aboutsummaryrefslogtreecommitdiffstats
path: root/framework
diff options
context:
space:
mode:
authorAshlee Young <ashlee@onosfw.com>2015-10-09 18:32:44 -0700
committerAshlee Young <ashlee@onosfw.com>2015-10-09 18:32:44 -0700
commit6a07d2d622eaa06953f3353e39c080984076e8de (patch)
treebfb50a2090fce186c2cc545a400c969bf2ea702b /framework
parente6d71622143ff9b2421a1abbe8434b954b5b1099 (diff)
Updated master to commit id 6ee8aa3e67ce89908a8c93aa9445c6f71a18f986
Change-Id: I94b055ee2f298daf71e2ec794fd0f2495bd8081f
Diffstat (limited to 'framework')
-rw-r--r--framework/src/onos/apps/aaa/pom.xml25
-rw-r--r--framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/AAA.java592
-rw-r--r--framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/AAAConfig.java239
-rw-r--r--framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/StateMachine.java351
-rw-r--r--framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/StateMachineException.java28
-rw-r--r--framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/StateMachineInvalidTransitionException.java27
-rw-r--r--framework/src/onos/apps/aaa/src/test/java/org/onosproject/aaa/AAATest.java469
-rw-r--r--framework/src/onos/apps/aaa/src/test/java/org/onosproject/aaa/StateMachineTest.java132
-rw-r--r--framework/src/onos/apps/acl/pom.xml30
-rw-r--r--framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/AclRule.java290
-rw-r--r--framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/AclService.java56
-rw-r--r--framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/AclStore.java146
-rw-r--r--framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/AclWebResource.java191
-rw-r--r--framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/RuleId.java85
-rw-r--r--framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/impl/AclManager.java338
-rw-r--r--framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/impl/DistributedAclStore.java251
-rw-r--r--framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/impl/package-info.java20
-rw-r--r--framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/package-info.java20
-rw-r--r--framework/src/onos/apps/acl/src/main/webapp/WEB-INF/web.xml2
-rw-r--r--framework/src/onos/apps/acl/src/test/java/org/onosproject/acl/AclWebResourceTest.java142
-rw-r--r--framework/src/onos/apps/bgprouter/pom.xml1
-rw-r--r--framework/src/onos/apps/bgprouter/src/main/java/org/onosproject/bgprouter/IcmpHandler.java1
-rw-r--r--framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/CordFabricManager.java2
-rw-r--r--framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtn.java178
-rw-r--r--framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnConfig.java22
-rw-r--r--framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnConfigManager.java144
-rw-r--r--framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnService.java36
-rw-r--r--framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/DefaultOvsdbNode.java40
-rw-r--r--framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/NodeConnectionManager.java166
-rw-r--r--framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/OvsdbNode.java25
-rw-r--r--framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/DhcpStore.java2
-rw-r--r--framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpManager.java162
-rw-r--r--framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DistributedDhcpStore.java4
-rw-r--r--framework/src/onos/apps/dhcp/src/test/java/org/onosproject/dhcp/impl/DhcpManagerTest.java10
-rw-r--r--framework/src/onos/apps/flowanalyzer/pom.xml32
-rw-r--r--framework/src/onos/apps/flowanalyzer/src/main/java/org/onosproject/flowanalyzer/FlowAnalysisCommand.java33
-rw-r--r--framework/src/onos/apps/flowanalyzer/src/main/java/org/onosproject/flowanalyzer/FlowAnalyzer.java213
-rw-r--r--framework/src/onos/apps/flowanalyzer/src/main/resources/OSGI-INF/blueprint/shell-config.xml23
-rw-r--r--framework/src/onos/apps/flowanalyzer/src/test/java/org/onosproject/flowanalyzer/DefaultMutableTopologyGraph.java28
-rw-r--r--framework/src/onos/apps/flowanalyzer/src/test/java/org/onosproject/flowanalyzer/FlowAnalyzerTest.java120
-rw-r--r--framework/src/onos/apps/flowanalyzer/src/test/java/org/onosproject/flowanalyzer/MockFlowRuleService.java103
-rw-r--r--framework/src/onos/apps/flowanalyzer/src/test/java/org/onosproject/flowanalyzer/MockLinkService.java183
-rw-r--r--framework/src/onos/apps/flowanalyzer/src/test/java/org/onosproject/flowanalyzer/MockTopologyService.java21
-rw-r--r--framework/src/onos/apps/igmp/pom.xml117
-rw-r--r--framework/src/onos/apps/igmp/src/main/java/org/onosproject/igmp/impl/IGMPComponent.java155
-rw-r--r--framework/src/onos/apps/igmp/src/main/java/org/onosproject/igmp/impl/IGMPProcessMembership.java39
-rw-r--r--framework/src/onos/apps/igmp/src/main/java/org/onosproject/igmp/impl/IGMPProcessQuery.java39
-rw-r--r--framework/src/onos/apps/mfwd/pom.xml142
-rw-r--r--framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/cli/McastDeleteCommand.java45
-rw-r--r--framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/cli/McastJoinCommand.java72
-rw-r--r--framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/cli/McastShowCommand.java62
-rw-r--r--framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/cli/package-info.java5
-rw-r--r--framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/MRibCodec.java211
-rw-r--r--framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastConnectPoint.java68
-rw-r--r--framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastForwarding.java237
-rw-r--r--framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastIntentManager.java133
-rw-r--r--framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRoute.java190
-rw-r--r--framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteBase.java431
-rw-r--r--framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteGroup.java110
-rw-r--r--framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteSource.java48
-rw-r--r--framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteTable.java338
-rw-r--r--framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/package-info.java4
-rw-r--r--framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/rest/McastResource.java149
-rw-r--r--framework/src/onos/apps/mfwd/src/main/resources/OSGI-INF/blueprint/shell-config.xml30
-rw-r--r--framework/src/onos/apps/mfwd/src/main/webapp/WEB-INF/web.xml44
-rw-r--r--framework/src/onos/apps/optical/src/main/java/org/onosproject/optical/OpticalPathProvisioner.java16
-rw-r--r--framework/src/onos/apps/pim/pom.xml122
-rw-r--r--framework/src/onos/apps/pim/src/main/java/org/onosproject/pim/cli/PIMShowCommand.java47
-rw-r--r--framework/src/onos/apps/pim/src/main/java/org/onosproject/pim/cli/package-info.java4
-rw-r--r--framework/src/onos/apps/pim/src/main/java/org/onosproject/pim/impl/PIMComponent.java153
-rw-r--r--framework/src/onos/apps/pim/src/main/java/org/onosproject/pim/impl/PIMNeighbor.java340
-rw-r--r--framework/src/onos/apps/pim/src/main/java/org/onosproject/pim/impl/PIMNeighbors.java395
-rw-r--r--framework/src/onos/apps/pim/src/main/java/org/onosproject/pim/impl/PIMNeighborsCodec.java97
-rw-r--r--framework/src/onos/apps/pim/src/main/java/org/onosproject/pim/impl/PIMTimer.java53
-rw-r--r--framework/src/onos/apps/pim/src/main/java/org/onosproject/pim/impl/package-info.java20
-rw-r--r--framework/src/onos/apps/pim/src/main/resources/OSGI-INF.blueprint/shell-config.xml24
-rw-r--r--framework/src/onos/apps/pom.xml5
-rw-r--r--framework/src/onos/apps/proxyarp/src/main/java/org/onosproject/proxyarp/ProxyArp.java26
-rw-r--r--framework/src/onos/apps/reactive-routing/src/main/java/org/onosproject/reactive/routing/LocationType.java35
-rw-r--r--framework/src/onos/apps/reactive-routing/src/main/java/org/onosproject/reactive/routing/ReactiveRoutingFib.java395
-rw-r--r--framework/src/onos/apps/reactive-routing/src/main/java/org/onosproject/reactive/routing/SdnIpReactiveRouting.java200
-rw-r--r--framework/src/onos/apps/reactive-routing/src/main/java/org/onosproject/reactive/routing/TrafficType.java56
-rw-r--r--framework/src/onos/apps/routing-api/src/main/java/org/onosproject/routing/IntentRequestListener.java10
-rw-r--r--framework/src/onos/apps/routing-api/src/main/java/org/onosproject/routing/IntentSynchronizationService.java51
-rw-r--r--framework/src/onos/apps/routing-api/src/main/java/org/onosproject/routing/RoutingService.java97
-rw-r--r--framework/src/onos/apps/routing-api/src/main/java/org/onosproject/routing/SdnIpService.java39
-rw-r--r--framework/src/onos/apps/routing-api/src/test/java/org/onosproject/routing/RouteEntryTest.java104
-rw-r--r--framework/src/onos/apps/routing/src/main/java/org/onosproject/routing/config/impl/Configuration.java4
-rw-r--r--framework/src/onos/apps/routing/src/main/java/org/onosproject/routing/config/impl/RoutingConfigurationImpl.java17
-rw-r--r--framework/src/onos/apps/routing/src/main/java/org/onosproject/routing/impl/Router.java166
-rw-r--r--framework/src/onos/apps/routing/src/main/java/org/onosproject/routing/impl/StaticRouter.java24
-rw-r--r--framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/impl/RouterTest.java192
-rw-r--r--framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/IntentSynchronizer.java901
-rw-r--r--framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/IntentUtils.java81
-rw-r--r--framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/PeerConnectivityManager.java74
-rw-r--r--framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/SdnIp.java18
-rw-r--r--framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/SdnIpFib.java216
-rw-r--r--framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/PrimaryChangeCommand.java2
-rw-r--r--framework/src/onos/apps/sdnip/src/test/java/org/onosproject/sdnip/IntentSyncTest.java460
-rw-r--r--framework/src/onos/apps/sdnip/src/test/java/org/onosproject/sdnip/PeerConnectivityManagerTest.java81
-rw-r--r--framework/src/onos/apps/sdnip/src/test/java/org/onosproject/sdnip/SdnIpFibTest.java417
-rw-r--r--framework/src/onos/apps/sdnip/src/test/java/org/onosproject/sdnip/TestIntentServiceHelper.java7
-rw-r--r--framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java105
-rw-r--r--framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java2
-rw-r--r--framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java113
-rw-r--r--framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/SegmentRoutingConfig.java128
-rw-r--r--framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/package-info.java2
-rw-r--r--framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DeviceProperties.java2
-rw-r--r--framework/src/onos/apps/test/distributed-primitives/src/main/java/org/onosproject/distributedprimitives/cli/CounterTestIncrementCommand.java3
-rw-r--r--framework/src/onos/apps/test/intent-perf/src/main/java/org/onosproject/intentperf/IntentPerfInstaller.java4
-rw-r--r--framework/src/onos/apps/vtn/app/app.xml25
-rw-r--r--framework/src/onos/apps/vtn/app/features.xml27
-rw-r--r--framework/src/onos/apps/vtn/app/pom.xml44
-rw-r--r--framework/src/onos/apps/vtn/pom.xml46
-rw-r--r--framework/src/onos/apps/vtn/vtnmgr/pom.xml53
-rw-r--r--framework/src/onos/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/VTNService.java68
-rw-r--r--framework/src/onos/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/impl/VTNManager.java672
-rw-r--r--framework/src/onos/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/impl/package-info.java20
-rw-r--r--framework/src/onos/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/package-info.java20
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/pom.xml56
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/AllocationPool.java38
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/AllowedAddressPair.java94
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/BindingHostId.java72
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultAllocationPool.java81
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultHostRoute.java79
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultSubnet.java183
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultTenantNetwork.java160
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultVirtualPort.java229
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/FixedIp.java93
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/HostRoute.java39
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PhysicalNetwork.java78
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/SecurityGroup.java77
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/SegmentationId.java77
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/Subnet.java129
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/SubnetId.java76
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/TenantId.java77
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/TenantNetwork.java130
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/TenantNetworkId.java76
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/VirtualPort.java156
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/VirtualPortId.java70
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/network/TenantNetworkCreateCommand.java97
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/network/TenantNetworkQueryCommand.java60
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/network/TenantNetworkRemoveCommand.java45
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/network/TenantNetworkUpdateCommand.java99
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/network/package-info.java20
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/subnet/SubnetCreateCommand.java118
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/subnet/SubnetQueryCommand.java61
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/subnet/SubnetRemoveCommand.java46
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/subnet/SubnetUpdateCommand.java118
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/subnet/package-info.java20
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/virtualport/VirtualPortCreateCommand.java134
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/virtualport/VirtualPortQueryCommand.java94
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/virtualport/VirtualPortRemoveCommand.java45
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/virtualport/VirtualPortUpdateCommand.java135
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/virtualport/package-info.java20
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/package-info.java20
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/subnet/SubnetService.java72
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/subnet/impl/SubnetManager.java183
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/subnet/impl/package-info.java20
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/subnet/package-info.java20
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/tenantnetwork/TenantNetworkService.java80
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/tenantnetwork/impl/TenantNetworkManager.java167
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/tenantnetwork/impl/package-info.java20
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/tenantnetwork/package-info.java20
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/tunnel/TunnelConfigService.java72
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/tunnel/package-info.java20
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/VirtualPortService.java100
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/impl/VirtualPortManager.java208
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/impl/package-info.java20
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/package-info.java20
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/AllocationPoolsCodec.java40
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/AllowedAddressPairCodec.java40
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/FixedIpCodec.java40
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/HostRoutesCodec.java40
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/SecurityGroupCodec.java39
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/SubnetCodec.java53
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/TenantNetworkCodec.java47
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/VirtualPortCodec.java57
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/package-info.java20
-rw-r--r--framework/src/onos/apps/vtn/vtnrsc/src/main/resources/OSGI-INF/blueprint/shell-config.xml56
-rw-r--r--framework/src/onos/apps/vtn/vtnweb/pom.xml87
-rw-r--r--framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/SubnetWebResource.java379
-rw-r--r--framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/TenantNetworkWebResource.java373
-rw-r--r--framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/VirtualPortWebResource.java412
-rw-r--r--framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/package-info.java20
-rw-r--r--framework/src/onos/apps/vtn/vtnweb/src/main/webapp/WEB-INF/web.xml45
-rwxr-xr-xframework/src/onos/bgp/api/pom.xml95
-rwxr-xr-xframework/src/onos/bgp/api/src/main/java/org/onosproject/bgp/controller/BGPCfg.java297
-rwxr-xr-xframework/src/onos/bgp/api/src/main/java/org/onosproject/bgp/controller/BGPController.java49
-rwxr-xr-xframework/src/onos/bgp/api/src/main/java/org/onosproject/bgp/controller/BGPId.java121
-rwxr-xr-xframework/src/onos/bgp/api/src/main/java/org/onosproject/bgp/controller/BGPPacketStats.java52
-rwxr-xr-xframework/src/onos/bgp/api/src/main/java/org/onosproject/bgp/controller/BGPPeerCfg.java166
-rwxr-xr-xframework/src/onos/bgp/api/src/main/java/org/onosproject/bgp/controller/package-info.java20
-rwxr-xr-xframework/src/onos/bgp/bgpio/pom.xml76
-rwxr-xr-xframework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/exceptions/BGPParseException.java106
-rwxr-xr-xframework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/exceptions/package-info.java20
-rw-r--r--framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPKeepaliveMsg.java58
-rw-r--r--framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPMessage.java92
-rwxr-xr-xframework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPMessageReader.java36
-rw-r--r--framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPMessageWriter.java36
-rw-r--r--framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPOpenMsg.java151
-rwxr-xr-xframework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPType.java45
-rwxr-xr-xframework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPVersion.java45
-rw-r--r--framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/IGPRouterID.java23
-rwxr-xr-xframework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/Writeable.java35
-rw-r--r--framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/link_state/BGPPrefixLSIdentifier.java228
-rw-r--r--framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/link_state/NodeDescriptors.java225
-rwxr-xr-xframework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/link_state/package-info.java20
-rwxr-xr-xframework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/package-info.java20
-rw-r--r--framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPKeepaliveMsgVer4.java172
-rw-r--r--framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPOpenMsgVer4.java468
-rwxr-xr-xframework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/package-info.java20
-rw-r--r--framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/AreaIDTlv.java126
-rw-r--r--framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/AutonomousSystemTlv.java126
-rw-r--r--framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/BGPErrorType.java57
-rwxr-xr-xframework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/BGPHeader.java161
-rw-r--r--framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/BGPLSIdentifierTlv.java127
-rwxr-xr-xframework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/BGPValueType.java39
-rw-r--r--framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/IPReachabilityInformationTlv.java156
-rw-r--r--framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/IsIsNonPseudonode.java117
-rw-r--r--framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/IsIsPseudonode.java133
-rw-r--r--framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/OSPFNonPseudonode.java118
-rw-r--r--framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/OSPFPseudonode.java125
-rw-r--r--framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/OSPFRouteTypeTlv.java163
-rwxr-xr-xframework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpAttrNodeFlagBitTlv.java177
-rw-r--r--framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpAttrNodeMultiTopologyId.java127
-rwxr-xr-xframework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/package-info.java20
-rwxr-xr-xframework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/package-info.java20
-rw-r--r--framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/util/UnSupportedAttribute.java51
-rw-r--r--framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/util/Validation.java189
-rwxr-xr-xframework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/util/package-info.java20
-rwxr-xr-xframework/src/onos/bgp/ctl/pom.xml65
-rwxr-xr-xframework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPChannelHandler.java34
-rwxr-xr-xframework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPConfig.java344
-rwxr-xr-xframework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPControllerImpl.java104
-rwxr-xr-xframework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPMessageDecoder.java53
-rwxr-xr-xframework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPMessageEncoder.java60
-rwxr-xr-xframework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPPacketStatsImpl.java128
-rwxr-xr-xframework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPPeerConfig.java109
-rwxr-xr-xframework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPPipelineFactory.java67
-rwxr-xr-xframework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/Controller.java183
-rwxr-xr-xframework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/package-info.java20
-rwxr-xr-xframework/src/onos/bgp/pom.xml60
-rw-r--r--framework/src/onos/cli/src/main/java/org/onosproject/cli/Comparators.java10
-rw-r--r--framework/src/onos/cli/src/main/java/org/onosproject/cli/cfg/NetworkConfigCommand.java22
-rw-r--r--framework/src/onos/cli/src/main/java/org/onosproject/cli/cfg/NetworkConfigRegistryCommand.java2
-rw-r--r--framework/src/onos/cli/src/main/java/org/onosproject/cli/net/DeviceControllersCommand.java47
-rw-r--r--framework/src/onos/cli/src/main/java/org/onosproject/cli/net/DevicePortsListCommand.java44
-rw-r--r--framework/src/onos/cli/src/main/java/org/onosproject/cli/net/DeviceSetControllersCommand.java69
-rw-r--r--framework/src/onos/cli/src/main/java/org/onosproject/cli/net/GetFlowStatistics.java323
-rw-r--r--framework/src/onos/cli/src/main/java/org/onosproject/cli/net/InterfaceAddCommand.java79
-rw-r--r--framework/src/onos/cli/src/main/java/org/onosproject/cli/net/InterfaceRemoveCommand.java51
-rw-r--r--framework/src/onos/cli/src/main/java/org/onosproject/cli/net/PacketProcessorsListCommand.java10
-rw-r--r--framework/src/onos/cli/src/main/java/org/onosproject/cli/net/TableStatisticsCommand.java145
-rw-r--r--framework/src/onos/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml36
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/cfg/ComponentConfigService.java11
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/AnnotationKeys.java16
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultDisjointPath.java100
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/DisjointPath.java49
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ControllerConfig.java6
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ControllerInfo.java100
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/config/NetworkConfigService.java12
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/config/SubjectFactory.java26
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/BasicDeviceConfig.java20
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/SubjectFactories.java16
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTableStatisticsEntry.java89
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficSelector.java22
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java46
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTypedFlowEntry.java122
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRule.java37
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleProviderService.java21
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java7
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleStore.java21
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TableStatisticsEntry.java59
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficSelector.java24
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java10
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TypedStoredFlowEntry.java65
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/Criteria.java24
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instruction.java9
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java73
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostProviderService.java9
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostStore.java9
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/FlowRuleIntent.java13
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/McastEvent.java118
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/McastListener.java26
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/McastRoute.java117
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/MulticastRouteService.java84
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/package-info.java20
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/DefaultMeterRequest.java5
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterKey.java72
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterService.java4
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterStore.java6
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceService.java9
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketProcessorEntry.java58
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketService.java8
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketStore.java6
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketStoreDelegate.java16
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/device/IntentSetMultimap.java47
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/BandwidthResourceRequest.java2
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/FlowStatisticService.java105
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/FlowStatisticStore.java65
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/SummaryFlowEntryWithLoad.java143
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/TypedFlowEntryWithLoad.java143
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/DefaultGraphDescription.java17
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/PathService.java54
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyService.java63
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyStore.java55
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AsyncAtomicCounter.java17
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AtomicCounter.java16
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/store/service/MutexExecutionService.java34
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/store/service/MutexTask.java39
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/NumberFormatter.java50
-rw-r--r--framework/src/onos/core/api/src/test/java/org/onosproject/cfg/ComponentConfigAdapter.java9
-rw-r--r--framework/src/onos/core/api/src/test/java/org/onosproject/net/behaviour/ControllerInfoTest.java112
-rw-r--r--framework/src/onos/core/api/src/test/java/org/onosproject/net/config/NetworkConfigServiceAdapter.java4
-rw-r--r--framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/DefaultTrafficSelectorTest.java24
-rw-r--r--framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/FlowRuleServiceAdapter.java9
-rw-r--r--framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/criteria/CriteriaTest.java65
-rw-r--r--framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java19
-rw-r--r--framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/PacketServiceAdapter.java3
-rw-r--r--framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/DefaultGraphDescriptionTest.java4
-rw-r--r--framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/PathServiceAdapter.java62
-rw-r--r--framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/TopologyServiceAdapter.java26
-rw-r--r--framework/src/onos/core/api/src/test/java/org/onosproject/store/service/TestAtomicCounter.java10
-rw-r--r--framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/CodecManager.java3
-rw-r--r--framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java1
-rw-r--r--framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/TableStatisticsEntryCodec.java46
-rw-r--r--framework/src/onos/core/common/src/main/java/org/onosproject/common/DefaultTopology.java140
-rw-r--r--framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/CriterionCodecTest.java15
-rw-r--r--framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionJsonMatcher.java2
-rw-r--r--framework/src/onos/core/common/src/test/java/org/onosproject/common/DefaultTopologyTest.java2
-rw-r--r--framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleFlowRuleStore.java23
-rw-r--r--framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleHostStore.java5
-rw-r--r--framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimplePacketStore.java51
-rw-r--r--framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleTopologyStore.java25
-rw-r--r--framework/src/onos/core/net/pom.xml14
-rw-r--r--framework/src/onos/core/net/src/main/java/org/onosproject/cfg/impl/ComponentConfigLoader.java74
-rw-r--r--framework/src/onos/core/net/src/main/java/org/onosproject/cfg/impl/ComponentConfigManager.java24
-rw-r--r--framework/src/onos/core/net/src/main/java/org/onosproject/core/impl/CoreManager.java17
-rw-r--r--framework/src/onos/core/net/src/main/java/org/onosproject/net/config/impl/NetworkConfigManager.java12
-rw-r--r--framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/BasicDeviceOperator.java17
-rw-r--r--framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java73
-rw-r--r--framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/OpticalPortOperator.java19
-rw-r--r--framework/src/onos/core/net/src/main/java/org/onosproject/net/flow/impl/FlowRuleManager.java45
-rw-r--r--framework/src/onos/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java10
-rw-r--r--framework/src/onos/core/net/src/main/java/org/onosproject/net/host/impl/HostMonitor.java1
-rw-r--r--framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentCleanup.java2
-rw-r--r--framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java19
-rw-r--r--framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/ObjectiveTracker.java26
-rw-r--r--framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalCircuitIntentCompiler.java53
-rw-r--r--framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalConnectivityIntentCompiler.java69
-rw-r--r--framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompiler.java4
-rw-r--r--framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceManager.java8
-rw-r--r--framework/src/onos/core/net/src/main/java/org/onosproject/net/packet/impl/PacketManager.java148
-rw-r--r--framework/src/onos/core/net/src/main/java/org/onosproject/net/statistic/impl/FlowStatisticManager.java634
-rw-r--r--framework/src/onos/core/net/src/main/java/org/onosproject/net/topology/impl/PathManager.java103
-rw-r--r--framework/src/onos/core/net/src/main/java/org/onosproject/net/topology/impl/TopologyManager.java43
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/cfg/impl/ComponentConfigLoaderTest.java126
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/host/impl/HostMonitorTest.java214
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java2
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MultiPointToSinglePointIntentCompilerTest.java10
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompilerTest.java12
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/PathManagerTest.java6
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/TopologyManagerTest.java2
-rw-r--r--framework/src/onos/core/net/src/test/resources/org/onosproject/cfg/impl/badComponent.json5
-rw-r--r--framework/src/onos/core/net/src/test/resources/org/onosproject/cfg/impl/badConfig.json5
-rw-r--r--framework/src/onos/core/net/src/test/resources/org/onosproject/cfg/impl/basic.json5
-rw-r--r--framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/Database.java4
-rw-r--r--framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseManager.java5
-rw-r--r--framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseProxy.java55
-rw-r--r--framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseState.java18
-rw-r--r--framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAsyncAtomicCounter.java21
-rw-r--r--framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAtomicCounter.java10
-rw-r--r--framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabase.java24
-rw-r--r--framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabaseState.java30
-rw-r--r--framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/MutexExecutionManager.java315
-rw-r--r--framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/PartitionedDatabase.java89
-rw-r--r--framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/ecmap/EventuallyConsistentMapImpl.java20
-rw-r--r--framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/flow/impl/NewDistributedFlowRuleStore.java64
-rw-r--r--framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/group/impl/DistributedGroupStore.java62
-rw-r--r--framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/host/impl/ECHostStore.java51
-rw-r--r--framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/intent/impl/GossipIntentStore.java2
-rw-r--r--framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/link/impl/GossipLinkStore.java4
-rw-r--r--framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/packet/impl/DistributedPacketStore.java78
-rw-r--r--framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentIntentSetMultimap.java111
-rw-r--r--framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentLinkResourceStore.java252
-rw-r--r--framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/statistic/impl/DistributedFlowStatisticStore.java289
-rw-r--r--framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/topology/impl/DistributedTopologyStore.java26
-rw-r--r--framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/host/impl/ECHostStoreTest.java95
-rw-r--r--framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java12
-rw-r--r--framework/src/onos/docs/external-excludes5
-rw-r--r--framework/src/onos/docs/internal-apps5
-rw-r--r--framework/src/onos/drivers/pom.xml23
-rw-r--r--framework/src/onos/drivers/src/main/java/org/onosproject/driver/handshaker/OFOpticalSwitch13.java170
-rw-r--r--framework/src/onos/drivers/src/main/java/org/onosproject/driver/ovsdb/OvsdbControllerConfig.java102
-rw-r--r--framework/src/onos/drivers/src/main/resources/onos-drivers.xml7
-rw-r--r--framework/src/onos/drivers/src/test/java/org/onosproject/driver/ovsdb/OvsdbControllerConfigTest.java95
-rw-r--r--framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/config/basics/InterfaceConfig.java66
-rw-r--r--framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/domain/DomainIntentResource.java84
-rw-r--r--framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/domain/IntentDomainProvider.java26
-rw-r--r--framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/domain/IntentResource.java52
-rw-r--r--framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/domain/NetworkIntentResource.java70
-rw-r--r--framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/intf/InterfaceAdminService.java40
-rw-r--r--framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/tunnel/DomainTunnelId.java92
-rw-r--r--framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/tunnel/NetworkTunnelId.java89
-rw-r--r--framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/DefaultVirtualDevice.java75
-rw-r--r--framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/DefaultVirtualNetwork.java76
-rw-r--r--framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualElement.java7
-rw-r--r--framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkAdminService.java38
-rw-r--r--framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkEvent.java72
-rw-r--r--framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkListener.java24
-rw-r--r--framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkProvider.java31
-rw-r--r--framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkProviderRegistry.java25
-rw-r--r--framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkProviderService.java11
-rw-r--r--framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkStore.java161
-rw-r--r--framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkStoreDelegate.java24
-rw-r--r--framework/src/onos/incubator/net/src/main/java/org/onosproject/incubator/net/intf/impl/InterfaceManager.java52
-rw-r--r--framework/src/onos/incubator/net/src/main/java/org/onosproject/incubator/net/mcast/impl/MulticastData.java85
-rw-r--r--framework/src/onos/incubator/net/src/main/java/org/onosproject/incubator/net/mcast/impl/MulticastRouteManager.java174
-rw-r--r--framework/src/onos/incubator/net/src/main/java/org/onosproject/incubator/net/mcast/impl/package-info.java20
-rw-r--r--framework/src/onos/incubator/net/src/main/java/org/onosproject/incubator/net/meter/impl/MeterManager.java37
-rw-r--r--framework/src/onos/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkManager.java223
-rw-r--r--framework/src/onos/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/package-info.java20
-rw-r--r--framework/src/onos/incubator/net/src/test/java/org/onosproject/incubator/net/mcast/impl/MulticastRouteManagerTest.java200
-rw-r--r--framework/src/onos/incubator/net/src/test/java/org/onosproject/incubator/net/meter/impl/MeterManagerTest.java15
-rw-r--r--framework/src/onos/incubator/store/src/main/java/org/onosproject/incubator/store/meter/impl/DistributedMeterStore.java51
-rw-r--r--framework/src/onos/incubator/store/src/main/java/org/onosproject/incubator/store/virtual/impl/DistributedVirtualNetworkStore.java147
-rw-r--r--framework/src/onos/incubator/store/src/main/java/org/onosproject/incubator/store/virtual/impl/package-info.java20
-rw-r--r--framework/src/onos/openflow/api/src/main/java/org/onosproject/openflow/controller/DefaultOpenFlowPacketContext.java2
-rw-r--r--framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/Controller.java117
-rw-r--r--framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OFChannelHandler.java3
-rw-r--r--framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImpl.java67
-rw-r--r--framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OpenflowPipelineFactory.java18
-rw-r--r--framework/src/onos/ovsdb/api/pom.xml4
-rw-r--r--framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbClientService.java73
-rw-r--r--framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbConstant.java2
-rw-r--r--framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbController.java11
-rw-r--r--framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/driver/DefaultOvsdbClient.java341
-rw-r--r--framework/src/onos/ovsdb/api/src/test/java/org/onosproject/ovsdb/controller/driver/OvsdbClientServiceAdapter.java208
-rw-r--r--framework/src/onos/ovsdb/api/src/test/java/org/onosproject/ovsdb/controller/driver/OvsdbControllerAdapter.java75
-rw-r--r--framework/src/onos/ovsdb/ctl/src/main/java/org/onosproject/ovsdb/controller/impl/Controller.java98
-rw-r--r--framework/src/onos/ovsdb/ctl/src/main/java/org/onosproject/ovsdb/controller/impl/OvsdbControllerImpl.java63
-rw-r--r--framework/src/onos/ovsdb/ctl/src/main/java/org/onosproject/ovsdb/controller/impl/OvsdbJsonRpcHandler.java2
-rw-r--r--framework/src/onos/ovsdb/rfc/src/main/java/org/onosproject/ovsdb/rfc/notation/Row.java43
-rw-r--r--framework/src/onos/ovsdb/rfc/src/main/java/org/onosproject/ovsdb/rfc/table/Bridge.java9
-rw-r--r--framework/src/onos/ovsdb/rfc/src/main/java/org/onosproject/ovsdb/rfc/table/TableGenerator.java1
-rw-r--r--framework/src/onos/ovsdb/rfc/src/main/java/org/onosproject/ovsdb/rfc/utils/FromJsonUtil.java31
-rw-r--r--framework/src/onos/pcep/pcepio/src/main/java/org/onosproject/pcepio/protocol/ver1/PcepErrorVer1.java2
-rw-r--r--framework/src/onos/pom.xml26
-rw-r--r--framework/src/onos/providers/host/src/main/java/org/onosproject/provider/host/impl/HostLocationProvider.java12
-rw-r--r--framework/src/onos/providers/host/src/test/java/org/onosproject/provider/host/impl/HostLocationProviderTest.java724
-rw-r--r--framework/src/onos/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LLDPLinkProvider.java20
-rw-r--r--framework/src/onos/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java227
-rw-r--r--framework/src/onos/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceValueMapper.java73
-rw-r--r--framework/src/onos/providers/openflow/device/src/test/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProviderTest.java3
-rw-r--r--framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowEntryBuilder.java5
-rw-r--r--framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer10.java2
-rw-r--r--framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java4
-rw-r--r--framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/NewAdaptiveFlowStatsCollector.java881
-rw-r--r--framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java218
-rw-r--r--framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/TableStatisticsCollector.java95
-rw-r--r--framework/src/onos/providers/ovsdb/device/src/test/java/org/onosproject/ovsdb/providers/device/OvsdbDeviceProviderTest.java5
-rw-r--r--framework/src/onos/providers/ovsdb/host/src/test/java/org/onosproject/ovsdb/provider/host/OvsdbHostProviderTest.java12
-rw-r--r--framework/src/onos/tools/build/conf/pom.xml2
-rw-r--r--framework/src/onos/tools/build/conf/src/main/resources/onos/checkstyle.xml5
-rw-r--r--framework/src/onos/tools/build/docker/Dockerfile4
-rwxr-xr-xframework/src/onos/tools/build/onos-package4
-rw-r--r--framework/src/onos/tools/dev/bash_profile70
-rwxr-xr-xframework/src/onos/tools/dev/bin/onos-create-app2
-rw-r--r--framework/src/onos/tools/dev/header.txt2
-rw-r--r--framework/src/onos/tools/package/archetypes/pom.xml2
-rw-r--r--framework/src/onos/tools/package/archetypes/ui/pom.xml2
-rw-r--r--framework/src/onos/tools/package/archetypes/ui/src/main/resources/archetype-resources/pom.xml2
-rw-r--r--framework/src/onos/tools/package/archetypes/ui/src/main/resources/archetype-resources/src/main/java/AppUiComponent.java7
-rw-r--r--framework/src/onos/tools/package/archetypes/ui/src/main/resources/archetype-resources/src/main/java/AppUiMessageHandler.java162
-rw-r--r--framework/src/onos/tools/package/archetypes/ui/src/main/resources/archetype-resources/src/main/resources/app/view/sampleCustom/sampleCustom.css48
-rw-r--r--framework/src/onos/tools/package/archetypes/ui/src/main/resources/archetype-resources/src/main/resources/app/view/sampleCustom/sampleCustom.html32
-rw-r--r--framework/src/onos/tools/package/archetypes/ui/src/main/resources/archetype-resources/src/main/resources/app/view/sampleCustom/sampleCustom.js69
-rw-r--r--framework/src/onos/tools/package/archetypes/ui/src/main/resources/archetype-resources/src/main/resources/css.html2
-rw-r--r--framework/src/onos/tools/package/archetypes/ui/src/main/resources/archetype-resources/src/main/resources/js.html2
-rw-r--r--framework/src/onos/tools/package/archetypes/uitab/pom.xml31
-rw-r--r--framework/src/onos/tools/package/archetypes/uitab/src/main/resources/META-INF/maven/archetype-metadata.xml39
-rw-r--r--framework/src/onos/tools/package/archetypes/uitab/src/main/resources/archetype-resources/pom.xml140
-rw-r--r--framework/src/onos/tools/package/archetypes/uitab/src/main/resources/archetype-resources/src/main/java/AppUiTableComponent.java80
-rw-r--r--framework/src/onos/tools/package/archetypes/uitab/src/main/resources/archetype-resources/src/main/java/AppUiTableMessageHandler.java190
-rw-r--r--framework/src/onos/tools/package/archetypes/uitab/src/main/resources/archetype-resources/src/main/resources/app/view/sampleTable/sampleTable.css35
-rw-r--r--framework/src/onos/tools/package/archetypes/uitab/src/main/resources/archetype-resources/src/main/resources/app/view/sampleTable/sampleTable.html46
-rw-r--r--framework/src/onos/tools/package/archetypes/uitab/src/main/resources/archetype-resources/src/main/resources/app/view/sampleTable/sampleTable.js141
-rw-r--r--framework/src/onos/tools/package/archetypes/uitab/src/main/resources/archetype-resources/src/main/resources/sampleTable/css.html1
-rw-r--r--framework/src/onos/tools/package/archetypes/uitab/src/main/resources/archetype-resources/src/main/resources/sampleTable/js.html1
-rw-r--r--framework/src/onos/tools/package/archetypes/uitab/src/test/resources/projects/basic/archetype.properties21
-rw-r--r--framework/src/onos/tools/package/archetypes/uitab/src/test/resources/projects/basic/goal.txt0
-rw-r--r--framework/src/onos/tools/package/archetypes/uitopo/pom.xml31
-rw-r--r--framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/META-INF/maven/archetype-metadata.xml39
-rw-r--r--framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/pom.xml140
-rw-r--r--framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/java/AppUiTopovComponent.java89
-rw-r--r--framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/java/AppUiTopovMessageHandler.java319
-rw-r--r--framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/java/AppUiTopovOverlay.java75
-rw-r--r--framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/java/DemoLink.java57
-rw-r--r--framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/java/DemoLinkMap.java33
-rw-r--r--framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/resources/app/view/sampleTopov/sampleTopov.css2
-rw-r--r--framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/resources/app/view/sampleTopov/sampleTopov.html4
-rw-r--r--framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/resources/app/view/sampleTopov/sampleTopovDemo.js104
-rw-r--r--framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/resources/app/view/sampleTopov/sampleTopovOverlay.js143
-rw-r--r--framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/resources/sampleTopov/css.html1
-rw-r--r--framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/resources/sampleTopov/js.html2
-rw-r--r--framework/src/onos/tools/package/archetypes/uitopo/src/test/resources/projects/basic/archetype.properties21
-rw-r--r--framework/src/onos/tools/package/archetypes/uitopo/src/test/resources/projects/basic/goal.txt0
-rw-r--r--framework/src/onos/tools/package/config/samples/component-cfg.json5
-rw-r--r--framework/src/onos/tools/package/config/samples/network-cfg.json66
-rw-r--r--framework/src/onos/tools/test/bin/ogroup-opts2
-rwxr-xr-xframework/src/onos/tools/test/bin/onos21
-rwxr-xr-xframework/src/onos/tools/test/bin/onos-archetypes-test13
-rwxr-xr-xframework/src/onos/tools/test/bin/onos-batch22
-rwxr-xr-xframework/src/onos/tools/test/bin/onos-config22
-rwxr-xr-xframework/src/onos/tools/test/bin/onos-install26
-rwxr-xr-xframework/src/onos/tools/test/bin/onos-push-bits18
-rwxr-xr-xframework/src/onos/tools/test/bin/onos-service1
-rwxr-xr-xframework/src/onos/tools/test/bin/onos-set-controllers2
-rwxr-xr-xframework/src/onos/tools/test/bin/onos-uninstall27
-rwxr-xr-xframework/src/onos/tools/test/bin/onos-watch32
-rw-r--r--framework/src/onos/tools/test/cells/andrea11
-rw-r--r--framework/src/onos/tools/test/cells/tomx3
-rw-r--r--framework/src/onos/tools/test/scenarios/archetypes.xml18
-rwxr-xr-xframework/src/onos/tools/test/topos/onos.py2
-rw-r--r--framework/src/onos/tools/test/topos/optical2.py2
-rw-r--r--framework/src/onos/tools/test/topos/solar.py2
-rw-r--r--framework/src/onos/tools/test/topos/sys-nonlinear-10.config20
-rw-r--r--framework/src/onos/tools/test/topos/sys-nonlinear-4.config8
-rw-r--r--framework/src/onos/tools/test/topos/sys.config20
-rw-r--r--framework/src/onos/utils/junit/src/main/java/org/onlab/junit/TestUtils.java37
-rw-r--r--framework/src/onos/utils/misc/src/main/java/org/onlab/graph/DisjointPathPair.java83
-rw-r--r--framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrGroup.java2
-rw-r--r--framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrSource.java2
-rw-r--r--framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrUnicast.java2
-rwxr-xr-xframework/src/onos/utils/misc/src/main/java/org/onlab/util/HexDump.java57
-rw-r--r--framework/src/onos/utils/misc/src/main/java/org/onlab/util/Tools.java6
-rw-r--r--framework/src/onos/utils/misc/src/test/java/org/onlab/graph/SRLGGraphSearchTest.java69
-rw-r--r--framework/src/onos/utils/misc/src/test/java/org/onlab/util/AbstractAccumulatorTest.java42
-rw-r--r--framework/src/onos/utils/misc/src/test/java/org/onlab/util/ManuallyAdvancingTimer.java504
-rw-r--r--framework/src/onos/utils/misc/src/test/java/org/onlab/util/ManuallyAdvancingTimerTest.java263
-rw-r--r--framework/src/onos/utils/osgi/src/test/java/org/onlab/osgi/ComponentContextAdapter.java41
-rw-r--r--framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/FlowsWebResource.java24
-rw-r--r--framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/NetworkConfigWebResource.java158
-rw-r--r--framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/PathsWebResource.java64
-rw-r--r--framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/StatisticsWebResource.java61
-rw-r--r--framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/DeviceViewMessageHandler.java77
-rw-r--r--framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/ProcessorViewMessageHandler.java108
-rw-r--r--framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/UiExtensionManager.java2
-rw-r--r--framework/src/onos/web/gui/src/main/webapp/app/fw/svg/glyph.js30
-rw-r--r--framework/src/onos/web/gui/src/main/webapp/app/fw/svg/icon.js6
-rw-r--r--framework/src/onos/web/gui/src/main/webapp/app/fw/util/keys.js30
-rw-r--r--framework/src/onos/web/gui/src/main/webapp/app/view/device/device.css9
-rw-r--r--framework/src/onos/web/gui/src/main/webapp/app/view/device/device.html6
-rw-r--r--framework/src/onos/web/gui/src/main/webapp/app/view/device/device.js116
-rw-r--r--framework/src/onos/web/gui/src/main/webapp/app/view/processor/processor.css49
-rw-r--r--framework/src/onos/web/gui/src/main/webapp/app/view/processor/processor.html63
-rw-r--r--framework/src/onos/web/gui/src/main/webapp/app/view/processor/processor.js58
-rw-r--r--framework/src/onos/web/gui/src/main/webapp/app/view/settings/settings.html2
-rw-r--r--framework/src/onos/web/gui/src/main/webapp/app/view/topo/topo.js3
-rw-r--r--framework/src/onos/web/gui/src/main/webapp/index.html2
-rw-r--r--framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_10_addDevice_s9_ids.json18
-rw-r--r--framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_11_addDevice_s10_controller.json18
-rw-r--r--framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_12_addDevice_s11_virtual.json18
-rw-r--r--framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_13_addDevice_s12_fiber_switch.json18
-rw-r--r--framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_14_addDevice_s13_microwave.json18
-rw-r--r--framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_15_addDevice_s14_other.json18
-rw-r--r--framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_16_addDevice_s15_unmatched.json18
-rw-r--r--framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_1_addInstance.json14
-rw-r--r--framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_2_addDevice_s1_switch.json18
-rw-r--r--framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_3_addDevice_s2_router.json18
-rw-r--r--framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_4_addDevice_s3_roadm.json18
-rw-r--r--framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_5_addDevice_s4_otn.json18
-rw-r--r--framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_6_addDevice_s5_roadm_otn.json18
-rw-r--r--framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_7_addDevice_s6_firewall.json18
-rw-r--r--framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_8_addDevice_s7_balancer.json18
-rw-r--r--framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_9_addDevice_s8_ips.json18
-rw-r--r--framework/src/onos/web/gui/src/test/_karma/ev/devices/scenario.json12
578 files changed, 39571 insertions, 4451 deletions
diff --git a/framework/src/onos/apps/aaa/pom.xml b/framework/src/onos/apps/aaa/pom.xml
index 78fd4a62..b03930a9 100644
--- a/framework/src/onos/apps/aaa/pom.xml
+++ b/framework/src/onos/apps/aaa/pom.xml
@@ -44,36 +44,41 @@
<dependency>
<groupId>org.onosproject</groupId>
- <artifactId>onlab-junit</artifactId>
- <scope>test</scope>
+ <artifactId>onos-api</artifactId>
+ <version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.onosproject</groupId>
- <artifactId>onos-api</artifactId>
+ <artifactId>onos-app-xos-integration</artifactId>
<version>${project.version}</version>
</dependency>
- <dependency>
+ <dependency>
<groupId>org.onosproject</groupId>
- <artifactId>onlab-osgi</artifactId>
- <version>${project.version}</version>
+ <artifactId>onlab-junit</artifactId>
+ <scope>test</scope>
</dependency>
<dependency>
- <groupId>org.apache.felix</groupId>
- <artifactId>org.apache.felix.scr.annotations</artifactId>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onlab-osgi</artifactId>
+ <version>${project.version}</version>
+ <classifier>tests</classifier>
+ <scope>test</scope>
</dependency>
<dependency>
<groupId>org.onosproject</groupId>
- <artifactId>onos-app-xos-integration</artifactId>
+ <artifactId>onos-api</artifactId>
<version>${project.version}</version>
+ <classifier>tests</classifier>
+ <scope>test</scope>
</dependency>
</dependencies>
- <build>
+ <build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
diff --git a/framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/AAA.java b/framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/AAA.java
index 7e3de885..479ec7ed 100644
--- a/framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/AAA.java
+++ b/framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/AAA.java
@@ -15,13 +15,14 @@
*/
package org.onosproject.aaa;
-import com.google.common.base.Strings;
-import com.google.common.collect.Maps;
+import java.net.InetAddress;
+import java.nio.ByteBuffer;
+import java.util.Optional;
+import java.util.Set;
+
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;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onlab.packet.DeserializationException;
@@ -38,14 +39,16 @@ import org.onlab.packet.RADIUSAttribute;
import org.onlab.packet.TpPort;
import org.onlab.packet.UDP;
import org.onlab.packet.VlanId;
-import org.onlab.util.Tools;
-import org.onosproject.cfg.ComponentConfigService;
import org.onosproject.core.ApplicationId;
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.config.ConfigFactory;
+import org.onosproject.net.config.NetworkConfigEvent;
+import org.onosproject.net.config.NetworkConfigListener;
+import org.onosproject.net.config.NetworkConfigRegistry;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.TrafficSelector;
@@ -58,28 +61,21 @@ import org.onosproject.net.packet.PacketContext;
import org.onosproject.net.packet.PacketProcessor;
import org.onosproject.net.packet.PacketService;
import org.onosproject.xosintegration.VoltTenantService;
-import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.nio.ByteBuffer;
-import java.util.Collections;
-import java.util.Dictionary;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-
+import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
import static org.onosproject.net.packet.PacketPriority.CONTROL;
import static org.slf4j.LoggerFactory.getLogger;
-
/**
* AAA application for ONOS.
*/
@Component(immediate = true)
public class AAA {
+
+ // for verbose output
+ private final Logger log = getLogger(getClass());
+
// a list of our dependencies :
// to register with ONOS as an application - described next
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -96,8 +92,28 @@ public class AAA {
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected VoltTenantService voltTenantService;
- // for verbose output
- private final Logger log = getLogger(getClass());
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected NetworkConfigRegistry netCfgService;
+
+ // Parsed RADIUS server addresses
+ protected InetAddress radiusIpAddress;
+ protected String radiusMacAddress;
+
+ // NAS IP address
+ protected InetAddress nasIpAddress;
+ protected String nasMacAddress;
+
+ // RADIUS server secret
+ protected String radiusSecret;
+
+ // ID of RADIUS switch
+ protected String radiusSwitch;
+
+ // RADIUS port number
+ protected long radiusPort;
+
+ // RADIUS server TCP port number
+ protected short radiusServerPort;
// our application-specific event handler
private ReactivePacketProcessor processor = new ReactivePacketProcessor();
@@ -105,124 +121,80 @@ public class AAA {
// our unique identifier
private ApplicationId appId;
- // Map of state machines. Each state machine is represented by an
- // unique identifier on the switch: dpid + port number
- Map stateMachineMap = null;
-
- // RADIUS server IP address
- private static final String DEFAULT_RADIUS_IP = "192.168.1.10";
- // NAS IP address
- private static final String DEFAULT_NAS_IP = "192.168.1.11";
- // RADIUS uplink port
- private static final int DEFAULT_RADIUS_UPLINK = 2;
- // RADIUS server shared secret
- private static final String DEFAULT_RADIUS_SECRET = "ONOSecret";
- // RADIUS MAC address
- private static final String RADIUS_MAC_ADDRESS = "00:00:00:00:01:10";
- // NAS MAC address
- private static final String NAS_MAC_ADDRESS = "00:00:00:00:10:01";
- // Radius Switch Id
- private static final String DEFAULT_RADIUS_SWITCH = "of:90e2ba82f97791e9";
- // Radius Port Number
- private static final String DEFAULT_RADIUS_PORT = "129";
-
- @Property(name = "radiusIpAddress", value = DEFAULT_RADIUS_IP,
- label = "RADIUS IP Address")
- private String radiusIpAddress = DEFAULT_RADIUS_IP;
-
- @Property(name = "nasIpAddress", value = DEFAULT_NAS_IP,
- label = "NAS IP Address")
- private String nasIpAddress = DEFAULT_NAS_IP;
-
- @Property(name = "radiusMacAddress", value = RADIUS_MAC_ADDRESS,
- label = "RADIUS MAC Address")
- private String radiusMacAddress = RADIUS_MAC_ADDRESS;
-
- @Property(name = "nasMacAddress", value = NAS_MAC_ADDRESS,
- label = "NAS MAC Address")
- private String nasMacAddress = NAS_MAC_ADDRESS;
-
- @Property(name = "radiusSecret", value = DEFAULT_RADIUS_SECRET,
- label = "RADIUS shared secret")
- private String radiusSecret = DEFAULT_RADIUS_SECRET;
-
- @Property(name = "radiusSwitchId", value = DEFAULT_RADIUS_SWITCH,
- label = "Radius switch")
- private String radiusSwitch = DEFAULT_RADIUS_SWITCH;
-
- @Property(name = "radiusPortNumber", value = DEFAULT_RADIUS_PORT,
- label = "Radius port")
- private String radiusPort = DEFAULT_RADIUS_PORT;
-
- // Parsed RADIUS server IP address
- protected InetAddress parsedRadiusIpAddress;
-
- // Parsed NAS IP address
- protected InetAddress parsedNasIpAddress;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected ComponentConfigService cfgService;
-
- @Modified
- public void modified(ComponentContext context) {
- Dictionary<?, ?> properties = context.getProperties();
-
- String s = Tools.get(properties, "radiusIpAddress");
- try {
- parsedRadiusIpAddress = InetAddress.getByName(s);
- radiusIpAddress = Strings.isNullOrEmpty(s) ? DEFAULT_RADIUS_IP : s;
- } catch (UnknownHostException e) {
- log.error("Invalid RADIUS IP address specification: {}", s);
- }
- try {
- s = Tools.get(properties, "nasIpAddress");
- parsedNasIpAddress = InetAddress.getByName(s);
- nasIpAddress = Strings.isNullOrEmpty(s) ? DEFAULT_NAS_IP : s;
- } catch (UnknownHostException e) {
- log.error("Invalid NAS IP address specification: {}", s);
- }
+ // Configuration properties factory
+ private final ConfigFactory factory =
+ new ConfigFactory<ApplicationId, AAAConfig>(APP_SUBJECT_FACTORY,
+ AAAConfig.class,
+ "AAA") {
+ @Override
+ public AAAConfig createConfig() {
+ return new AAAConfig();
+ }
+ };
- s = Tools.get(properties, "radiusMacAddress");
- radiusMacAddress = Strings.isNullOrEmpty(s) ? RADIUS_MAC_ADDRESS : s;
+ // Listener for config changes
+ private final InternalConfigListener cfgListener = new InternalConfigListener();
- s = Tools.get(properties, "nasMacAddress");
- nasMacAddress = Strings.isNullOrEmpty(s) ? NAS_MAC_ADDRESS : s;
+ /**
+ * Builds an EAPOL packet based on the given parameters.
+ *
+ * @param dstMac destination MAC address
+ * @param srcMac source MAC address
+ * @param vlan vlan identifier
+ * @param eapolType EAPOL type
+ * @param eap EAP payload
+ * @return Ethernet frame
+ */
+ private static Ethernet buildEapolResponse(MacAddress dstMac, MacAddress srcMac,
+ short vlan, byte eapolType, EAP eap) {
- s = Tools.get(properties, "radiusSecret");
- radiusSecret = Strings.isNullOrEmpty(s) ? DEFAULT_RADIUS_SECRET : s;
+ Ethernet eth = new Ethernet();
+ eth.setDestinationMACAddress(dstMac.toBytes());
+ eth.setSourceMACAddress(srcMac.toBytes());
+ eth.setEtherType(EthType.EtherType.EAPOL.ethType().toShort());
+ if (vlan != Ethernet.VLAN_UNTAGGED) {
+ eth.setVlanID(vlan);
+ }
+ //eapol header
+ EAPOL eapol = new EAPOL();
+ eapol.setEapolType(eapolType);
+ eapol.setPacketLength(eap.getLength());
- s = Tools.get(properties, "radiusSwitchId");
- radiusSwitch = Strings.isNullOrEmpty(s) ? DEFAULT_RADIUS_SWITCH : s;
+ //eap part
+ eapol.setPayload(eap);
- s = Tools.get(properties, "radiusPortNumber");
- radiusPort = Strings.isNullOrEmpty(s) ? DEFAULT_RADIUS_PORT : s;
+ eth.setPayload(eapol);
+ eth.setPad(true);
+ return eth;
}
@Activate
- public void activate(ComponentContext context) {
- cfgService.registerProperties(getClass());
- modified(context);
+ public void activate() {
+ netCfgService.addListener(cfgListener);
+ netCfgService.registerConfigFactory(factory);
+
// "org.onosproject.aaa" is the FQDN of our app
appId = coreService.registerApplication("org.onosproject.aaa");
+
+ cfgListener.reconfigureNetwork(netCfgService.getConfig(appId, AAAConfig.class));
+
// register our event handler
packetService.addProcessor(processor, PacketProcessor.director(2));
requestIntercepts();
- // Instantiate the map of the state machines
- stateMachineMap = Collections.synchronizedMap(Maps.newHashMap());
- hostService.startMonitoringIp(IpAddress.valueOf(radiusIpAddress));
+ StateMachine.initializeMaps();
+ hostService.startMonitoringIp(IpAddress.valueOf(radiusIpAddress));
}
@Deactivate
public void deactivate() {
- cfgService.unregisterProperties(getClass(), false);
-
appId = coreService.registerApplication("org.onosproject.aaa");
withdrawIntercepts();
// de-register and null our handler
packetService.removeProcessor(processor);
processor = null;
+ StateMachine.destroyMaps();
}
/**
@@ -237,8 +209,8 @@ public class AAA {
TrafficSelector radSelector = DefaultTrafficSelector.builder()
.matchEthType(EthType.EtherType.IPV4.ethType().toShort())
.matchIPProtocol(IPv4.PROTOCOL_UDP)
- .matchUdpDst(TpPort.tpPort(1812))
- .matchUdpSrc(TpPort.tpPort(1812))
+ .matchUdpDst(TpPort.tpPort(radiusServerPort))
+ .matchUdpSrc(TpPort.tpPort(radiusServerPort))
.build();
packetService.requestPackets(radSelector, CONTROL, appId);
}
@@ -254,45 +226,12 @@ public class AAA {
TrafficSelector radSelector = DefaultTrafficSelector.builder()
.matchEthType(EthType.EtherType.IPV4.ethType().toShort())
.matchIPProtocol(IPv4.PROTOCOL_UDP)
- .matchUdpDst(TpPort.tpPort(1812))
- .matchUdpSrc(TpPort.tpPort(1812))
+ .matchUdpDst(TpPort.tpPort(radiusServerPort))
+ .matchUdpSrc(TpPort.tpPort(radiusServerPort))
.build();
packetService.cancelPackets(radSelector, CONTROL, appId);
}
- /**
- * Builds an EAPOL packet based on the given parameters.
- *
- * @param dstMac destination MAC address
- * @param srcMac source MAC address
- * @param vlan vlan identifier
- * @param eapolType EAPOL type
- * @param eap EAP payload
- * @return Ethernet frame
- */
- private static Ethernet buildEapolResponse(MacAddress dstMac, MacAddress srcMac,
- short vlan, byte eapolType, EAP eap) {
-
- Ethernet eth = new Ethernet();
- eth.setDestinationMACAddress(dstMac.toBytes());
- eth.setSourceMACAddress(srcMac.toBytes());
- eth.setEtherType(EthType.EtherType.EAPOL.ethType().toShort());
- if (vlan != Ethernet.VLAN_UNTAGGED) {
- eth.setVlanID(vlan);
- }
- //eapol header
- EAPOL eapol = new EAPOL();
- eapol.setEapolType(eapolType);
- eapol.setPacketLength(eap.getLength());
-
- //eap part
- eapol.setPayload(eap);
-
- eth.setPayload(eapol);
- eth.setPad(true);
- return eth;
- }
-
// our handler defined as a private inner class
/**
@@ -308,42 +247,66 @@ public class AAA {
if (ethPkt == null) {
return;
}
- // identify if incoming packet comes from supplicant (EAP) or RADIUS
- switch (EthType.EtherType.lookup(ethPkt.getEtherType())) {
- case EAPOL:
- handleSupplicantPacket(context.inPacket());
- break;
- case IPV4:
- IPv4 ipv4Packet = (IPv4) ethPkt.getPayload();
- Ip4Address srcIp = Ip4Address.valueOf(ipv4Packet.getSourceAddress());
- Ip4Address radiusIp4Address = Ip4Address.valueOf(parsedRadiusIpAddress);
- if (srcIp.equals(radiusIp4Address) && ipv4Packet.getProtocol() == IPv4.PROTOCOL_UDP) {
- // TODO: check for port as well when it's configurable
- UDP udpPacket = (UDP) ipv4Packet.getPayload();
-
- byte[] datagram = udpPacket.getPayload().serialize();
- RADIUS radiusPacket;
- try {
+ try {
+ // identify if incoming packet comes from supplicant (EAP) or RADIUS
+ switch (EthType.EtherType.lookup(ethPkt.getEtherType())) {
+ case EAPOL:
+ handleSupplicantPacket(context.inPacket());
+ break;
+ case IPV4:
+ IPv4 ipv4Packet = (IPv4) ethPkt.getPayload();
+ Ip4Address srcIp = Ip4Address.valueOf(ipv4Packet.getSourceAddress());
+ Ip4Address radiusIp4Address = Ip4Address.valueOf(radiusIpAddress);
+ if (srcIp.equals(radiusIp4Address) && ipv4Packet.getProtocol() == IPv4.PROTOCOL_UDP) {
+ // TODO: check for port as well when it's configurable
+ UDP udpPacket = (UDP) ipv4Packet.getPayload();
+
+ byte[] datagram = udpPacket.getPayload().serialize();
+ RADIUS radiusPacket;
radiusPacket = RADIUS.deserializer().deserialize(datagram, 0, datagram.length);
- } catch (DeserializationException e) {
- log.warn("Unable to deserialize RADIUS packet:", e);
- return;
+ handleRadiusPacket(radiusPacket);
}
- handleRadiusPacket(radiusPacket);
- }
- break;
- default:
- return;
+
+ break;
+ default:
+ log.trace("Skipping Ethernet packet type {}",
+ EthType.EtherType.lookup(ethPkt.getEtherType()));
+ }
+ } catch (DeserializationException | StateMachineException e) {
+ log.warn("Unable to process RADIUS packet:", e);
}
}
+ /**
+ * Creates and initializes common fields of a RADIUS packet.
+ *
+ * @param identifier RADIUS identifier
+ * @param eapPacket EAP packet
+ * @return RADIUS packet
+ */
+ private RADIUS getRadiusPayload(byte identifier, EAP eapPacket) {
+ RADIUS radiusPayload =
+ new RADIUS(RADIUS.RADIUS_CODE_ACCESS_REQUEST,
+ eapPacket.getIdentifier());
+ radiusPayload.setIdentifier(identifier);
+ radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME,
+ eapPacket.getData());
+
+ radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP,
+ AAA.this.nasIpAddress.getAddress());
+
+ radiusPayload.encapsulateMessage(eapPacket);
+ radiusPayload.addMessageAuthenticator(AAA.this.radiusSecret);
+
+ return radiusPayload;
+ }
/**
* Handles PAE packets (supplicant).
*
* @param inPacket Ethernet packet coming from the supplicant
*/
- private void handleSupplicantPacket(InboundPacket inPacket) {
+ private void handleSupplicantPacket(InboundPacket inPacket) throws StateMachineException {
Ethernet ethPkt = inPacket.parsed();
// Where does it come from?
MacAddress srcMAC = ethPkt.getSourceMAC();
@@ -351,114 +314,83 @@ public class AAA {
DeviceId deviceId = inPacket.receivedFrom().deviceId();
PortNumber portNumber = inPacket.receivedFrom().port();
String sessionId = deviceId.toString() + portNumber.toString();
- StateMachine stateMachine = getStateMachine(sessionId);
+ StateMachine stateMachine = StateMachine.lookupStateMachineBySessionId(sessionId);
+ if (stateMachine == null) {
+ stateMachine = new StateMachine(sessionId, voltTenantService);
+ }
+
EAPOL eapol = (EAPOL) ethPkt.getPayload();
switch (eapol.getEapolType()) {
case EAPOL.EAPOL_START:
- try {
- stateMachine.start();
- stateMachine.supplicantConnectpoint = inPacket.receivedFrom();
-
- //send an EAP Request/Identify to the supplicant
- EAP eapPayload = new EAP(EAP.REQUEST, stateMachine.getIdentifier(), EAP.ATTR_IDENTITY, null);
- Ethernet eth = buildEapolResponse(srcMAC, MacAddress.valueOf(1L),
- ethPkt.getVlanID(), EAPOL.EAPOL_PACKET,
- eapPayload);
- stateMachine.supplicantAddress = srcMAC;
- stateMachine.vlanId = ethPkt.getVlanID();
-
- this.sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint);
- } catch (StateMachineException e) {
- e.printStackTrace();
- }
+ stateMachine.start();
+ stateMachine.setSupplicantConnectpoint(inPacket.receivedFrom());
+
+ //send an EAP Request/Identify to the supplicant
+ EAP eapPayload = new EAP(EAP.REQUEST, stateMachine.identifier(), EAP.ATTR_IDENTITY, null);
+ Ethernet eth = buildEapolResponse(srcMAC, MacAddress.valueOf(1L),
+ ethPkt.getVlanID(), EAPOL.EAPOL_PACKET,
+ eapPayload);
+ stateMachine.setSupplicantAddress(srcMAC);
+ stateMachine.setVlanId(ethPkt.getVlanID());
+
+ this.sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
break;
case EAPOL.EAPOL_PACKET:
- //check if this is a Response/Identify or a Response/TLS
+ RADIUS radiusPayload;
+ // check if this is a Response/Identify or a Response/TLS
EAP eapPacket = (EAP) eapol.getPayload();
byte dataType = eapPacket.getDataType();
switch (dataType) {
+
case EAP.ATTR_IDENTITY:
- try {
- //request id access to RADIUS
- RADIUS radiusPayload = new RADIUS(RADIUS.RADIUS_CODE_ACCESS_REQUEST,
- eapPacket.getIdentifier());
- radiusPayload.setIdentifier(stateMachine.getIdentifier());
- radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME,
- eapPacket.getData());
- stateMachine.setUsername(eapPacket.getData());
- radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP,
- AAA.this.parsedNasIpAddress.getAddress());
-
- radiusPayload.encapsulateMessage(eapPacket);
-
- // set Request Authenticator in StateMachine
- stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
- radiusPayload.addMessageAuthenticator(AAA.this.radiusSecret);
- sendRadiusMessage(radiusPayload);
+ // request id access to RADIUS
+ stateMachine.setUsername(eapPacket.getData());
- //change the state to "PENDING"
- stateMachine.requestAccess();
- } catch (StateMachineException e) {
- e.printStackTrace();
- }
+ radiusPayload = getRadiusPayload(stateMachine.identifier(), eapPacket);
+
+ // set Request Authenticator in StateMachine
+ stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
+ sendRadiusMessage(radiusPayload);
+
+ // change the state to "PENDING"
+ stateMachine.requestAccess();
break;
case EAP.ATTR_MD5:
- //verify if the EAP identifier corresponds to the challenge identifier from the client state
- //machine.
- if (eapPacket.getIdentifier() == stateMachine.getChallengeIdentifier()) {
+ // verify if the EAP identifier corresponds to the
+ // challenge identifier from the client state
+ // machine.
+ if (eapPacket.getIdentifier() == stateMachine.challengeIdentifier()) {
//send the RADIUS challenge response
- RADIUS radiusPayload = new RADIUS(RADIUS.RADIUS_CODE_ACCESS_REQUEST,
- eapPacket.getIdentifier());
- radiusPayload.setIdentifier(stateMachine.getChallengeIdentifier());
- radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME,
- stateMachine.getUsername());
- radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP,
- AAA.this.parsedNasIpAddress.getAddress());
-
- radiusPayload.encapsulateMessage(eapPacket);
+ radiusPayload = getRadiusPayload(stateMachine.challengeIdentifier(), eapPacket);
radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
- stateMachine.getChallengeState());
- radiusPayload.addMessageAuthenticator(AAA.this.radiusSecret);
+ stateMachine.challengeState());
sendRadiusMessage(radiusPayload);
}
break;
case EAP.ATTR_TLS:
- try {
- //request id access to RADIUS
- RADIUS radiusPayload = new RADIUS(RADIUS.RADIUS_CODE_ACCESS_REQUEST,
- eapPacket.getIdentifier());
- radiusPayload.setIdentifier(stateMachine.getIdentifier());
- radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME,
- stateMachine.getUsername());
- radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP,
- AAA.this.parsedNasIpAddress.getAddress());
-
- radiusPayload.encapsulateMessage(eapPacket);
+ // request id access to RADIUS
+ radiusPayload = getRadiusPayload(stateMachine.identifier(), eapPacket);
- radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
- stateMachine.getChallengeState());
- stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
+ radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
+ stateMachine.challengeState());
+ stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
- radiusPayload.addMessageAuthenticator(AAA.this.radiusSecret);
+ sendRadiusMessage(radiusPayload);
+ // TODO: this gets called on every fragment, should only be called at TLS-Start
+ stateMachine.requestAccess();
- sendRadiusMessage(radiusPayload);
- // TODO: this gets called on every fragment, should only be called at TLS-Start
- stateMachine.requestAccess();
- } catch (StateMachineException e) {
- e.printStackTrace();
- }
break;
default:
return;
}
break;
default:
- return;
+ log.trace("Skipping EAPOL message {}", eapol.getEapolType());
}
}
@@ -467,99 +399,46 @@ public class AAA {
*
* @param radiusPacket RADIUS packet coming from the RADIUS server.
*/
- private void handleRadiusPacket(RADIUS radiusPacket) {
- StateMachine stateMachine = getStateMachineById(radiusPacket.getIdentifier());
+ private void handleRadiusPacket(RADIUS radiusPacket) throws StateMachineException {
+ StateMachine stateMachine = StateMachine.lookupStateMachineById(radiusPacket.getIdentifier());
if (stateMachine == null) {
log.error("Invalid session identifier, exiting...");
return;
}
- EAP eapPayload = new EAP();
- Ethernet eth = null;
+ EAP eapPayload;
+ Ethernet eth;
switch (radiusPacket.getCode()) {
case RADIUS.RADIUS_CODE_ACCESS_CHALLENGE:
byte[] challengeState = radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_STATE).getValue();
eapPayload = radiusPacket.decapsulateMessage();
stateMachine.setChallengeInfo(eapPayload.getIdentifier(), challengeState);
- eth = buildEapolResponse(stateMachine.supplicantAddress,
- MacAddress.valueOf(1L), stateMachine.vlanId, EAPOL.EAPOL_PACKET,
+ eth = buildEapolResponse(stateMachine.supplicantAddress(),
+ MacAddress.valueOf(1L), stateMachine.vlanId(), EAPOL.EAPOL_PACKET,
eapPayload);
- this.sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint);
+ this.sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
break;
case RADIUS.RADIUS_CODE_ACCESS_ACCEPT:
- try {
- //send an EAPOL - Success to the supplicant.
- byte[] eapMessage =
- radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE).getValue();
- eapPayload = new EAP();
- eapPayload = (EAP) eapPayload.deserialize(eapMessage, 0, eapMessage.length);
- eth = buildEapolResponse(stateMachine.supplicantAddress,
- MacAddress.valueOf(1L), stateMachine.vlanId, EAPOL.EAPOL_PACKET,
- eapPayload);
- this.sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint);
-
- stateMachine.authorizeAccess();
- } catch (StateMachineException e) {
- e.printStackTrace();
- }
+ //send an EAPOL - Success to the supplicant.
+ byte[] eapMessage =
+ radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE).getValue();
+ eapPayload = new EAP();
+ eapPayload = (EAP) eapPayload.deserialize(eapMessage, 0, eapMessage.length);
+ eth = buildEapolResponse(stateMachine.supplicantAddress(),
+ MacAddress.valueOf(1L), stateMachine.vlanId(), EAPOL.EAPOL_PACKET,
+ eapPayload);
+ this.sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
+
+ stateMachine.authorizeAccess();
break;
case RADIUS.RADIUS_CODE_ACCESS_REJECT:
- try {
- stateMachine.denyAccess();
- } catch (StateMachineException e) {
- e.printStackTrace();
- }
+ stateMachine.denyAccess();
break;
default:
log.warn("Unknown RADIUS message received with code: {}", radiusPacket.getCode());
}
}
- private StateMachine getStateMachineById(byte identifier) {
- StateMachine stateMachine = null;
- Set stateMachineSet = stateMachineMap.entrySet();
-
- synchronized (stateMachineMap) {
- Iterator itr = stateMachineSet.iterator();
- while (itr.hasNext()) {
- Map.Entry entry = (Map.Entry) itr.next();
- stateMachine = (StateMachine) entry.getValue();
- if (identifier == stateMachine.getIdentifier()) {
- //the state machine has already been created for this session session
- stateMachine = (StateMachine) entry.getValue();
- break;
- }
- }
- }
-
- return stateMachine;
- }
-
- private StateMachine getStateMachine(String sessionId) {
- StateMachine stateMachine = null;
- Set stateMachineSet = stateMachineMap.entrySet();
-
- synchronized (stateMachineMap) {
- Iterator itr = stateMachineSet.iterator();
- while (itr.hasNext()) {
-
- Map.Entry entry = (Map.Entry) itr.next();
- if (sessionId.equals(entry.getKey())) {
- //the state machine has already been created for this session session
- stateMachine = (StateMachine) entry.getValue();
- break;
- }
- }
- }
-
- if (stateMachine == null) {
- stateMachine = new StateMachine(sessionId, voltTenantService);
- stateMachineMap.put(sessionId, stateMachine);
- }
-
- return stateMachine;
- }
-
private void sendRadiusMessage(RADIUS radiusMessage) {
Set<Host> hosts = hostService.getHostsByIp(IpAddress.valueOf(radiusIpAddress));
Optional<Host> odst = hosts.stream().filter(h -> h.vlan().toShort() == VlanId.UNTAGGED).findFirst();
@@ -576,12 +455,12 @@ public class AAA {
IPv4 ip4Packet = new IPv4();
Ethernet ethPkt = new Ethernet();
radiusMessage.setParent(udp);
- udp.setDestinationPort((short) 1812);
- udp.setSourcePort((short) 1812); // TODO: make this configurable
+ udp.setDestinationPort(radiusServerPort);
+ udp.setSourcePort(radiusServerPort);
udp.setPayload(radiusMessage);
udp.setParent(ip4Packet);
- ip4Packet.setSourceAddress(AAA.this.nasIpAddress);
- ip4Packet.setDestinationAddress(AAA.this.radiusIpAddress);
+ ip4Packet.setSourceAddress(AAA.this.nasIpAddress.getHostAddress());
+ ip4Packet.setDestinationAddress(AAA.this.radiusIpAddress.getHostAddress());
ip4Packet.setProtocol(IPv4.PROTOCOL_UDP);
ip4Packet.setPayload(udp);
ip4Packet.setParent(ethPkt);
@@ -591,7 +470,7 @@ public class AAA {
ethPkt.setPayload(ip4Packet);
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
- .setOutput(PortNumber.portNumber(Integer.parseInt(radiusPort))).build();
+ .setOutput(PortNumber.portNumber(radiusPort)).build();
OutboundPacket packet = new DefaultOutboundPacket(DeviceId.deviceId(radiusSwitch),
treatment, ByteBuffer.wrap(ethPkt.serialize()));
packetService.emit(packet);
@@ -613,4 +492,59 @@ public class AAA {
}
+ private class InternalConfigListener implements NetworkConfigListener {
+
+ /**
+ * Reconfigures the DHCP Server according to the configuration parameters passed.
+ *
+ * @param cfg configuration object
+ */
+ private void reconfigureNetwork(AAAConfig cfg) {
+ AAAConfig newCfg;
+ if (cfg == null) {
+ newCfg = new AAAConfig();
+ } else {
+ newCfg = cfg;
+ }
+ if (newCfg.nasIp() != null) {
+ nasIpAddress = newCfg.nasIp();
+ }
+ if (newCfg.radiusIp() != null) {
+ radiusIpAddress = newCfg.radiusIp();
+ }
+ if (newCfg.radiusMac() != null) {
+ radiusMacAddress = newCfg.radiusMac();
+ }
+ if (newCfg.nasMac() != null) {
+ nasMacAddress = newCfg.nasMac();
+ }
+ if (newCfg.radiusSecret() != null) {
+ radiusSecret = newCfg.radiusSecret();
+ }
+ if (newCfg.radiusSwitch() != null) {
+ radiusSwitch = newCfg.radiusSwitch();
+ }
+ if (newCfg.radiusPort() != -1) {
+ radiusPort = newCfg.radiusPort();
+ }
+ if (newCfg.radiusServerUDPPort() != -1) {
+ radiusServerPort = newCfg.radiusServerUDPPort();
+ }
+ }
+
+ @Override
+ public void event(NetworkConfigEvent event) {
+
+ if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
+ event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
+ event.configClass().equals(AAAConfig.class)) {
+
+ AAAConfig cfg = netCfgService.getConfig(appId, AAAConfig.class);
+ reconfigureNetwork(cfg);
+ log.info("Reconfigured");
+ }
+ }
+ }
+
+
}
diff --git a/framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/AAAConfig.java b/framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/AAAConfig.java
new file mode 100644
index 00000000..c18d2bf2
--- /dev/null
+++ b/framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/AAAConfig.java
@@ -0,0 +1,239 @@
+/*
+ * 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.aaa;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.config.Config;
+import org.onosproject.net.config.basics.BasicElementConfig;
+
+/**
+ * Network config for the AAA app.
+ */
+public class AAAConfig extends Config<ApplicationId> {
+
+ private static final String RADIUS_IP = "radiusIp";
+ private static final String RADIUS_SERVER_PORT = "1812";
+ private static final String RADIUS_MAC = "radiusMac";
+ private static final String NAS_IP = "nasIp";
+ private static final String NAS_MAC = "nasMac";
+ private static final String RADIUS_SECRET = "radiusSecret";
+ private static final String RADIUS_SWITCH = "radiusSwitch";
+ private static final String RADIUS_PORT = "radiusPort";
+
+ // RADIUS server IP address
+ protected static final String DEFAULT_RADIUS_IP = "192.168.1.10";
+
+ // RADIUS MAC address
+ protected static final String DEFAULT_RADIUS_MAC = "00:00:00:00:01:10";
+
+ // NAS IP address
+ protected static final String DEFAULT_NAS_IP = "192.168.1.11";
+
+ // NAS MAC address
+ protected static final String DEFAULT_NAS_MAC = "00:00:00:00:10:01";
+
+ // RADIUS server shared secret
+ protected static final String DEFAULT_RADIUS_SECRET = "ONOSecret";
+
+ // Radius Switch Id
+ protected static final String DEFAULT_RADIUS_SWITCH = "of:90e2ba82f97791e9";
+
+ // Radius Port Number
+ protected static final String DEFAULT_RADIUS_PORT = "129";
+
+ // Radius Server UDP Port Number
+ protected static final String DEFAULT_RADIUS_SERVER_PORT = "1812";
+
+ /**
+ * Gets the value of a string property, protecting for an empty
+ * JSON object.
+ *
+ * @param name name of the property
+ * @param defaultValue default value if none has been specified
+ * @return String value if one os found, default value otherwise
+ */
+ private String getStringProperty(String name, String defaultValue) {
+ if (object == null) {
+ return defaultValue;
+ }
+ return get(name, defaultValue);
+ }
+
+ /**
+ * Returns the NAS ip.
+ *
+ * @return ip address or null if not set
+ */
+ public InetAddress nasIp() {
+ try {
+ return InetAddress.getByName(getStringProperty(NAS_IP, DEFAULT_NAS_IP));
+ } catch (UnknownHostException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Sets the NAS ip.
+ *
+ * @param ip new ip address; null to clear
+ * @return self
+ */
+ public BasicElementConfig nasIp(String ip) {
+ return (BasicElementConfig) setOrClear(NAS_IP, ip);
+ }
+
+ /**
+ * Returns the RADIUS server ip.
+ *
+ * @return ip address or null if not set
+ */
+ public InetAddress radiusIp() {
+ try {
+ return InetAddress.getByName(getStringProperty(RADIUS_IP, DEFAULT_RADIUS_IP));
+ } catch (UnknownHostException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Sets the RADIUS server ip.
+ *
+ * @param ip new ip address; null to clear
+ * @return self
+ */
+ public BasicElementConfig radiusIp(String ip) {
+ return (BasicElementConfig) setOrClear(RADIUS_IP, ip);
+ }
+
+ /**
+ * Returns the RADIUS MAC address.
+ *
+ * @return mac address or null if not set
+ */
+ public String radiusMac() {
+ return getStringProperty(RADIUS_MAC, DEFAULT_RADIUS_MAC);
+ }
+
+ /**
+ * Sets the RADIUS MAC address.
+ *
+ * @param mac new MAC address; null to clear
+ * @return self
+ */
+ public BasicElementConfig radiusMac(String mac) {
+ return (BasicElementConfig) setOrClear(RADIUS_MAC, mac);
+ }
+
+ /**
+ * Returns the RADIUS MAC address.
+ *
+ * @return mac address or null if not set
+ */
+ public String nasMac() {
+ return getStringProperty(NAS_MAC, DEFAULT_NAS_MAC);
+ }
+
+ /**
+ * Sets the RADIUS MAC address.
+ *
+ * @param mac new MAC address; null to clear
+ * @return self
+ */
+ public BasicElementConfig nasMac(String mac) {
+ return (BasicElementConfig) setOrClear(NAS_MAC, mac);
+ }
+
+ /**
+ * Returns the RADIUS secret.
+ *
+ * @return radius secret or null if not set
+ */
+ public String radiusSecret() {
+ return getStringProperty(RADIUS_SECRET, DEFAULT_RADIUS_SECRET);
+ }
+
+ /**
+ * Sets the RADIUS secret.
+ *
+ * @param secret new MAC address; null to clear
+ * @return self
+ */
+ public BasicElementConfig radiusSecret(String secret) {
+ return (BasicElementConfig) setOrClear(RADIUS_SECRET, secret);
+ }
+
+ /**
+ * Returns the ID of the RADIUS switch.
+ *
+ * @return radius switch ID or null if not set
+ */
+ public String radiusSwitch() {
+ return getStringProperty(RADIUS_SWITCH, DEFAULT_RADIUS_SWITCH);
+ }
+
+ /**
+ * Sets the ID of the RADIUS switch.
+ *
+ * @param switchId new RADIUS switch ID; null to clear
+ * @return self
+ */
+ public BasicElementConfig radiusSwitch(String switchId) {
+ return (BasicElementConfig) setOrClear(RADIUS_SWITCH, switchId);
+ }
+
+ /**
+ * Returns the RADIUS port.
+ *
+ * @return radius port or null if not set
+ */
+ public long radiusPort() {
+ return Integer.parseInt(getStringProperty(RADIUS_PORT, DEFAULT_RADIUS_PORT));
+ }
+
+ /**
+ * Sets the RADIUS port.
+ *
+ * @param port new RADIUS port; null to clear
+ * @return self
+ */
+ public BasicElementConfig radiusPort(long port) {
+ return (BasicElementConfig) setOrClear(RADIUS_PORT, port);
+ }
+
+ /**
+ * Returns the RADIUS server UDP port.
+ *
+ * @return radius server UDP port.
+ */
+ public short radiusServerUDPPort() {
+ return Short.parseShort(getStringProperty(RADIUS_SERVER_PORT,
+ DEFAULT_RADIUS_SERVER_PORT));
+ }
+
+ /**
+ * Sets the RADIUS port.
+ *
+ * @param port new RADIUS UDP port; -1 to clear
+ * @return self
+ */
+ public BasicElementConfig radiusServerUDPPort(short port) {
+ return (BasicElementConfig) setOrClear(RADIUS_SERVER_PORT, (long) port);
+ }
+
+}
diff --git a/framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/StateMachine.java b/framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/StateMachine.java
index 60959ada..84f69241 100644
--- a/framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/StateMachine.java
+++ b/framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/StateMachine.java
@@ -18,13 +18,16 @@
package org.onosproject.aaa;
+import java.util.BitSet;
+import java.util.Map;
+
import org.onlab.packet.MacAddress;
import org.onosproject.net.ConnectPoint;
import org.onosproject.xosintegration.VoltTenant;
import org.onosproject.xosintegration.VoltTenantService;
import org.slf4j.Logger;
-import java.util.BitSet;
+import com.google.common.collect.Maps;
import static org.slf4j.LoggerFactory.getLogger;
@@ -58,9 +61,9 @@ class StateMachine {
private byte[] requestAuthenticator;
// Supplicant connectivity info
- protected ConnectPoint supplicantConnectpoint;
- protected MacAddress supplicantAddress;
- protected short vlanId;
+ private ConnectPoint supplicantConnectpoint;
+ private MacAddress supplicantAddress;
+ private short vlanId;
private String sessionId = null;
@@ -109,8 +112,28 @@ class StateMachine {
private int currentState = STATE_IDLE;
+ // Maps of state machines. Each state machine is represented by an
+ // unique identifier on the switch: dpid + port number
+ private static Map<String, StateMachine> sessionIdMap;
+ private static Map<Integer, StateMachine> identifierMap;
- /**
+ public static void initializeMaps() {
+ sessionIdMap = Maps.newConcurrentMap();
+ identifierMap = Maps.newConcurrentMap();
+ }
+
+ public static void destroyMaps() {
+ sessionIdMap = null;
+ identifierMap = null;
+ }
+
+ public static StateMachine lookupStateMachineById(byte identifier) {
+ return identifierMap.get((int) identifier);
+ }
+
+ public static StateMachine lookupStateMachineBySessionId(String sessionId) {
+ return sessionIdMap.get(sessionId);
+ } /**
* State Machine Constructor.
*
* @param sessionId session Id represented by the switch dpid + port number
@@ -120,15 +143,69 @@ class StateMachine {
log.info("Creating a new state machine for {}", sessionId);
this.sessionId = sessionId;
this.voltService = voltService;
+ sessionIdMap.put(sessionId, this);
+ }
+
+ /**
+ * Gets the connect point for the supplicant side.
+ *
+ * @return supplicant connect point
+ */
+ public ConnectPoint supplicantConnectpoint() {
+ return supplicantConnectpoint;
+ }
+
+ /**
+ * Sets the supplicant side connect point.
+ *
+ * @param supplicantConnectpoint supplicant select point.
+ */
+ public void setSupplicantConnectpoint(ConnectPoint supplicantConnectpoint) {
+ this.supplicantConnectpoint = supplicantConnectpoint;
+ }
+
+ /**
+ * Gets the MAC address of the supplicant.
+ *
+ * @return supplicant MAC address
+ */
+ public MacAddress supplicantAddress() {
+ return supplicantAddress;
+ }
+
+ /**
+ * Sets the supplicant MAC address.
+ *
+ * @param supplicantAddress new supplicant MAC address
+ */
+ public void setSupplicantAddress(MacAddress supplicantAddress) {
+ this.supplicantAddress = supplicantAddress;
+ }
+
+ /**
+ * Gets the client's Vlan ID.
+ *
+ * @return client vlan ID
+ */
+ public short vlanId() {
+ return vlanId;
+ }
+ /**
+ * Sets the client's vlan ID.
+ *
+ * @param vlanId new client vlan ID
+ */
+ public void setVlanId(short vlanId) {
+ this.vlanId = vlanId;
}
/**
- * Get the client id that is requesting for access.
+ * Gets the client id that is requesting for access.
*
* @return The client id.
*/
- public String getSessionId() {
+ public String sessionId() {
return this.sessionId;
}
@@ -137,7 +214,7 @@ class StateMachine {
*/
private void createIdentifier() throws StateMachineException {
log.debug("Creating Identifier.");
- int index = -1;
+ int index;
try {
//find the first available spot for identifier assignment
@@ -178,11 +255,11 @@ class StateMachine {
}
/**
- * Get the challenge EAP identifier set by the RADIUS.
+ * Gets the challenge EAP identifier set by the RADIUS.
*
* @return The challenge EAP identifier.
*/
- protected byte getChallengeIdentifier() {
+ protected byte challengeIdentifier() {
return this.challengeIdentifier;
}
@@ -198,11 +275,11 @@ class StateMachine {
}
/**
- * Get the challenge state set by the RADIUS.
+ * Gets the challenge state set by the RADIUS.
*
* @return The challenge state.
*/
- protected byte[] getChallengeState() {
+ protected byte[] challengeState() {
return this.challengeState;
}
@@ -217,16 +294,16 @@ class StateMachine {
/**
- * Get the username.
+ * Gets the username.
*
* @return The requestAuthenticator.
*/
- protected byte[] getReqeustAuthenticator() {
+ protected byte[] requestAuthenticator() {
return this.requestAuthenticator;
}
/**
- * Set the username.
+ * Sets the authenticator.
*
* @param authenticator The username sent to the RADIUS upon access request.
*/
@@ -236,11 +313,11 @@ class StateMachine {
/**
- * Get the username.
+ * Gets the username.
*
* @return The username.
*/
- protected byte[] getUsername() {
+ protected byte[] username() {
return this.username;
}
@@ -249,7 +326,7 @@ class StateMachine {
*
* @return The state machine identifier.
*/
- public byte getIdentifier() {
+ public byte identifier() {
return (byte) this.identifier;
}
@@ -267,7 +344,7 @@ class StateMachine {
/**
* Move to the next state.
*
- * @param msg
+ * @param msg message
*/
private void next(int msg) {
currentState = transition[currentState][msg];
@@ -280,14 +357,11 @@ class StateMachine {
* @throws StateMachineException if authentication protocol is violated
*/
public void start() throws StateMachineException {
- try {
- states[currentState].start();
- //move to the next state
- next(TRANSITION_START);
- createIdentifier();
- } catch (StateMachineInvalidTransitionException e) {
- e.printStackTrace();
- }
+ states[currentState].start();
+ //move to the next state
+ next(TRANSITION_START);
+ createIdentifier();
+ identifierMap.put(identifier, this);
}
/**
@@ -297,13 +371,9 @@ class StateMachine {
* @throws StateMachineException if authentication protocol is violated
*/
public void requestAccess() throws StateMachineException {
- try {
- states[currentState].requestAccess();
- //move to the next state
- next(TRANSITION_REQUEST_ACCESS);
- } catch (StateMachineInvalidTransitionException e) {
- e.printStackTrace();
- }
+ states[currentState].requestAccess();
+ //move to the next state
+ next(TRANSITION_REQUEST_ACCESS);
}
/**
@@ -313,27 +383,22 @@ class StateMachine {
* @throws StateMachineException if authentication protocol is violated
*/
public void authorizeAccess() throws StateMachineException {
- try {
- states[currentState].radiusAccepted();
- //move to the next state
- next(TRANSITION_AUTHORIZE_ACCESS);
-
- if (voltService != null) {
- voltService.addTenant(
- VoltTenant.builder()
- .withHumanReadableName("VCPE-" + this.identifier)
- .withId(this.identifier)
- .withProviderService(1)
- .withServiceSpecificId(String.valueOf(this.identifier))
- .withPort(this.supplicantConnectpoint)
- .withVlanId(String.valueOf(this.vlanId)).build());
- }
-
- deleteIdentifier();
- } catch (StateMachineInvalidTransitionException e) {
- e.printStackTrace();
+ states[currentState].radiusAccepted();
+ //move to the next state
+ next(TRANSITION_AUTHORIZE_ACCESS);
+
+ if (voltService != null) {
+ voltService.addTenant(
+ VoltTenant.builder()
+ .withHumanReadableName("VCPE-" + this.identifier)
+ .withId(this.identifier)
+ .withProviderService(1)
+ .withServiceSpecificId(String.valueOf(this.identifier))
+ .withPort(this.supplicantConnectpoint)
+ .withVlanId(String.valueOf(this.vlanId)).build());
}
+ deleteIdentifier();
}
/**
@@ -343,14 +408,10 @@ class StateMachine {
* @throws StateMachineException if authentication protocol is violated
*/
public void denyAccess() throws StateMachineException {
- try {
- states[currentState].radiusDenied();
- //move to the next state
- next(TRANSITION_DENY_ACCESS);
- deleteIdentifier();
- } catch (StateMachineInvalidTransitionException e) {
- e.printStackTrace();
- }
+ states[currentState].radiusDenied();
+ //move to the next state
+ next(TRANSITION_DENY_ACCESS);
+ deleteIdentifier();
}
/**
@@ -360,141 +421,117 @@ class StateMachine {
* @throws StateMachineException if authentication protocol is violated
*/
public void logoff() throws StateMachineException {
- try {
- states[currentState].logoff();
- //move to the next state
- next(TRANSITION_LOGOFF);
- } catch (StateMachineInvalidTransitionException e) {
- e.printStackTrace();
- }
+ states[currentState].logoff();
+ //move to the next state
+ next(TRANSITION_LOGOFF);
}
/**
- * Get the current state.
+ * Gets the current state.
*
* @return The current state. Could be STATE_IDLE, STATE_STARTED, STATE_PENDING, STATE_AUTHORIZED,
* STATE_UNAUTHORIZED.
*/
- public int getState() {
+ public int state() {
return currentState;
}
-
+ @Override
public String toString() {
return ("sessionId: " + this.sessionId) + "\t" + ("identifier: " + this.identifier) + "\t" +
("state: " + this.currentState);
}
-}
-// FIXME: A source file should contain no more than one top-level entity!
+ abstract class State {
+ private final Logger log = getLogger(getClass());
-abstract class State {
- private final Logger log = getLogger(getClass());
-
- private String name = "State";
+ private String name = "State";
- public void start() throws StateMachineInvalidTransitionException {
- log.warn("START transition from this state is not allowed.");
- }
+ public void start() throws StateMachineInvalidTransitionException {
+ log.warn("START transition from this state is not allowed.");
+ }
- public void requestAccess() throws StateMachineInvalidTransitionException {
- log.warn("REQUEST ACCESS transition from this state is not allowed.");
- }
+ public void requestAccess() throws StateMachineInvalidTransitionException {
+ log.warn("REQUEST ACCESS transition from this state is not allowed.");
+ }
- public void radiusAccepted() throws StateMachineInvalidTransitionException {
- log.warn("AUTHORIZE ACCESS transition from this state is not allowed.");
- }
+ public void radiusAccepted() throws StateMachineInvalidTransitionException {
+ log.warn("AUTHORIZE ACCESS transition from this state is not allowed.");
+ }
- public void radiusDenied() throws StateMachineInvalidTransitionException {
- log.warn("DENY ACCESS transition from this state is not allowed.");
- }
+ public void radiusDenied() throws StateMachineInvalidTransitionException {
+ log.warn("DENY ACCESS transition from this state is not allowed.");
+ }
- public void logoff() throws StateMachineInvalidTransitionException {
- log.warn("LOGOFF transition from this state is not allowed.");
+ public void logoff() throws StateMachineInvalidTransitionException {
+ log.warn("LOGOFF transition from this state is not allowed.");
+ }
}
-}
-/**
- * Idle state: supplicant is logged of from the network.
- */
-class Idle extends State {
- private final Logger log = getLogger(getClass());
- private String name = "IDLE_STATE";
+ /**
+ * Idle state: supplicant is logged of from the network.
+ */
+ class Idle extends State {
+ private final Logger log = getLogger(getClass());
+ private String name = "IDLE_STATE";
- public void start() {
- log.info("Moving from IDLE state to STARTED state.");
+ public void start() {
+ log.info("Moving from IDLE state to STARTED state.");
+ }
}
-}
-/**
- * Started state: supplicant has entered the network and informed the authenticator.
- */
-class Started extends State {
- private final Logger log = getLogger(getClass());
- private String name = "STARTED_STATE";
+ /**
+ * Started state: supplicant has entered the network and informed the authenticator.
+ */
+ class Started extends State {
+ private final Logger log = getLogger(getClass());
+ private String name = "STARTED_STATE";
- public void requestAccess() {
- log.info("Moving from STARTED state to PENDING state.");
+ public void requestAccess() {
+ log.info("Moving from STARTED state to PENDING state.");
+ }
}
-}
-/**
- * Pending state: supplicant has been identified by the authenticator but has not access yet.
- */
-class Pending extends State {
- private final Logger log = getLogger(getClass());
- private String name = "PENDING_STATE";
+ /**
+ * Pending state: supplicant has been identified by the authenticator but has not access yet.
+ */
+ class Pending extends State {
+ private final Logger log = getLogger(getClass());
+ private String name = "PENDING_STATE";
- public void radiusAccepted() {
- log.info("Moving from PENDING state to AUTHORIZED state.");
- }
+ public void radiusAccepted() {
+ log.info("Moving from PENDING state to AUTHORIZED state.");
+ }
- public void radiusDenied() {
- log.info("Moving from PENDING state to UNAUTHORIZED state.");
+ public void radiusDenied() {
+ log.info("Moving from PENDING state to UNAUTHORIZED state.");
+ }
}
-}
-/**
- * Authorized state: supplicant port has been accepted, access is granted.
- */
-class Authorized extends State {
- private final Logger log = getLogger(getClass());
- private String name = "AUTHORIZED_STATE";
+ /**
+ * Authorized state: supplicant port has been accepted, access is granted.
+ */
+ class Authorized extends State {
+ private final Logger log = getLogger(getClass());
+ private String name = "AUTHORIZED_STATE";
- public void logoff() {
+ public void logoff() {
- log.info("Moving from AUTHORIZED state to IDLE state.");
+ log.info("Moving from AUTHORIZED state to IDLE state.");
+ }
}
-}
-/**
- * Unauthorized state: supplicant port has been rejected, access is denied.
- */
-class Unauthorized extends State {
- private final Logger log = getLogger(getClass());
- private String name = "UNAUTHORIZED_STATE";
+ /**
+ * Unauthorized state: supplicant port has been rejected, access is denied.
+ */
+ class Unauthorized extends State {
+ private final Logger log = getLogger(getClass());
+ private String name = "UNAUTHORIZED_STATE";
- public void logoff() {
- log.info("Moving from UNAUTHORIZED state to IDLE state.");
+ public void logoff() {
+ log.info("Moving from UNAUTHORIZED state to IDLE state.");
+ }
}
-}
-/**
- * Exception for the State Machine.
- */
-class StateMachineException extends Exception {
- public StateMachineException(String message) {
- super(message);
-
- }
-}
-
-/**
- * Exception raised when the transition from one state to another is invalid.
- */
-class StateMachineInvalidTransitionException extends StateMachineException {
- public StateMachineInvalidTransitionException(String message) {
- super(message);
- }
}
diff --git a/framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/StateMachineException.java b/framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/StateMachineException.java
new file mode 100644
index 00000000..d4a4da77
--- /dev/null
+++ b/framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/StateMachineException.java
@@ -0,0 +1,28 @@
+/*
+ *
+ * Copyright 2015 AT&T Foundry
+ *
+ * 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.aaa;
+
+/**
+ * Exception for the State Machine.
+ */
+class StateMachineException extends Exception {
+ public StateMachineException(String message) {
+ super(message);
+
+ }
+}
diff --git a/framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/StateMachineInvalidTransitionException.java b/framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/StateMachineInvalidTransitionException.java
new file mode 100644
index 00000000..9f41a34f
--- /dev/null
+++ b/framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/StateMachineInvalidTransitionException.java
@@ -0,0 +1,27 @@
+/*
+ *
+ * Copyright 2015 AT&T Foundry
+ *
+ * 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.aaa;
+
+/**
+ * Exception raised when the transition from one state to another is invalid.
+ */
+class StateMachineInvalidTransitionException extends StateMachineException {
+ public StateMachineInvalidTransitionException(String message) {
+ super(message);
+ }
+}
diff --git a/framework/src/onos/apps/aaa/src/test/java/org/onosproject/aaa/AAATest.java b/framework/src/onos/apps/aaa/src/test/java/org/onosproject/aaa/AAATest.java
index 1b581ab1..75a60336 100644
--- a/framework/src/onos/apps/aaa/src/test/java/org/onosproject/aaa/AAATest.java
+++ b/framework/src/onos/apps/aaa/src/test/java/org/onosproject/aaa/AAATest.java
@@ -15,29 +15,494 @@
*/
package org.onosproject.aaa;
+import java.nio.ByteBuffer;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import org.onlab.packet.Data;
+import org.onlab.packet.DeserializationException;
+import org.onlab.packet.EAP;
+import org.onlab.packet.EAPOL;
+import org.onlab.packet.EthType;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.IPv4;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.RADIUS;
+import org.onlab.packet.RADIUSAttribute;
+import org.onlab.packet.UDP;
+import org.onlab.packet.VlanId;
+import org.onosproject.core.CoreServiceAdapter;
+import org.onosproject.net.Annotations;
+import org.onosproject.net.Host;
+import org.onosproject.net.HostId;
+import org.onosproject.net.HostLocation;
+import org.onosproject.net.config.Config;
+import org.onosproject.net.config.NetworkConfigRegistryAdapter;
+import org.onosproject.net.host.HostServiceAdapter;
+import org.onosproject.net.packet.DefaultInboundPacket;
+import org.onosproject.net.packet.DefaultPacketContext;
+import org.onosproject.net.packet.InboundPacket;
+import org.onosproject.net.packet.OutboundPacket;
+import org.onosproject.net.packet.PacketContext;
+import org.onosproject.net.packet.PacketProcessor;
+import org.onosproject.net.packet.PacketServiceAdapter;
+import org.onosproject.net.provider.ProviderId;
+
+import com.google.common.base.Charsets;
+import com.google.common.collect.ImmutableSet;
+
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
+import static org.onosproject.net.NetTestTools.connectPoint;
/**
* Set of tests of the ONOS application component.
*/
public class AAATest {
+ MacAddress clientMac = MacAddress.valueOf("1a:1a:1a:1a:1a:1a");
+ MacAddress serverMac = MacAddress.valueOf("2a:2a:2a:2a:2a:2a");
+
+ PacketProcessor packetProcessor;
private AAA aaa;
+ List<Ethernet> savedPackets = new LinkedList<>();
+
+ /**
+ * Saves the given packet onto the saved packets list.
+ *
+ * @param eth packet to save
+ */
+ private void savePacket(Ethernet eth) {
+ savedPackets.add(eth);
+ }
+
+ /**
+ * Keeps a reference to the PacketProcessor and saves the OutboundPackets.
+ */
+ private class MockPacketService extends PacketServiceAdapter {
+
+ @Override
+ public void addProcessor(PacketProcessor processor, int priority) {
+ packetProcessor = processor;
+ }
+
+ @Override
+ public void emit(OutboundPacket packet) {
+ try {
+ Ethernet eth = Ethernet.deserializer().deserialize(packet.data().array(),
+ 0, packet.data().array().length);
+ savePacket(eth);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+ }
+ }
+
+ /**
+ * Mocks the DefaultPacketContext.
+ */
+ private final class TestPacketContext extends DefaultPacketContext {
+
+ private TestPacketContext(long time, InboundPacket inPkt,
+ OutboundPacket outPkt, boolean block) {
+ super(time, inPkt, outPkt, block);
+ }
+
+ @Override
+ public void send() {
+ // We don't send anything out.
+ }
+ }
+
+ /**
+ * Mocks a host to allow locating the Radius server.
+ */
+ private static final class MockHost implements Host {
+ @Override
+ public HostId id() {
+ return null;
+ }
+
+ @Override
+ public MacAddress mac() {
+ return null;
+ }
+
+ @Override
+ public VlanId vlan() {
+ return VlanId.vlanId(VlanId.UNTAGGED);
+ }
+
+ @Override
+ public Set<IpAddress> ipAddresses() {
+ return null;
+ }
+
+ @Override
+ public HostLocation location() {
+ return null;
+ }
+
+ @Override
+ public Annotations annotations() {
+ return null;
+ }
+
+ @Override
+ public ProviderId providerId() {
+ return null;
+ }
+ }
+
+ /**
+ * Mocks the Host service.
+ */
+ private static final class MockHostService extends HostServiceAdapter {
+ @Override
+ public Set<Host> getHostsByIp(IpAddress ip) {
+ return ImmutableSet.of(new MockHost());
+ }
+ }
+
+ /**
+ * Mocks the network config registry.
+ */
+ @SuppressWarnings("unchecked")
+ private static final class TestNetworkConfigRegistry
+ extends NetworkConfigRegistryAdapter {
+ @Override
+ public <S, C extends Config<S>> C getConfig(S subject, Class<C> configClass) {
+ return (C) new AAAConfig();
+ }
+ }
+
+ /**
+ * Sends an Ethernet packet to the process method of the Packet Processor.
+ *
+ * @param reply Ethernet packet
+ */
+ private void sendPacket(Ethernet reply) {
+ final ByteBuffer byteBuffer = ByteBuffer.wrap(reply.serialize());
+ InboundPacket inPacket = new DefaultInboundPacket(connectPoint("1", 1),
+ reply,
+ byteBuffer);
+
+ PacketContext context = new TestPacketContext(127L, inPacket, null, false);
+ packetProcessor.process(context);
+ }
+
+ /**
+ * Constructs an Ethernet packet containing a EAPOL_START Payload.
+ *
+ * @return Ethernet packet
+ */
+ private Ethernet constructSupplicantStartPacket() {
+ Ethernet eth = new Ethernet();
+ eth.setDestinationMACAddress(clientMac.toBytes());
+ eth.setSourceMACAddress(serverMac.toBytes());
+ eth.setEtherType(EthType.EtherType.EAPOL.ethType().toShort());
+ eth.setVlanID((short) 2);
+
+ EAP eap = new EAP(EAPOL.EAPOL_START, (byte) 1, EAPOL.EAPOL_START, null);
+
+ //eapol header
+ EAPOL eapol = new EAPOL();
+ eapol.setEapolType(EAPOL.EAPOL_START);
+ eapol.setPacketLength(eap.getLength());
+
+ //eap part
+ eapol.setPayload(eap);
+
+ eth.setPayload(eapol);
+ eth.setPad(true);
+ return eth;
+ }
+
+ /**
+ * Constructs an Ethernet packet containing identification payload.
+ *
+ * @return Ethernet packet
+ */
+ private Ethernet constructSupplicantIdentifyPacket(byte type) {
+ Ethernet eth = new Ethernet();
+ eth.setDestinationMACAddress(clientMac.toBytes());
+ eth.setSourceMACAddress(serverMac.toBytes());
+ eth.setEtherType(EthType.EtherType.EAPOL.ethType().toShort());
+ eth.setVlanID((short) 2);
+
+ String username = "user";
+ EAP eap = new EAP(EAP.REQUEST, (byte) 1, type,
+ username.getBytes(Charsets.US_ASCII));
+ eap.setIdentifier((byte) 1);
+
+ // eapol header
+ EAPOL eapol = new EAPOL();
+ eapol.setEapolType(EAPOL.EAPOL_PACKET);
+ eapol.setPacketLength(eap.getLength());
+
+ // eap part
+ eapol.setPayload(eap);
+
+ eth.setPayload(eapol);
+ eth.setPad(true);
+ return eth;
+ }
+
+ /**
+ * Constructs an Ethernet packet containing a RADIUS challenge
+ * packet.
+ *
+ * @param challengeCode code to use in challenge packet
+ * @param challengeType type to use in challenge packet
+ * @return Ethernet packet
+ */
+ private Ethernet constructRADIUSCodeAccessChallengePacket(byte challengeCode, byte challengeType) {
+ Ethernet eth = new Ethernet();
+ eth.setDestinationMACAddress(clientMac.toBytes());
+ eth.setSourceMACAddress(serverMac.toBytes());
+ eth.setEtherType(EthType.EtherType.IPV4.ethType().toShort());
+ eth.setVlanID((short) 2);
+
+ IPv4 ipv4 = new IPv4();
+ ipv4.setProtocol(IPv4.PROTOCOL_UDP);
+ ipv4.setSourceAddress(aaa.radiusIpAddress.getHostAddress());
+
+ String challenge = "1234";
+
+ EAP eap = new EAP(challengeType, (byte) 1, challengeType,
+ challenge.getBytes(Charsets.US_ASCII));
+ eap.setIdentifier((byte) 1);
+
+ RADIUS radius = new RADIUS();
+ radius.setCode(challengeCode);
+
+ radius.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
+ challenge.getBytes(Charsets.US_ASCII));
+ radius.setPayload(eap);
+ radius.setAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE,
+ eap.serialize());
+
+ UDP udp = new UDP();
+ udp.setPayload(radius);
+ ipv4.setPayload(udp);
+
+ eth.setPayload(ipv4);
+ eth.setPad(true);
+ return eth;
+ }
+
+ /**
+ * Sets up the services required by the AAA application.
+ */
@Before
public void setUp() {
-
+ aaa = new AAA();
+ aaa.netCfgService = new TestNetworkConfigRegistry();
+ aaa.coreService = new CoreServiceAdapter();
+ aaa.packetService = new MockPacketService();
+ aaa.hostService = new MockHostService();
+ aaa.activate();
}
+ /**
+ * Tears down the AAA application.
+ */
@After
public void tearDown() {
+ aaa.deactivate();
+ }
+
+ /**
+ * Extracts the RADIUS packet from a packet sent by the supplicant.
+ *
+ * @param supplicantPacket packet sent by the supplicant
+ * @return RADIUS packet
+ * @throws DeserializationException if deserialization of the packet contents
+ * fails.
+ */
+ private RADIUS checkAndFetchRADIUSPacketFromSupplicant(Ethernet supplicantPacket)
+ throws DeserializationException {
+ assertThat(supplicantPacket, notNullValue());
+ assertThat(supplicantPacket.getVlanID(), is(VlanId.UNTAGGED));
+ assertThat(supplicantPacket.getSourceMAC().toString(), is(aaa.nasMacAddress));
+ assertThat(supplicantPacket.getDestinationMAC().toString(), is(aaa.radiusMacAddress));
+
+ assertThat(supplicantPacket.getPayload(), instanceOf(IPv4.class));
+ IPv4 ipv4 = (IPv4) supplicantPacket.getPayload();
+ assertThat(ipv4, notNullValue());
+ assertThat(IpAddress.valueOf(ipv4.getSourceAddress()).toString(),
+ is(aaa.nasIpAddress.getHostAddress()));
+ assertThat(IpAddress.valueOf(ipv4.getDestinationAddress()).toString(),
+ is(aaa.radiusIpAddress.getHostAddress()));
+
+ assertThat(ipv4.getPayload(), instanceOf(UDP.class));
+ UDP udp = (UDP) ipv4.getPayload();
+ assertThat(udp, notNullValue());
+
+ assertThat(udp.getPayload(), instanceOf(Data.class));
+ Data data = (Data) udp.getPayload();
+ RADIUS radius = RADIUS.deserializer()
+ .deserialize(data.getData(), 0, data.getData().length);
+ assertThat(radius, notNullValue());
+ return radius;
}
+ /**
+ * Checks the contents of a RADIUS packet being sent to the RADIUS server.
+ *
+ * @param radiusPacket packet to check
+ * @param code expected code
+ */
+ private void checkRadiusPacket(Ethernet radiusPacket, byte code) {
+ assertThat(radiusPacket.getVlanID(), is((short) 2));
+
+ // TODO: These address values seem wrong, but are produced by the current AAA implementation
+ assertThat(radiusPacket.getSourceMAC(), is(MacAddress.valueOf(1L)));
+ assertThat(radiusPacket.getDestinationMAC(), is(serverMac));
+
+ assertThat(radiusPacket.getPayload(), instanceOf(EAPOL.class));
+ EAPOL eapol = (EAPOL) radiusPacket.getPayload();
+ assertThat(eapol, notNullValue());
+
+ assertThat(eapol.getEapolType(), is(EAPOL.EAPOL_PACKET));
+ assertThat(eapol.getPayload(), instanceOf(EAP.class));
+ EAP eap = (EAP) eapol.getPayload();
+ assertThat(eap, notNullValue());
+ assertThat(eap.getCode(), is(code));
+ }
+
+ /**
+ * Fetches the sent packet at the given index. The requested packet
+ * must be the last packet on the list.
+ *
+ * @param index index into sent packets array
+ * @return packet
+ */
+ private Ethernet fetchPacket(int index) {
+ assertThat(savedPackets.size(), is(index + 1));
+ Ethernet eth = savedPackets.get(index);
+ assertThat(eth, notNullValue());
+ return eth;
+ }
+
+ /**
+ * Tests the authentication path through the AAA application.
+ *
+ * @throws DeserializationException if packed deserialization fails.
+ */
@Test
- public void basics() {
+ public void testAuthentication() throws DeserializationException {
+
+ // Our session id will be the device ID ("of:1") with the port ("1") concatenated
+ String sessionId = "of:11";
+
+ // (1) Supplicant start up
+
+ Ethernet startPacket = constructSupplicantStartPacket();
+ sendPacket(startPacket);
+
+ Ethernet responsePacket = fetchPacket(0);
+ checkRadiusPacket(responsePacket, EAP.ATTR_IDENTITY);
+
+ // (2) Supplicant identify
+
+ Ethernet identifyPacket = constructSupplicantIdentifyPacket(EAP.ATTR_IDENTITY);
+ sendPacket(identifyPacket);
+ Ethernet radiusIdentifyPacket = fetchPacket(1);
+
+ RADIUS radiusAccessRequest = checkAndFetchRADIUSPacketFromSupplicant(radiusIdentifyPacket);
+ assertThat(radiusAccessRequest, notNullValue());
+ assertThat(radiusAccessRequest.getCode(), is(RADIUS.RADIUS_CODE_ACCESS_REQUEST));
+ assertThat(new String(radiusAccessRequest.getAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME).getValue()),
+ is("user"));
+
+ IpAddress nasIp =
+ IpAddress.valueOf(IpAddress.Version.INET,
+ radiusAccessRequest.getAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP)
+ .getValue());
+ assertThat(nasIp.toString(), is(aaa.nasIpAddress.getHostAddress()));
+
+ // State machine should have been created by now
+
+ StateMachine stateMachine =
+ StateMachine.lookupStateMachineBySessionId(sessionId);
+ assertThat(stateMachine, notNullValue());
+ assertThat(stateMachine.state(), is(StateMachine.STATE_PENDING));
+
+ // (3) RADIUS MD5 challenge
+
+ Ethernet radiusCodeAccessChallengePacket =
+ constructRADIUSCodeAccessChallengePacket(RADIUS.RADIUS_CODE_ACCESS_CHALLENGE, EAP.ATTR_MD5);
+ sendPacket(radiusCodeAccessChallengePacket);
+
+ Ethernet radiusChallengeMD5Packet = fetchPacket(2);
+ checkRadiusPacket(radiusChallengeMD5Packet, EAP.ATTR_MD5);
+
+ // (4) Supplicant MD5 response
+
+ Ethernet md5RadiusPacket = constructSupplicantIdentifyPacket(EAP.ATTR_MD5);
+ sendPacket(md5RadiusPacket);
+ Ethernet supplicantMD5ResponsePacket = fetchPacket(3);
+ RADIUS responseMd5RadiusPacket = checkAndFetchRADIUSPacketFromSupplicant(supplicantMD5ResponsePacket);
+ assertThat(responseMd5RadiusPacket.getIdentifier(), is((byte) 1));
+ assertThat(responseMd5RadiusPacket.getCode(), is(RADIUS.RADIUS_CODE_ACCESS_REQUEST));
+
+ // State machine should be in pending state
+
+ assertThat(stateMachine, notNullValue());
+ assertThat(stateMachine.state(), is(StateMachine.STATE_PENDING));
+
+ // (5) RADIUS TLS Challenge
+
+ Ethernet radiusCodeAccessChallengeTLSPacket =
+ constructRADIUSCodeAccessChallengePacket(RADIUS.RADIUS_CODE_ACCESS_CHALLENGE, EAP.ATTR_TLS);
+ sendPacket(radiusCodeAccessChallengeTLSPacket);
+
+ Ethernet radiusChallengeTLSPacket = fetchPacket(4);
+ checkRadiusPacket(radiusChallengeTLSPacket, EAP.ATTR_TLS);
+
+ // (6) Supplicant TLS response
+
+ Ethernet tlsRadiusPacket = constructSupplicantIdentifyPacket(EAP.ATTR_TLS);
+ sendPacket(tlsRadiusPacket);
+ Ethernet supplicantTLSResponsePacket = fetchPacket(5);
+ RADIUS responseTLSRadiusPacket = checkAndFetchRADIUSPacketFromSupplicant(supplicantTLSResponsePacket);
+ assertThat(responseTLSRadiusPacket.getIdentifier(), is((byte) 0));
+ assertThat(responseTLSRadiusPacket.getCode(), is(RADIUS.RADIUS_CODE_ACCESS_REQUEST));
+
+ // (7) RADIUS Success
+
+ Ethernet successPacket =
+ constructRADIUSCodeAccessChallengePacket(RADIUS.RADIUS_CODE_ACCESS_ACCEPT, EAP.SUCCESS);
+ sendPacket(successPacket);
+ Ethernet supplicantSuccessPacket = fetchPacket(6);
+
+ checkRadiusPacket(supplicantSuccessPacket, EAP.SUCCESS);
+
+ // State machine should be in authorized state
+
+ assertThat(stateMachine, notNullValue());
+ assertThat(stateMachine.state(), is(StateMachine.STATE_AUTHORIZED));
}
+ /**
+ * Tests the default configuration.
+ */
+ @Test
+ public void testConfig() {
+ assertThat(aaa.nasIpAddress.getHostAddress(), is(AAAConfig.DEFAULT_NAS_IP));
+ assertThat(aaa.nasMacAddress, is(AAAConfig.DEFAULT_NAS_MAC));
+ assertThat(aaa.radiusIpAddress.getHostAddress(), is(AAAConfig.DEFAULT_RADIUS_IP));
+ assertThat(aaa.radiusMacAddress, is(AAAConfig.DEFAULT_RADIUS_MAC));
+ }
}
diff --git a/framework/src/onos/apps/aaa/src/test/java/org/onosproject/aaa/StateMachineTest.java b/framework/src/onos/apps/aaa/src/test/java/org/onosproject/aaa/StateMachineTest.java
index 2fe44ab9..04837e85 100644
--- a/framework/src/onos/apps/aaa/src/test/java/org/onosproject/aaa/StateMachineTest.java
+++ b/framework/src/onos/apps/aaa/src/test/java/org/onosproject/aaa/StateMachineTest.java
@@ -21,6 +21,7 @@ import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
+import static org.junit.Assert.*;
public class StateMachineTest {
@@ -30,6 +31,7 @@ public class StateMachineTest {
public void setUp() {
System.out.println("Set Up.");
StateMachine.bitSet.clear();
+ StateMachine.initializeMaps();
stateMachine = new StateMachine("session0", null);
}
@@ -37,6 +39,7 @@ public class StateMachineTest {
public void tearDown() {
System.out.println("Tear Down.");
StateMachine.bitSet.clear();
+ StateMachine.destroyMaps();
stateMachine = null;
}
@@ -46,19 +49,19 @@ public class StateMachineTest {
*/
public void basic() throws StateMachineException {
System.out.println("======= BASIC =======.");
- Assert.assertEquals(stateMachine.getState(), StateMachine.STATE_IDLE);
+ Assert.assertEquals(stateMachine.state(), StateMachine.STATE_IDLE);
stateMachine.start();
- Assert.assertEquals(stateMachine.getState(), StateMachine.STATE_STARTED);
+ Assert.assertEquals(stateMachine.state(), StateMachine.STATE_STARTED);
stateMachine.requestAccess();
- Assert.assertEquals(stateMachine.getState(), StateMachine.STATE_PENDING);
+ Assert.assertEquals(stateMachine.state(), StateMachine.STATE_PENDING);
stateMachine.authorizeAccess();
- Assert.assertEquals(stateMachine.getState(), StateMachine.STATE_AUTHORIZED);
+ Assert.assertEquals(stateMachine.state(), StateMachine.STATE_AUTHORIZED);
stateMachine.logoff();
- Assert.assertEquals(stateMachine.getState(), StateMachine.STATE_IDLE);
+ Assert.assertEquals(stateMachine.state(), StateMachine.STATE_IDLE);
}
@Test
@@ -68,19 +71,19 @@ public class StateMachineTest {
public void testIdleState() throws StateMachineException {
System.out.println("======= IDLE STATE TEST =======.");
stateMachine.requestAccess();
- Assert.assertEquals(stateMachine.getState(), StateMachine.STATE_IDLE);
+ Assert.assertEquals(stateMachine.state(), StateMachine.STATE_IDLE);
stateMachine.authorizeAccess();
- Assert.assertEquals(stateMachine.getState(), StateMachine.STATE_IDLE);
+ Assert.assertEquals(stateMachine.state(), StateMachine.STATE_IDLE);
stateMachine.denyAccess();
- Assert.assertEquals(stateMachine.getState(), StateMachine.STATE_IDLE);
+ Assert.assertEquals(stateMachine.state(), StateMachine.STATE_IDLE);
stateMachine.logoff();
- Assert.assertEquals(stateMachine.getState(), StateMachine.STATE_IDLE);
+ Assert.assertEquals(stateMachine.state(), StateMachine.STATE_IDLE);
stateMachine.start();
- Assert.assertEquals(stateMachine.getState(), StateMachine.STATE_STARTED);
+ Assert.assertEquals(stateMachine.state(), StateMachine.STATE_STARTED);
}
@Test
@@ -92,19 +95,19 @@ public class StateMachineTest {
stateMachine.start();
stateMachine.authorizeAccess();
- Assert.assertEquals(stateMachine.getState(), StateMachine.STATE_STARTED);
+ Assert.assertEquals(stateMachine.state(), StateMachine.STATE_STARTED);
stateMachine.denyAccess();
- Assert.assertEquals(stateMachine.getState(), StateMachine.STATE_STARTED);
+ Assert.assertEquals(stateMachine.state(), StateMachine.STATE_STARTED);
stateMachine.logoff();
- Assert.assertEquals(stateMachine.getState(), StateMachine.STATE_STARTED);
+ Assert.assertEquals(stateMachine.state(), StateMachine.STATE_STARTED);
stateMachine.start();
- Assert.assertEquals(stateMachine.getState(), StateMachine.STATE_STARTED);
+ Assert.assertEquals(stateMachine.state(), StateMachine.STATE_STARTED);
stateMachine.requestAccess();
- Assert.assertEquals(stateMachine.getState(), StateMachine.STATE_PENDING);
+ Assert.assertEquals(stateMachine.state(), StateMachine.STATE_PENDING);
}
@Test
@@ -118,19 +121,19 @@ public class StateMachineTest {
stateMachine.requestAccess();
stateMachine.logoff();
- Assert.assertEquals(stateMachine.getState(), StateMachine.STATE_PENDING);
+ Assert.assertEquals(stateMachine.state(), StateMachine.STATE_PENDING);
stateMachine.start();
- Assert.assertEquals(stateMachine.getState(), StateMachine.STATE_PENDING);
+ Assert.assertEquals(stateMachine.state(), StateMachine.STATE_PENDING);
stateMachine.requestAccess();
- Assert.assertEquals(stateMachine.getState(), StateMachine.STATE_PENDING);
+ Assert.assertEquals(stateMachine.state(), StateMachine.STATE_PENDING);
stateMachine.authorizeAccess();
- Assert.assertEquals(stateMachine.getState(), StateMachine.STATE_AUTHORIZED);
+ Assert.assertEquals(stateMachine.state(), StateMachine.STATE_AUTHORIZED);
stateMachine.denyAccess();
- Assert.assertEquals(stateMachine.getState(), StateMachine.STATE_AUTHORIZED);
+ Assert.assertEquals(stateMachine.state(), StateMachine.STATE_AUTHORIZED);
}
@Test
@@ -144,19 +147,19 @@ public class StateMachineTest {
stateMachine.requestAccess();
stateMachine.logoff();
- Assert.assertEquals(stateMachine.getState(), StateMachine.STATE_PENDING);
+ Assert.assertEquals(stateMachine.state(), StateMachine.STATE_PENDING);
stateMachine.start();
- Assert.assertEquals(stateMachine.getState(), StateMachine.STATE_PENDING);
+ Assert.assertEquals(stateMachine.state(), StateMachine.STATE_PENDING);
stateMachine.requestAccess();
- Assert.assertEquals(stateMachine.getState(), StateMachine.STATE_PENDING);
+ Assert.assertEquals(stateMachine.state(), StateMachine.STATE_PENDING);
stateMachine.denyAccess();
- Assert.assertEquals(stateMachine.getState(), StateMachine.STATE_UNAUTHORIZED);
+ Assert.assertEquals(stateMachine.state(), StateMachine.STATE_UNAUTHORIZED);
stateMachine.authorizeAccess();
- Assert.assertEquals(stateMachine.getState(), StateMachine.STATE_UNAUTHORIZED);
+ Assert.assertEquals(stateMachine.state(), StateMachine.STATE_UNAUTHORIZED);
}
@Test
@@ -170,19 +173,19 @@ public class StateMachineTest {
stateMachine.authorizeAccess();
stateMachine.start();
- Assert.assertEquals(stateMachine.getState(), StateMachine.STATE_AUTHORIZED);
+ Assert.assertEquals(stateMachine.state(), StateMachine.STATE_AUTHORIZED);
stateMachine.requestAccess();
- Assert.assertEquals(stateMachine.getState(), StateMachine.STATE_AUTHORIZED);
+ Assert.assertEquals(stateMachine.state(), StateMachine.STATE_AUTHORIZED);
stateMachine.authorizeAccess();
- Assert.assertEquals(stateMachine.getState(), StateMachine.STATE_AUTHORIZED);
+ Assert.assertEquals(stateMachine.state(), StateMachine.STATE_AUTHORIZED);
stateMachine.denyAccess();
- Assert.assertEquals(stateMachine.getState(), StateMachine.STATE_AUTHORIZED);
+ Assert.assertEquals(stateMachine.state(), StateMachine.STATE_AUTHORIZED);
stateMachine.logoff();
- Assert.assertEquals(stateMachine.getState(), StateMachine.STATE_IDLE);
+ Assert.assertEquals(stateMachine.state(), StateMachine.STATE_IDLE);
}
@Test
@@ -196,27 +199,27 @@ public class StateMachineTest {
stateMachine.denyAccess();
stateMachine.start();
- Assert.assertEquals(stateMachine.getState(), StateMachine.STATE_UNAUTHORIZED);
+ Assert.assertEquals(stateMachine.state(), StateMachine.STATE_UNAUTHORIZED);
stateMachine.requestAccess();
- Assert.assertEquals(stateMachine.getState(), StateMachine.STATE_UNAUTHORIZED);
+ Assert.assertEquals(stateMachine.state(), StateMachine.STATE_UNAUTHORIZED);
stateMachine.authorizeAccess();
- Assert.assertEquals(stateMachine.getState(), StateMachine.STATE_UNAUTHORIZED);
+ Assert.assertEquals(stateMachine.state(), StateMachine.STATE_UNAUTHORIZED);
stateMachine.denyAccess();
- Assert.assertEquals(stateMachine.getState(), StateMachine.STATE_UNAUTHORIZED);
+ Assert.assertEquals(stateMachine.state(), StateMachine.STATE_UNAUTHORIZED);
stateMachine.logoff();
- Assert.assertEquals(stateMachine.getState(), StateMachine.STATE_IDLE);
+ Assert.assertEquals(stateMachine.state(), StateMachine.STATE_IDLE);
}
@Test
public void testIdentifierAvailability() throws StateMachineException {
System.out.println("======= IDENTIFIER TEST =======.");
- byte identifier = stateMachine.getIdentifier();
- System.out.println("State: " + stateMachine.getState());
+ byte identifier = stateMachine.identifier();
+ System.out.println("State: " + stateMachine.state());
System.out.println("Identifier: " + Byte.toUnsignedInt(identifier));
Assert.assertEquals(-1, identifier);
stateMachine.start();
@@ -230,7 +233,7 @@ public class StateMachineTest {
for (int i = 1; i <= 255; i++) {
StateMachine sm = new StateMachine("session" + i, null);
sm.start();
- byte id = sm.getIdentifier();
+ byte id = sm.identifier();
Assert.assertEquals(i, Byte.toUnsignedInt(id));
if (i == 3) {
sm3 = sm;
@@ -244,27 +247,72 @@ public class StateMachineTest {
//simulate the state machine for a specific session and logoff so we can free up a spot for an identifier
//let's choose identifier 247 then we free up 3
+ Assert.assertNotNull(sm247);
sm247.requestAccess();
sm247.authorizeAccess();
sm247.logoff();
- sm247 = null;
+ Assert.assertNotNull(sm3);
sm3.requestAccess();
sm3.authorizeAccess();
sm3.logoff();
- sm3 = null;
StateMachine otherSM3 = new StateMachine("session3b", null);
otherSM3.start();
otherSM3.requestAccess();
- byte id3 = otherSM3.getIdentifier();
+ byte id3 = otherSM3.identifier();
Assert.assertEquals(3, Byte.toUnsignedInt(id3));
StateMachine otherSM247 = new StateMachine("session247b", null);
otherSM247.start();
otherSM247.requestAccess();
- byte id247 = otherSM247.getIdentifier();
+ byte id247 = otherSM247.identifier();
Assert.assertEquals(247, Byte.toUnsignedInt(id247));
+ }
+ @Test
+ public void testSessionIdLookups() {
+ String sessionId1 = "session1";
+ String sessionId2 = "session2";
+ String sessionId3 = "session3";
+
+ StateMachine machine1ShouldBeNull =
+ StateMachine.lookupStateMachineBySessionId(sessionId1);
+ assertNull(machine1ShouldBeNull);
+ StateMachine machine2ShouldBeNull =
+ StateMachine.lookupStateMachineBySessionId(sessionId2);
+ assertNull(machine2ShouldBeNull);
+
+ StateMachine stateMachine1 = new StateMachine(sessionId1, null);
+ StateMachine stateMachine2 = new StateMachine(sessionId2, null);
+
+ assertEquals(stateMachine1,
+ StateMachine.lookupStateMachineBySessionId(sessionId1));
+ assertEquals(stateMachine2,
+ StateMachine.lookupStateMachineBySessionId(sessionId2));
+ assertNull(StateMachine.lookupStateMachineBySessionId(sessionId3));
+ }
+
+ @Test
+ public void testIdentifierLookups() throws StateMachineException {
+ String sessionId1 = "session1";
+ String sessionId2 = "session2";
+
+ StateMachine machine1ShouldBeNull =
+ StateMachine.lookupStateMachineById((byte) 1);
+ assertNull(machine1ShouldBeNull);
+ StateMachine machine2ShouldBeNull =
+ StateMachine.lookupStateMachineById((byte) 2);
+ assertNull(machine2ShouldBeNull);
+
+ StateMachine stateMachine1 = new StateMachine(sessionId1, null);
+ stateMachine1.start();
+ StateMachine stateMachine2 = new StateMachine(sessionId2, null);
+ stateMachine2.start();
+
+ assertEquals(stateMachine1,
+ StateMachine.lookupStateMachineById(stateMachine1.identifier()));
+ assertEquals(stateMachine2,
+ StateMachine.lookupStateMachineById(stateMachine2.identifier()));
}
}
diff --git a/framework/src/onos/apps/acl/pom.xml b/framework/src/onos/apps/acl/pom.xml
index 54dee432..454ac7e6 100644
--- a/framework/src/onos/apps/acl/pom.xml
+++ b/framework/src/onos/apps/acl/pom.xml
@@ -18,7 +18,9 @@
~ 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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
@@ -36,10 +38,10 @@
<url>http://onosproject.org</url>
<properties>
- <onos.version>1.4.0-SNAPSHOT</onos.version>
<onos.app.name>org.onosproject.acl</onos.app.name>
<onos.app.origin>DLUT</onos.app.origin>
- <web.context>/onos/acl</web.context>
+
+ <web.context>/onos/v1/acl</web.context>
<api.version>1.0.0</api.version>
<api.title>ONOS ACL Application REST API</api.title>
<api.description>
@@ -64,19 +66,34 @@
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onlab-junit</artifactId>
- <version>${onos.version}</version>
</dependency>
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onos-rest</artifactId>
- <version>${onos.version}</version>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onlab-osgi</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>
+ <classifier>tests</classifier>
+ <scope>test</scope>
</dependency>
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onos-core-serializers</artifactId>
- <version>${onos.version}</version>
+ <version>${project.version}</version>
</dependency>
<dependency>
@@ -100,7 +117,6 @@
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onlab-misc</artifactId>
- <version>${onos.version}</version>
</dependency>
</dependencies>
diff --git a/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/AclRule.java b/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/AclRule.java
new file mode 100644
index 00000000..8c91da4c
--- /dev/null
+++ b/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/AclRule.java
@@ -0,0 +1,290 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ * Originally created by Pengfei Lu, Network and Cloud Computing Laboratory, Dalian University of Technology, China
+ * Advisers: Keqiu Li, Heng Qi and Haisheng Yu
+ * This work is supported by the State Key Program of National Natural Science of China(Grant No. 61432002)
+ * and Prospective Research Project on Future Networks in Jiangsu Future Networks Innovation Institute.
+ *
+ * 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.acl;
+
+import com.google.common.base.MoreObjects;
+import org.onlab.packet.IPv4;
+import org.onlab.packet.Ip4Prefix;
+import org.onosproject.core.IdGenerator;
+
+import java.util.Objects;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+/**
+ * ACL rule class.
+ */
+public final class AclRule {
+
+ private final RuleId id;
+
+ private final Ip4Prefix srcIp;
+ private final Ip4Prefix dstIp;
+ private final byte ipProto;
+ private final short dstTpPort;
+ private final Action action;
+
+ private static IdGenerator idGenerator;
+
+ /**
+ * Enum type for ACL rule's action.
+ */
+ public enum Action {
+ DENY, ALLOW
+ }
+
+ /**
+ * Constructor for serializer.
+ */
+ private AclRule() {
+ this.id = null;
+ this.srcIp = null;
+ this.dstIp = null;
+ this.ipProto = 0;
+ this.dstTpPort = 0;
+ this.action = null;
+ }
+
+ /**
+ * Create a new ACL rule.
+ *
+ * @param srcIp source IP address
+ * @param dstIp destination IP address
+ * @param ipProto IP protocol
+ * @param dstTpPort destination transport layer port
+ * @param action ACL rule's action
+ */
+ private AclRule(Ip4Prefix srcIp, Ip4Prefix dstIp, byte ipProto,
+ short dstTpPort, Action action) {
+ checkState(idGenerator != null, "Id generator is not bound.");
+ this.id = RuleId.valueOf(idGenerator.getNewId());
+ this.srcIp = srcIp;
+ this.dstIp = dstIp;
+ this.ipProto = ipProto;
+ this.dstTpPort = dstTpPort;
+ this.action = action;
+ }
+
+ /**
+ * Check if the first CIDR address is in (or the same as) the second CIDR address.
+ */
+ private boolean checkCIDRinCIDR(Ip4Prefix cidrAddr1, Ip4Prefix cidrAddr2) {
+ if (cidrAddr2 == null) {
+ return true;
+ } else if (cidrAddr1 == null) {
+ return false;
+ }
+ if (cidrAddr1.prefixLength() < cidrAddr2.prefixLength()) {
+ return false;
+ }
+ int offset = 32 - cidrAddr2.prefixLength();
+
+ int cidr1Prefix = cidrAddr1.address().toInt();
+ int cidr2Prefix = cidrAddr2.address().toInt();
+ cidr1Prefix = cidr1Prefix >> offset;
+ cidr2Prefix = cidr2Prefix >> offset;
+ cidr1Prefix = cidr1Prefix << offset;
+ cidr2Prefix = cidr2Prefix << offset;
+
+ return (cidr1Prefix == cidr2Prefix);
+ }
+
+ /**
+ * Check if this ACL rule match the given ACL rule.
+ *
+ * @param r ACL rule to check against
+ * @return true if this ACL rule matches the given ACL ruleule.
+ */
+ public boolean checkMatch(AclRule r) {
+ return (this.dstTpPort == r.dstTpPort || r.dstTpPort == 0)
+ && (this.ipProto == r.ipProto || r.ipProto == 0)
+ && (checkCIDRinCIDR(this.srcIp(), r.srcIp()))
+ && (checkCIDRinCIDR(this.dstIp(), r.dstIp()));
+ }
+
+ /**
+ * Returns a new ACL rule builder.
+ *
+ * @return ACL rule builder
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /**
+ * Builder of an ACL rule.
+ */
+ public static final class Builder {
+
+ private Ip4Prefix srcIp = null;
+ private Ip4Prefix dstIp = null;
+ private byte ipProto = 0;
+ private short dstTpPort = 0;
+ private Action action = Action.DENY;
+
+ private Builder() {
+ // Hide constructor
+ }
+
+ /**
+ * Sets the source IP address for the ACL rule that will be built.
+ *
+ * @param srcIp source IP address to use for built ACL rule
+ * @return this builder
+ */
+ public Builder srcIp(Ip4Prefix srcIp) {
+ this.srcIp = srcIp;
+ return this;
+ }
+
+ /**
+ * Sets the destination IP address for the ACL rule that will be built.
+ *
+ * @param dstIp destination IP address to use for built ACL rule
+ * @return this builder
+ */
+ public Builder dstIp(Ip4Prefix dstIp) {
+ this.dstIp = dstIp;
+ return this;
+ }
+
+ /**
+ * Sets the IP protocol for the ACL rule that will be built.
+ *
+ * @param ipProto IP protocol to use for built ACL rule
+ * @return this builder
+ */
+ public Builder ipProto(byte ipProto) {
+ this.ipProto = ipProto;
+ return this;
+ }
+
+ /**
+ * Sets the destination transport layer port for the ACL rule that will be built.
+ *
+ * @param dstTpPort destination transport layer port to use for built ACL rule
+ * @return this builder
+ */
+ public Builder dstTpPort(short dstTpPort) {
+ if ((ipProto == IPv4.PROTOCOL_TCP || ipProto == IPv4.PROTOCOL_UDP)) {
+ this.dstTpPort = dstTpPort;
+ }
+ return this;
+ }
+
+ /**
+ * Sets the action for the ACL rule that will be built.
+ *
+ * @param action action to use for built ACL rule
+ * @return this builder
+ */
+ public Builder action(Action action) {
+ this.action = action;
+ return this;
+ }
+
+ /**
+ * Builds an ACL rule from the accumulated parameters.
+ *
+ * @return ACL rule instance
+ */
+ public AclRule build() {
+ checkState(srcIp != null && dstIp != null, "Either srcIp or dstIp must be assigned.");
+ checkState(ipProto == 0 || ipProto == IPv4.PROTOCOL_ICMP
+ || ipProto == IPv4.PROTOCOL_TCP || ipProto == IPv4.PROTOCOL_UDP,
+ "ipProto must be assigned to TCP, UDP, or ICMP.");
+ return new AclRule(srcIp, dstIp, ipProto, dstTpPort, action);
+ }
+
+ }
+
+ /**
+ * Binds an id generator for unique ACL rule id generation.
+ * <p>
+ * Note: A generator cannot be bound if there is already a generator bound.
+ *
+ * @param newIdGenerator id generator
+ */
+ public static void bindIdGenerator(IdGenerator newIdGenerator) {
+ checkState(idGenerator == null, "Id generator is already bound.");
+ idGenerator = checkNotNull(newIdGenerator);
+ }
+
+ public RuleId id() {
+ return id;
+ }
+
+ public Ip4Prefix srcIp() {
+ return srcIp;
+ }
+
+ public Ip4Prefix dstIp() {
+ return this.dstIp;
+ }
+
+ public byte ipProto() {
+ return ipProto;
+ }
+
+ public short dstTpPort() {
+ return dstTpPort;
+ }
+
+ public Action action() {
+ return action;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(action, id.fingerprint(), ipProto, srcIp, dstIp, dstTpPort);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof AclRule) {
+ AclRule that = (AclRule) obj;
+ return Objects.equals(id, that.id) &&
+ Objects.equals(srcIp, that.srcIp) &&
+ Objects.equals(dstIp, that.dstIp) &&
+ Objects.equals(ipProto, that.ipProto) &&
+ Objects.equals(dstTpPort, that.dstTpPort) &&
+ Objects.equals(action, that.action);
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .omitNullValues()
+ .add("id", id)
+ .add("srcIp", srcIp)
+ .add("dstIp", dstIp)
+ .add("ipProto", ipProto)
+ .add("dstTpPort", dstTpPort)
+ .add("action", action)
+ .toString();
+ }
+
+}
diff --git a/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/AclService.java b/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/AclService.java
new file mode 100644
index 00000000..487a6761
--- /dev/null
+++ b/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/AclService.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ * Originally created by Pengfei Lu, Network and Cloud Computing Laboratory, Dalian University of Technology, China
+ * Advisers: Keqiu Li, Heng Qi and Haisheng Yu
+ * This work is supported by the State Key Program of National Natural Science of China(Grant No. 61432002)
+ * and Prospective Research Project on Future Networks in Jiangsu Future Networks Innovation Institute.
+ *
+ * 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.acl;
+
+import java.util.List;
+
+/**
+ * Service interface exported by ACL application.
+ */
+public interface AclService {
+
+ /**
+ * Gets a list containing all ACL rules.
+ *
+ * @return a list containing all ACL rules
+ */
+ List<AclRule> getAclRules();
+
+ /**
+ * Adds a new ACL rule.
+ *
+ * @param rule ACL rule
+ * @return true if successfully added, otherwise false
+ */
+ boolean addAclRule(AclRule rule);
+
+ /**
+ * Removes an exsiting ACL rule by rule id.
+ *
+ * @param ruleId ACL rule identifier
+ */
+ void removeAclRule(RuleId ruleId);
+
+ /**
+ * Clears ACL and resets all.
+ */
+ void clearAcl();
+
+} \ No newline at end of file
diff --git a/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/AclStore.java b/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/AclStore.java
new file mode 100644
index 00000000..ff9e25f6
--- /dev/null
+++ b/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/AclStore.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ * Originally created by Pengfei Lu, Network and Cloud Computing Laboratory, Dalian University of Technology, China
+ * Advisers: Keqiu Li, Heng Qi and Haisheng Yu
+ * This work is supported by the State Key Program of National Natural Science of China(Grant No. 61432002)
+ * and Prospective Research Project on Future Networks in Jiangsu Future Networks Innovation Institute.
+ *
+ * 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.acl;
+
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.store.Store;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Service interface exported by ACL distributed store.
+ */
+public interface AclStore extends Store {
+
+ /**
+ * Gets a list containing all ACL rules.
+ *
+ * @return a list containing all ACL rules
+ */
+ List<AclRule> getAclRules();
+
+ /**
+ * Adds a new ACL rule.
+ *
+ * @param rule new ACL rule
+ */
+ void addAclRule(AclRule rule);
+
+ /**
+ * Gets an existing ACL rule.
+ *
+ * @param ruleId ACL rule id
+ * @return ACL rule with the given id
+ */
+ AclRule getAclRule(RuleId ruleId);
+
+ /**
+ * Removes an existing ACL rule by rule id.
+ *
+ * @param ruleId ACL rule id
+ */
+ void removeAclRule(RuleId ruleId);
+
+ /**
+ * Clears ACL and reset all.
+ */
+ void clearAcl();
+
+ /**
+ * Gets the current priority for new ACL flow rule by device id.
+ *
+ * @param deviceId device id
+ * @return new ACL flow rule's priority in the given device
+ */
+ int getPriorityByDevice(DeviceId deviceId);
+
+ /**
+ * Gets a set containing all ACL flow rules belonging to a given ACL rule.
+ *
+ * @param ruleId ACL rule id
+ * @return a set containing all ACL flow rules belonging to the given ACL rule
+ */
+ Set<FlowRule> getFlowByRule(RuleId ruleId);
+
+ /**
+ * Adds a new mapping from ACL rule to ACL flow rule.
+ *
+ * @param ruleId ACL rule id
+ * @param flowRule ACL flow rule
+ */
+ void addRuleToFlowMapping(RuleId ruleId, FlowRule flowRule);
+
+ /**
+ * Removes an existing mapping from ACL rule to ACL flow rule.
+ *
+ * @param ruleId ACL rule id
+ */
+ void removeRuleToFlowMapping(RuleId ruleId);
+
+ /**
+ * Gets a list containing all allowing ACL rules matching a given denying ACL rule.
+ *
+ * @param denyingRuleId denying ACL rule id
+ * @return a list containing all allowing ACL rules matching the given denying ACL rule
+ */
+ List<RuleId> getAllowingRuleByDenyingRule(RuleId denyingRuleId);
+
+ /**
+ * Adds a new mapping from denying ACL rule to allowing ACL rule.
+ *
+ * @param denyingRuleId denying ACL rule id
+ * @param allowingRuleId allowing ACL rule id
+ */
+ void addDenyToAllowMapping(RuleId denyingRuleId, RuleId allowingRuleId);
+
+ /**
+ * Removes an exsiting mapping from denying ACL rule to allowing ACL rule.
+ *
+ * @param denyingRuleId denying ACL rule id
+ */
+ void removeDenyToAllowMapping(RuleId denyingRuleId);
+
+ /**
+ * Checks if an existing ACL rule already works in a given device.
+ *
+ * @param ruleId ACL rule id
+ * @param deviceId devide id
+ * @return true if the given ACL rule works in the given device
+ */
+ boolean checkIfRuleWorksInDevice(RuleId ruleId, DeviceId deviceId);
+
+ /**
+ * Adds a new mapping from ACL rule to device.
+ *
+ * @param ruleId ACL rule id
+ * @param deviceId device id
+ */
+ void addRuleToDeviceMapping(RuleId ruleId, DeviceId deviceId);
+
+ /**
+ * Removes an existing mapping from ACL rule to device.
+ *
+ * @param ruleId ACL rule id
+ */
+ void removeRuleToDeviceMapping(RuleId ruleId);
+
+}
diff --git a/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/AclWebResource.java b/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/AclWebResource.java
new file mode 100644
index 00000000..e792efba
--- /dev/null
+++ b/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/AclWebResource.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ * Originally created by Pengfei Lu, Network and Cloud Computing Laboratory, Dalian University of Technology, China
+ * Advisers: Keqiu Li, Heng Qi and Haisheng Yu
+ * This work is supported by the State Key Program of National Natural Science of China(Grant No. 61432002)
+ * and Prospective Research Project on Future Networks in Jiangsu Future Networks Innovation Institute.
+ *
+ * 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.acl;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onlab.packet.IPv4;
+import org.onlab.packet.Ip4Prefix;
+import org.onosproject.rest.AbstractWebResource;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.List;
+
+/**
+ * Manage ACL rules.
+ */
+@Path("rules")
+public class AclWebResource extends AbstractWebResource {
+
+ /**
+ * Get all ACL rules.
+ * Returns array of all ACL rules.
+ *
+ * @return 200 OK
+ */
+ @GET
+ public Response queryAclRule() {
+ List<AclRule> rules = get(AclService.class).getAclRules();
+ ObjectMapper mapper = new ObjectMapper();
+ ObjectNode root = mapper.createObjectNode();
+ ArrayNode arrayNode = mapper.createArrayNode();
+ for (AclRule rule : rules) {
+ ObjectNode node = mapper.createObjectNode();
+ node.put("id", rule.id().toString());
+ if (rule.srcIp() != null) {
+ node.put("srcIp", rule.srcIp().toString());
+ }
+ if (rule.dstIp() != null) {
+ node.put("dstIp", rule.dstIp().toString());
+ }
+ if (rule.ipProto() != 0) {
+ switch (rule.ipProto()) {
+ case IPv4.PROTOCOL_ICMP:
+ node.put("ipProto", "ICMP");
+ break;
+ case IPv4.PROTOCOL_TCP:
+ node.put("ipProto", "TCP");
+ break;
+ case IPv4.PROTOCOL_UDP:
+ node.put("ipProto", "UDP");
+ break;
+ default:
+ break;
+ }
+ }
+ if (rule.dstTpPort() != 0) {
+ node.put("dstTpPort", rule.dstTpPort());
+ }
+ node.put("action", rule.action().toString());
+ arrayNode.add(node);
+ }
+ root.set("aclRules", arrayNode);
+ return Response.ok(root.toString(), MediaType.APPLICATION_JSON_TYPE).build();
+ }
+
+ /**
+ * Add a new ACL rule.
+ *
+ * @param stream JSON data describing the rule
+ * @return 200 OK
+ */
+ @POST
+ @Consumes(MediaType.APPLICATION_JSON)
+ public Response addAclRule(InputStream stream) throws URISyntaxException {
+ AclRule newRule = jsonToRule(stream);
+ return get(AclService.class).addAclRule(newRule) ?
+ Response.created(new URI(newRule.id().toString())).build() :
+ Response.serverError().build();
+ }
+
+ /**
+ * Remove ACL rule.
+ *
+ * @param id ACL rule id (in hex string format)
+ * @return 200 OK
+ */
+ @DELETE
+ @Path("{id}")
+ public Response removeAclRule(@PathParam("id") String id) {
+ RuleId ruleId = new RuleId(Long.parseLong(id.substring(2), 16));
+ get(AclService.class).removeAclRule(ruleId);
+ return Response.ok().build();
+ }
+
+ /**
+ * Remove all ACL rules.
+ *
+ * @return 200 OK
+ */
+ @DELETE
+ public Response clearACL() {
+ get(AclService.class).clearAcl();
+ return Response.ok().build();
+ }
+
+ /**
+ * Turns a JSON string into an ACL rule instance.
+ */
+ private AclRule jsonToRule(InputStream stream) {
+ JsonNode node;
+ try {
+ node = mapper().readTree(stream);
+ } catch (IOException e) {
+ throw new IllegalArgumentException("Unable to parse ACL request", e);
+ }
+
+ AclRule.Builder rule = AclRule.builder();
+
+ String s = node.path("srcIp").asText(null);
+ if (s != null) {
+ rule.srcIp(Ip4Prefix.valueOf(s));
+ }
+
+ s = node.path("dstIp").asText(null);
+ if (s != null) {
+ rule.dstIp(Ip4Prefix.valueOf(s));
+ }
+
+ s = node.path("ipProto").asText(null);
+ if (s != null) {
+ if ("TCP".equalsIgnoreCase(s)) {
+ rule.ipProto(IPv4.PROTOCOL_TCP);
+ } else if ("UDP".equalsIgnoreCase(s)) {
+ rule.ipProto(IPv4.PROTOCOL_UDP);
+ } else if ("ICMP".equalsIgnoreCase(s)) {
+ rule.ipProto(IPv4.PROTOCOL_ICMP);
+ } else {
+ throw new IllegalArgumentException("ipProto must be assigned to TCP, UDP, or ICMP");
+ }
+ }
+
+ int port = node.path("dstTpPort").asInt(0);
+ if (port > 0) {
+ rule.dstTpPort((short) port);
+ }
+
+ s = node.path("action").asText(null);
+ if (s != null) {
+ if ("allow".equalsIgnoreCase(s)) {
+ rule.action(AclRule.Action.ALLOW);
+ } else if ("deny".equalsIgnoreCase(s)) {
+ rule.action(AclRule.Action.DENY);
+ } else {
+ throw new IllegalArgumentException("action must be ALLOW or DENY");
+ }
+ }
+
+ return rule.build();
+ }
+
+} \ No newline at end of file
diff --git a/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/RuleId.java b/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/RuleId.java
new file mode 100644
index 00000000..468dab5c
--- /dev/null
+++ b/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/RuleId.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ * Originally created by Pengfei Lu, Network and Cloud Computing Laboratory, Dalian University of Technology, China
+ * Advisers: Keqiu Li and Heng Qi
+ * This work is supported by the State Key Program of National Natural Science of China(Grant No. 61432002)
+ * and Prospective Research Project on Future Networks in Jiangsu Future Networks Innovation Institute.
+ *
+ * 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.acl;
+
+/**
+ * ACL rule identifier suitable as an external key.
+ * <p>This class is immutable.</p>
+ */
+public final class RuleId {
+ private final long value;
+
+ /**
+ * Creates an ACL rule identifier from the specified long value.
+ *
+ * @param value long value
+ * @return ACL rule identifier
+ */
+ public static RuleId valueOf(long value) {
+ return new RuleId(value);
+ }
+
+ /**
+ * Constructor for serializer.
+ */
+ RuleId() {
+ this.value = 0;
+ }
+
+ /**
+ * Constructs the ID corresponding to a given long value.
+ *
+ * @param value the underlying value of this ID
+ */
+ RuleId(long value) {
+ this.value = value;
+ }
+
+ /**
+ * Returns the backing value.
+ *
+ * @return the value
+ */
+ public long fingerprint() {
+ return value;
+ }
+
+ @Override
+ public int hashCode() {
+ return Long.hashCode(value);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof RuleId)) {
+ return false;
+ }
+ RuleId that = (RuleId) obj;
+ return this.value == that.value;
+ }
+
+ @Override
+ public String toString() {
+ return "0x" + Long.toHexString(value);
+ }
+}
diff --git a/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/impl/AclManager.java b/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/impl/AclManager.java
new file mode 100644
index 00000000..f5c0c204
--- /dev/null
+++ b/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/impl/AclManager.java
@@ -0,0 +1,338 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ * Originally created by Pengfei Lu, Network and Cloud Computing Laboratory, Dalian University of Technology, China
+ * Advisers: Keqiu Li, Heng Qi and Haisheng Yu
+ * This work is supported by the State Key Program of National Natural Science of China(Grant No. 61432002)
+ * and Prospective Research Project on Future Networks in Jiangsu Future Networks Innovation Institute.
+ *
+ * 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.acl.impl;
+
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.IPv4;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.Ip4Prefix;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.TpPort;
+import org.onosproject.acl.AclRule;
+import org.onosproject.acl.AclService;
+import org.onosproject.acl.AclStore;
+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.onosproject.acl.RuleId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.core.IdGenerator;
+import org.onosproject.mastership.MastershipService;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Host;
+import org.onosproject.net.MastershipRole;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.DefaultFlowEntry;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowEntry;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleService;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.instructions.Instructions;
+import org.onosproject.net.host.HostEvent;
+import org.onosproject.net.host.HostListener;
+import org.onosproject.net.host.HostService;
+import org.slf4j.Logger;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Implementation of the ACL service.
+ */
+@Component(immediate = true)
+@Service
+public class AclManager implements AclService {
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CoreService coreService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected FlowRuleService flowRuleService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected HostService hostService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected MastershipService mastershipService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected AclStore aclStore;
+
+ private final Logger log = getLogger(getClass());
+ private ApplicationId appId;
+ private final HostListener hostListener = new InternalHostListener();
+ private IdGenerator idGenerator;
+
+ /**
+ * Checks if the given IP address is in the given CIDR address.
+ */
+ private boolean checkIpInCIDR(Ip4Address ip, Ip4Prefix cidr) {
+ int offset = 32 - cidr.prefixLength();
+ int cidrPrefix = cidr.address().toInt();
+ int ipIntValue = ip.toInt();
+ cidrPrefix = cidrPrefix >> offset;
+ ipIntValue = ipIntValue >> offset;
+ cidrPrefix = cidrPrefix << offset;
+ ipIntValue = ipIntValue << offset;
+
+ return (cidrPrefix == ipIntValue);
+ }
+
+ private class InternalHostListener implements HostListener {
+
+ /**
+ * Generate new ACL flow rules for new host following the given ACL rule.
+ */
+ private void processHostAddedEvent(HostEvent event, AclRule rule) {
+ DeviceId deviceId = event.subject().location().deviceId();
+ for (IpAddress address : event.subject().ipAddresses()) {
+ if ((rule.srcIp() != null) ?
+ (checkIpInCIDR(address.getIp4Address(), rule.srcIp())) :
+ (checkIpInCIDR(address.getIp4Address(), rule.dstIp()))) {
+ if (!aclStore.checkIfRuleWorksInDevice(rule.id(), deviceId)) {
+ List<RuleId> allowingRuleList = aclStore
+ .getAllowingRuleByDenyingRule(rule.id());
+ if (allowingRuleList != null) {
+ for (RuleId allowingRuleId : allowingRuleList) {
+ generateACLFlow(aclStore.getAclRule(allowingRuleId), deviceId);
+ }
+ }
+ generateACLFlow(rule, deviceId);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void event(HostEvent event) {
+ // if a new host appears and an existing rule denies
+ // its traffic, a new ACL flow rule is generated.
+ if (event.type() == HostEvent.Type.HOST_ADDED) {
+ DeviceId deviceId = event.subject().location().deviceId();
+ if (mastershipService.getLocalRole(deviceId) == MastershipRole.MASTER) {
+ for (AclRule rule : aclStore.getAclRules()) {
+ if (rule.action() != AclRule.Action.ALLOW) {
+ processHostAddedEvent(event, rule);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ @Activate
+ public void activate() {
+ appId = coreService.registerApplication("org.onos.acl");
+ hostService.addListener(hostListener);
+ idGenerator = coreService.getIdGenerator("acl-ids");
+ AclRule.bindIdGenerator(idGenerator);
+ log.info("Started");
+ }
+
+ @Deactivate
+ public void deactivate() {
+ hostService.removeListener(hostListener);
+ flowRuleService.removeFlowRulesById(appId);
+ aclStore.clearAcl();
+ log.info("Stopped");
+ }
+
+ @Override
+ public List<AclRule> getAclRules() {
+ return aclStore.getAclRules();
+ }
+
+ /**
+ * Checks if the new ACL rule matches an existing rule.
+ * If existing allowing rules matches the new denying rule, store the mappings.
+ *
+ * @return true if the new ACL rule matches an existing rule, false otherwise
+ */
+ private boolean matchCheck(AclRule newRule) {
+ for (AclRule existingRule : aclStore.getAclRules()) {
+ if (newRule.checkMatch(existingRule)) {
+ return true;
+ }
+
+ if (existingRule.action() == AclRule.Action.ALLOW
+ && newRule.action() == AclRule.Action.DENY) {
+ if (existingRule.checkMatch(newRule)) {
+ aclStore.addDenyToAllowMapping(newRule.id(), existingRule.id());
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean addAclRule(AclRule rule) {
+ if (matchCheck(rule)) {
+ return false;
+ }
+ aclStore.addAclRule(rule);
+ log.info("ACL rule(id:{}) is added.", rule.id());
+ if (rule.action() != AclRule.Action.ALLOW) {
+ enforceRuleAdding(rule);
+ }
+ return true;
+ }
+
+ /**
+ * Gets a set containing all devices connecting with the hosts
+ * whose IP address is in the given CIDR IP address.
+ */
+ private Set<DeviceId> getDeviceIdSet(Ip4Prefix cidrAddr) {
+ Set<DeviceId> deviceIdSet = new HashSet<>();
+ final Iterable<Host> hosts = hostService.getHosts();
+
+ if (cidrAddr.prefixLength() != 32) {
+ for (Host h : hosts) {
+ for (IpAddress a : h.ipAddresses()) {
+ if (checkIpInCIDR(a.getIp4Address(), cidrAddr)) {
+ deviceIdSet.add(h.location().deviceId());
+ }
+ }
+ }
+ } else {
+ for (Host h : hosts) {
+ for (IpAddress a : h.ipAddresses()) {
+ if (checkIpInCIDR(a.getIp4Address(), cidrAddr)) {
+ deviceIdSet.add(h.location().deviceId());
+ return deviceIdSet;
+ }
+ }
+ }
+ }
+ return deviceIdSet;
+ }
+
+ /**
+ * Enforces denying ACL rule by ACL flow rules.
+ */
+ private void enforceRuleAdding(AclRule rule) {
+ Set<DeviceId> dpidSet;
+ if (rule.srcIp() != null) {
+ dpidSet = getDeviceIdSet(rule.srcIp());
+ } else {
+ dpidSet = getDeviceIdSet(rule.dstIp());
+ }
+
+ for (DeviceId deviceId : dpidSet) {
+ List<RuleId> allowingRuleList = aclStore.getAllowingRuleByDenyingRule(rule.id());
+ if (allowingRuleList != null) {
+ for (RuleId allowingRuleId : allowingRuleList) {
+ generateACLFlow(aclStore.getAclRule(allowingRuleId), deviceId);
+ }
+ }
+ generateACLFlow(rule, deviceId);
+ }
+ }
+
+ /**
+ * Generates ACL flow rule according to ACL rule
+ * and install it into related device.
+ */
+ private void generateACLFlow(AclRule rule, DeviceId deviceId) {
+ if (rule == null || aclStore.checkIfRuleWorksInDevice(rule.id(), deviceId)) {
+ return;
+ }
+
+ TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
+ TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+ FlowEntry.Builder flowEntry = DefaultFlowEntry.builder();
+
+ selectorBuilder.matchEthType(Ethernet.TYPE_IPV4);
+ if (rule.srcIp() != null) {
+ selectorBuilder.matchIPSrc(rule.srcIp());
+ if (rule.dstIp() != null) {
+ selectorBuilder.matchIPDst(rule.dstIp());
+ }
+ } else {
+ selectorBuilder.matchIPDst(rule.dstIp());
+ }
+ if (rule.ipProto() != 0) {
+ selectorBuilder.matchIPProtocol(Integer.valueOf(rule.ipProto()).byteValue());
+ }
+ if (rule.dstTpPort() != 0) {
+ switch (rule.ipProto()) {
+ case IPv4.PROTOCOL_TCP:
+ selectorBuilder.matchTcpDst(TpPort.tpPort(rule.dstTpPort()));
+ break;
+ case IPv4.PROTOCOL_UDP:
+ selectorBuilder.matchUdpDst(TpPort.tpPort(rule.dstTpPort()));
+ break;
+ default:
+ break;
+ }
+ }
+ if (rule.action() == AclRule.Action.ALLOW) {
+ treatment.add(Instructions.createOutput(PortNumber.CONTROLLER));
+ }
+ flowEntry.forDevice(deviceId);
+ flowEntry.withPriority(aclStore.getPriorityByDevice(deviceId));
+ flowEntry.withSelector(selectorBuilder.build());
+ flowEntry.withTreatment(treatment.build());
+ flowEntry.fromApp(appId);
+ flowEntry.makePermanent();
+ // install flow rule
+ flowRuleService.applyFlowRules(flowEntry.build());
+ log.debug("ACL flow rule {} is installed in {}.", flowEntry.build(), deviceId);
+ aclStore.addRuleToFlowMapping(rule.id(), flowEntry.build());
+ aclStore.addRuleToDeviceMapping(rule.id(), deviceId);
+ }
+
+ @Override
+ public void removeAclRule(RuleId ruleId) {
+ aclStore.removeAclRule(ruleId);
+ log.info("ACL rule(id:{}) is removed.", ruleId);
+ enforceRuleRemoving(ruleId);
+ }
+
+ /**
+ * Enforces removing an existing ACL rule.
+ */
+ private void enforceRuleRemoving(RuleId ruleId) {
+ Set<FlowRule> flowSet = aclStore.getFlowByRule(ruleId);
+ if (flowSet != null) {
+ for (FlowRule flowRule : flowSet) {
+ flowRuleService.removeFlowRules(flowRule);
+ log.debug("ACL flow rule {} is removed from {}.", flowRule.toString(), flowRule.deviceId().toString());
+ }
+ }
+ aclStore.removeRuleToFlowMapping(ruleId);
+ aclStore.removeRuleToDeviceMapping(ruleId);
+ aclStore.removeDenyToAllowMapping(ruleId);
+ }
+
+ @Override
+ public void clearAcl() {
+ aclStore.clearAcl();
+ flowRuleService.removeFlowRulesById(appId);
+ log.info("ACL is cleared.");
+ }
+
+}
diff --git a/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/impl/DistributedAclStore.java b/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/impl/DistributedAclStore.java
new file mode 100644
index 00000000..a5fcfcc7
--- /dev/null
+++ b/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/impl/DistributedAclStore.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ * Originally created by Pengfei Lu, Network and Cloud Computing Laboratory, Dalian University of Technology, China
+ * Advisers: Keqiu Li, Heng Qi and Haisheng Yu
+ * This work is supported by the State Key Program of National Natural Science of China(Grant No. 61432002)
+ * and Prospective Research Project on Future Networks in Jiangsu Future Networks Innovation Institute.
+ *
+ * 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.acl.impl;
+
+import com.google.common.collect.Collections2;
+import org.onosproject.acl.AclRule;
+import org.onosproject.acl.AclStore;
+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.util.KryoNamespace;
+import org.onosproject.acl.RuleId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.store.AbstractStore;
+import org.onosproject.store.serializers.KryoNamespaces;
+import org.onosproject.store.service.ConsistentMap;
+import org.onosproject.store.service.Serializer;
+import org.onosproject.store.service.StorageService;
+import org.onosproject.store.service.Versioned;
+import org.slf4j.Logger;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Implementation of the ACL store service.
+ */
+@Component(immediate = true)
+@Service
+public class DistributedAclStore extends AbstractStore implements AclStore {
+
+ private final Logger log = getLogger(getClass());
+ private final int defaultFlowMaxPriority = 30000;
+
+ private ConsistentMap<RuleId, AclRule> ruleSet;
+ private ConsistentMap<DeviceId, Integer> deviceToPriority;
+ private ConsistentMap<RuleId, Set<DeviceId>> ruleToDevice;
+ private ConsistentMap<RuleId, Set<FlowRule>> ruleToFlow;
+ private ConsistentMap<RuleId, List<RuleId>> denyRuleToAllowRule;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected StorageService storageService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CoreService coreService;
+
+ @Activate
+ public void activate() {
+ ApplicationId appId = coreService.getAppId("org.onosproject.acl");
+
+ KryoNamespace.Builder serializer = KryoNamespace.newBuilder()
+ .register(KryoNamespaces.API)
+ .register(AclRule.class)
+ .register(AclRule.Action.class)
+ .register(RuleId.class);
+
+ ruleSet = storageService.<RuleId, AclRule>consistentMapBuilder()
+ .withSerializer(Serializer.using(serializer.build()))
+ .withName("acl-rule-set")
+ .withApplicationId(appId)
+ .withPurgeOnUninstall()
+ .build();
+
+ deviceToPriority = storageService.<DeviceId, Integer>consistentMapBuilder()
+ .withSerializer(Serializer.using(serializer.build()))
+ .withName("device-to-priority")
+ .withApplicationId(appId)
+ .withPurgeOnUninstall()
+ .build();
+
+ ruleToFlow = storageService.<RuleId, Set<FlowRule>>consistentMapBuilder()
+ .withSerializer(Serializer.using(serializer.build()))
+ .withName("rule-to-flow")
+ .withApplicationId(appId)
+ .withPurgeOnUninstall()
+ .build();
+
+ denyRuleToAllowRule = storageService.<RuleId, List<RuleId>>consistentMapBuilder()
+ .withSerializer(Serializer.using(serializer.build()))
+ .withName("deny-to-allow")
+ .withApplicationId(appId)
+ .withPurgeOnUninstall()
+ .build();
+
+ ruleToDevice = storageService.<RuleId, Set<DeviceId>>consistentMapBuilder()
+ .withSerializer(Serializer.using(serializer.build()))
+ .withName("rule-to-device")
+ .withApplicationId(appId)
+ .withPurgeOnUninstall()
+ .build();
+
+ log.info("Started");
+ }
+
+ @Deactivate
+ public void deactive() {
+ log.info("Stopped");
+ }
+
+ @Override
+ public List<AclRule> getAclRules() {
+ List<AclRule> aclRules = new ArrayList<>();
+ aclRules.addAll(Collections2.transform(ruleSet.values(), Versioned::value));
+ return aclRules;
+ }
+
+ @Override
+ public void addAclRule(AclRule rule) {
+ ruleSet.putIfAbsent(rule.id(), rule);
+ }
+
+ @Override
+ public AclRule getAclRule(RuleId ruleId) {
+ Versioned<AclRule> rule = ruleSet.get(ruleId);
+ if (rule != null) {
+ return rule.value();
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public void removeAclRule(RuleId ruleId) {
+ ruleSet.remove(ruleId);
+ }
+
+ @Override
+ public void clearAcl() {
+ ruleSet.clear();
+ deviceToPriority.clear();
+ ruleToFlow.clear();
+ denyRuleToAllowRule.clear();
+ ruleToDevice.clear();
+ }
+
+ @Override
+ public int getPriorityByDevice(DeviceId deviceId) {
+ return deviceToPriority.compute(deviceId,
+ (id, priority) -> (priority == null) ? defaultFlowMaxPriority : (priority - 1))
+ .value();
+ }
+
+ @Override
+ public Set<FlowRule> getFlowByRule(RuleId ruleId) {
+ Versioned<Set<FlowRule>> flowRuleSet = ruleToFlow.get(ruleId);
+ if (flowRuleSet != null) {
+ return flowRuleSet.value();
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public void addRuleToFlowMapping(RuleId ruleId, FlowRule flowRule) {
+ ruleToFlow.computeIf(ruleId,
+ flowRuleSet -> (flowRuleSet == null || !flowRuleSet.contains(flowRule)),
+ (id, flowRuleSet) -> {
+ Set<FlowRule> newSet = new HashSet<>();
+ if (flowRuleSet != null) {
+ newSet.addAll(flowRuleSet);
+ }
+ newSet.add(flowRule);
+ return newSet;
+ });
+ }
+
+ @Override
+ public void removeRuleToFlowMapping(RuleId ruleId) {
+ ruleToFlow.remove(ruleId);
+ }
+
+ @Override
+ public List<RuleId> getAllowingRuleByDenyingRule(RuleId denyingRuleId) {
+ Versioned<List<RuleId>> allowRuleIdSet = denyRuleToAllowRule.get(denyingRuleId);
+ if (allowRuleIdSet != null) {
+ return allowRuleIdSet.value();
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public void addDenyToAllowMapping(RuleId denyingRuleId, RuleId allowingRuleId) {
+ denyRuleToAllowRule.computeIf(denyingRuleId,
+ ruleIdList -> (ruleIdList == null || !ruleIdList.contains(allowingRuleId)),
+ (id, ruleIdList) -> {
+ ArrayList<RuleId> newList = new ArrayList<>();
+ if (ruleIdList != null) {
+ newList.addAll(ruleIdList);
+ }
+ newList.add(allowingRuleId);
+ return newList;
+ });
+ }
+
+ @Override
+ public void removeDenyToAllowMapping(RuleId denyingRuleId) {
+ denyRuleToAllowRule.remove(denyingRuleId);
+ }
+
+ @Override
+ public boolean checkIfRuleWorksInDevice(RuleId ruleId, DeviceId deviceId) {
+ return ruleToDevice.containsKey(ruleId) && ruleToDevice.get(ruleId).value().contains(deviceId);
+ }
+
+ @Override
+ public void addRuleToDeviceMapping(RuleId ruleId, DeviceId deviceId) {
+ ruleToDevice.computeIf(ruleId,
+ deviceIdSet -> (deviceIdSet == null || !deviceIdSet.contains(deviceId)),
+ (id, deviceIdSet) -> {
+ Set<DeviceId> newSet = new HashSet<>();
+ if (deviceIdSet != null) {
+ newSet.addAll(deviceIdSet);
+ }
+ newSet.add(deviceId);
+ return newSet;
+ });
+ }
+
+ @Override
+ public void removeRuleToDeviceMapping(RuleId ruleId) {
+ ruleToDevice.remove(ruleId);
+ }
+
+}
diff --git a/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/impl/package-info.java b/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/impl/package-info.java
new file mode 100644
index 00000000..9da9b3b7
--- /dev/null
+++ b/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/impl/package-info.java
@@ -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.
+ */
+
+/**
+ * ACL application implementation.
+ */
+package org.onosproject.acl.impl;
diff --git a/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/package-info.java b/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/package-info.java
new file mode 100644
index 00000000..67f755c6
--- /dev/null
+++ b/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/package-info.java
@@ -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.
+ */
+
+/**
+ * ACL application.
+ */
+package org.onosproject.acl;
diff --git a/framework/src/onos/apps/acl/src/main/webapp/WEB-INF/web.xml b/framework/src/onos/apps/acl/src/main/webapp/WEB-INF/web.xml
index 2c2d5cf3..fc188b7f 100644
--- a/framework/src/onos/apps/acl/src/main/webapp/WEB-INF/web.xml
+++ b/framework/src/onos/apps/acl/src/main/webapp/WEB-INF/web.xml
@@ -33,7 +33,7 @@
</init-param>
<init-param>
<param-name>com.sun.jersey.config.property.classnames</param-name>
- <param-value>org.onos.acl.AclWebResource</param-value>
+ <param-value>org.onosproject.acl.AclWebResource</param-value>
</init-param>
<load-on-startup>10</load-on-startup>
</servlet>
diff --git a/framework/src/onos/apps/acl/src/test/java/org/onosproject/acl/AclWebResourceTest.java b/framework/src/onos/apps/acl/src/test/java/org/onosproject/acl/AclWebResourceTest.java
new file mode 100644
index 00000000..c554db6e
--- /dev/null
+++ b/framework/src/onos/apps/acl/src/test/java/org/onosproject/acl/AclWebResourceTest.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ * Originally created by Pengfei Lu, Network and Cloud Computing Laboratory, Dalian University of Technology, China
+ * Advisers: Keqiu Li and Heng Qi
+ * This work is supported by the State Key Program of National Natural Science of China(Grant No. 61432002)
+ * and Prospective Research Project on Future Networks in Jiangsu Future Networks Innovation Institute.
+ *
+ * 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.acl;
+
+import com.sun.jersey.api.client.WebResource;
+import com.sun.jersey.test.framework.AppDescriptor;
+import com.sun.jersey.test.framework.WebAppDescriptor;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.onlab.osgi.ServiceDirectory;
+import org.onlab.osgi.TestServiceDirectory;
+import org.onlab.rest.BaseResource;
+import org.onosproject.core.IdGenerator;
+import org.onosproject.rest.ResourceTest;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicLong;
+
+import static org.easymock.EasyMock.*;
+import static org.hamcrest.Matchers.containsString;
+import static org.junit.Assert.assertThat;
+
+/**
+ * Test class for ACL application REST resource.
+ */
+public class AclWebResourceTest extends ResourceTest {
+
+ final AclService mockAclService = createMock(AclService.class);
+ final AclStore mockAclStore = createMock(AclStore.class);
+ final List<AclRule> rules = new ArrayList<>();
+
+ @Before
+ public void setUp() {
+ expect(mockAclService.getAclRules()).andReturn(rules).anyTimes();
+ ServiceDirectory testDirectory = new TestServiceDirectory().add(AclService.class, mockAclService)
+ .add(AclStore.class, mockAclStore);
+ BaseResource.setServiceDirectory(testDirectory);
+
+ IdGenerator idGenerator = new MockIdGenerator();
+ AclRule.bindIdGenerator(idGenerator);
+ }
+
+ @After
+ public void tearDown() {
+ verify(mockAclService);
+ }
+
+ /**
+ * Mock id generator for testing.
+ */
+ private class MockIdGenerator implements IdGenerator {
+ private AtomicLong nextId = new AtomicLong(0);
+
+ @Override
+ public long getNewId() {
+ return nextId.getAndIncrement();
+ }
+ }
+
+ @Override
+ public AppDescriptor configure() {
+ return new WebAppDescriptor.Builder("org.onosproject.acl").build();
+ }
+
+ @Test
+ @Ignore("FIXME: This needs to get reworked")
+ public void addRule() throws IOException {
+ WebResource.Builder rs = resource().path("rules").header("Content-type", "application/json");
+ String response;
+ String json;
+
+ replay(mockAclService);
+
+ // input a invalid JSON string that contains neither nw_src and nw_dst
+ json = "{\"ipProto\":\"TCP\",\"dstTpPort\":\"80\"}";
+ response = rs.post(String.class, json);
+ assertThat(response, containsString("Failed! Either srcIp or dstIp must be assigned."));
+
+ // input a invalid JSON string that doesn't contain CIDR mask bits
+ json = "{\"ipProto\":\"TCP\",\"srcIp\":\"10.0.0.1\",\"dstTpPort\":\"80\",\"action\":\"DENY\"}";
+ response = rs.post(String.class, json);
+ assertThat(response, containsString("Malformed IPv4 prefix string: 10.0.0.1. " +
+ "Address must take form \"x.x.x.x/y\""));
+
+ // input a invalid JSON string that contains a invalid IP address
+ json = "{\"ipProto\":\"TCP\",\"srcIp\":\"10.0.0.256/32\",\"dstTpPort\":\"80\",\"action\":\"DENY\"}";
+ response = rs.post(String.class, json);
+ assertThat(response, containsString("Invalid IP address string: 10.0.0.256"));
+
+ // input a invalid JSON string that contains a invalid IP address
+ json = "{\"ipProto\":\"TCP\",\"srcIp\":\"10.0.01/32\",\"dstTpPort\":\"80\",\"action\":\"DENY\"}";
+ response = rs.post(String.class, json);
+ assertThat(response, containsString("Invalid IP address string: 10.0.01"));
+
+ // input a invalid JSON string that contains a invalid CIDR mask bits
+ json = "{\"ipProto\":\"TCP\",\"srcIp\":\"10.0.0.1/a\",\"dstTpPort\":\"80\",\"action\":\"DENY\"}";
+ response = rs.post(String.class, json);
+ assertThat(response, containsString("Failed! For input string: \"a\""));
+
+ // input a invalid JSON string that contains a invalid CIDR mask bits
+ json = "{\"ipProto\":\"TCP\",\"srcIp\":\"10.0.0.1/33\",\"dstTpPort\":\"80\",\"action\":\"DENY\"}";
+ response = rs.post(String.class, json);
+ assertThat(response, containsString("Invalid prefix length 33. The value must be in the interval [0, 32]"));
+
+ // input a invalid JSON string that contains a invalid ipProto value
+ json = "{\"ipProto\":\"ARP\",\"srcIp\":\"10.0.0.1/32\",\"dstTpPort\":\"80\",\"action\":\"DENY\"}";
+ response = rs.post(String.class, json);
+ assertThat(response, containsString("ipProto must be assigned to TCP, UDP, or ICMP."));
+
+ // input a invalid JSON string that contains a invalid dstTpPort value
+ json = "{\"ipProto\":\"TCP\",\"srcIp\":\"10.0.0.1/32\",\"dstTpPort\":\"a\",\"action\":\"DENY\"}";
+ response = rs.post(String.class, json);
+ assertThat(response, containsString("dstTpPort must be assigned to a numerical value."));
+
+ // input a invalid JSON string that contains a invalid action value
+ json = "{\"ipProto\":\"TCP\",\"srcIp\":\"10.0.0.1/32\",\"dstTpPort\":\"80\",\"action\":\"PERMIT\"}";
+ response = rs.post(String.class, json);
+ assertThat(response, containsString("action must be assigned to ALLOW or DENY."));
+ }
+}
diff --git a/framework/src/onos/apps/bgprouter/pom.xml b/framework/src/onos/apps/bgprouter/pom.xml
index decdf5c2..6503ee79 100644
--- a/framework/src/onos/apps/bgprouter/pom.xml
+++ b/framework/src/onos/apps/bgprouter/pom.xml
@@ -24,7 +24,6 @@
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
-
<artifactId>onos-app-bgprouter</artifactId>
<packaging>bundle</packaging>
diff --git a/framework/src/onos/apps/bgprouter/src/main/java/org/onosproject/bgprouter/IcmpHandler.java b/framework/src/onos/apps/bgprouter/src/main/java/org/onosproject/bgprouter/IcmpHandler.java
index 88265350..6130a2e2 100644
--- a/framework/src/onos/apps/bgprouter/src/main/java/org/onosproject/bgprouter/IcmpHandler.java
+++ b/framework/src/onos/apps/bgprouter/src/main/java/org/onosproject/bgprouter/IcmpHandler.java
@@ -101,6 +101,7 @@ public class IcmpHandler {
icmpReplyIpv4.setChecksum((short) 0);
ICMP icmpReply = new ICMP();
+ icmpReply.setPayload(((ICMP) icmpRequestIpv4.getPayload()).getPayload());
icmpReply.setIcmpType(ICMP.TYPE_ECHO_REPLY);
icmpReply.setIcmpCode(ICMP.SUBTYPE_ECHO_REPLY);
icmpReply.setChecksum((short) 0);
diff --git a/framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/CordFabricManager.java b/framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/CordFabricManager.java
index 1523e9c2..fa916865 100644
--- a/framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/CordFabricManager.java
+++ b/framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/CordFabricManager.java
@@ -86,7 +86,7 @@ public class CordFabricManager implements FabricService {
private short radiusPort = 1812;
- private short ofPort = 6633;
+ private short ofPort = 6653;
private DeviceId fabricDeviceId = DeviceId.deviceId("of:5e3e486e73000187");
diff --git a/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtn.java b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtn.java
index 072254de..cb8acab2 100644
--- a/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtn.java
+++ b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtn.java
@@ -21,24 +21,11 @@ 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.onlab.packet.TpPort;
import org.onlab.util.KryoNamespace;
-import org.onosproject.cluster.ClusterService;
-import org.onosproject.cluster.LeadershipEvent;
-import org.onosproject.cluster.LeadershipEventListener;
-import org.onosproject.cluster.LeadershipService;
-import org.onosproject.cluster.NodeId;
-import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
-import org.onosproject.mastership.MastershipService;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Host;
-import org.onosproject.net.config.ConfigFactory;
-import org.onosproject.net.config.NetworkConfigRegistry;
-import org.onosproject.net.config.NetworkConfigService;
-import org.onosproject.net.config.basics.SubjectFactories;
import org.onosproject.net.device.DeviceEvent;
import org.onosproject.net.device.DeviceListener;
import org.onosproject.net.device.DeviceService;
@@ -57,11 +44,15 @@ import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.cordvtn.OvsdbNode.State;
import static org.onosproject.cordvtn.OvsdbNode.State.INIT;
+import static org.onosproject.cordvtn.OvsdbNode.State.DISCONNECT;
+import static org.onosproject.net.Device.Type.SWITCH;
import static org.slf4j.LoggerFactory.getLogger;
/**
- * CORD VTN Application that provisions overlay virtual tenant networks.
+ * Provides initial setup or cleanup for provisioning virtual tenant networks
+ * on ovsdb, integration bridge and vm when they are added or deleted.
*/
@Component(immediate = true)
@Service
@@ -69,6 +60,11 @@ public class CordVtn implements CordVtnService {
protected final Logger log = getLogger(getClass());
+ private static final int NUM_THREADS = 1;
+ private static final KryoNamespace.Builder NODE_SERIALIZER = KryoNamespace.newBuilder()
+ .register(KryoNamespaces.API)
+ .register(OvsdbNode.class);
+
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CoreService coreService;
@@ -79,112 +75,81 @@ public class CordVtn implements CordVtnService {
protected LogicalClockService clockService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected ClusterService clusterService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected LeadershipService leadershipService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected NetworkConfigService configService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected NetworkConfigRegistry configRegistry;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DeviceService deviceService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected HostService hostService;
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected MastershipService mastershipService;
-
- private static final int DEFAULT_NUM_THREADS = 1;
- private static final KryoNamespace.Builder NODE_SERIALIZER = KryoNamespace.newBuilder()
- .register(KryoNamespaces.API)
- .register(OvsdbNode.class);
+ private final ExecutorService eventExecutor = Executors
+ .newFixedThreadPool(NUM_THREADS, groupedThreads("onos/cordvtn", "event-handler"));
- private final ExecutorService eventExecutor = Executors.newFixedThreadPool(
- DEFAULT_NUM_THREADS, groupedThreads("onos/cordvtn", "event-handler"));
-
- private final LeadershipEventListener leadershipListener = new InternalLeadershipListener();
private final DeviceListener deviceListener = new InternalDeviceListener();
private final HostListener hostListener = new InternalHostListener();
- private final NodeHandler nodeHandler = new NodeHandler();
+
+ private final OvsdbHandler ovsdbHandler = new OvsdbHandler();
private final BridgeHandler bridgeHandler = new BridgeHandler();
- private final VirtualMachineHandler vmHandler = new VirtualMachineHandler();
-
- private final ConfigFactory configFactory =
- new ConfigFactory(SubjectFactories.APP_SUBJECT_FACTORY, CordVtnConfig.class, "cordvtn") {
- @Override
- public CordVtnConfig createConfig() {
- return new CordVtnConfig();
- }
- };
-
- private ApplicationId appId;
- private NodeId local;
+ private final VmHandler vmHandler = new VmHandler();
+
private EventuallyConsistentMap<DeviceId, OvsdbNode> nodeStore;
- private NodeConnectionManager nodeConnectionManager;
@Activate
protected void activate() {
- appId = coreService.registerApplication("org.onosproject.cordvtn");
-
- local = clusterService.getLocalNode().id();
+ coreService.registerApplication("org.onosproject.cordvtn");
nodeStore = storageService.<DeviceId, OvsdbNode>eventuallyConsistentMapBuilder()
.withName("cordvtn-nodestore")
.withSerializer(NODE_SERIALIZER)
.withTimestampProvider((k, v) -> clockService.getTimestamp())
.build();
- configRegistry.registerConfigFactory(configFactory);
deviceService.addListener(deviceListener);
hostService.addListener(hostListener);
- leadershipService.addListener(leadershipListener);
- leadershipService.runForLeadership(appId.name());
- nodeConnectionManager = new NodeConnectionManager(appId, local, nodeStore,
- mastershipService, leadershipService);
- nodeConnectionManager.start();
+
log.info("Started");
}
@Deactivate
protected void deactivate() {
- nodeConnectionManager.stop();
- leadershipService.removeListener(leadershipListener);
- leadershipService.withdraw(appId.name());
deviceService.removeListener(deviceListener);
hostService.removeListener(hostListener);
+
eventExecutor.shutdown();
nodeStore.destroy();
- configRegistry.unregisterConfigFactory(configFactory);
+
log.info("Stopped");
}
@Override
- public void addNode(String hostname, IpAddress ip, TpPort port) {
- DefaultOvsdbNode node = new DefaultOvsdbNode(hostname, ip, port, DeviceId.NONE, INIT);
-
- if (nodeStore.containsKey(node.deviceId())) {
- log.warn("Node {} with ovsdb-server {}:{} already exists", hostname, ip, port);
+ public void addNode(OvsdbNode ovsdbNode) {
+ if (nodeStore.containsKey(ovsdbNode.deviceId())) {
+ log.warn("Node {} already exists", ovsdbNode.host());
return;
}
- nodeStore.put(node.deviceId(), node);
- log.info("New node {} with ovsdb-server {}:{} has been added", hostname, ip, port);
+ nodeStore.put(ovsdbNode.deviceId(), ovsdbNode);
+ if (ovsdbNode.state() != INIT) {
+ updateNode(ovsdbNode, INIT);
+ }
}
@Override
- public void deleteNode(IpAddress ip, TpPort port) {
- DeviceId deviceId = DeviceId.deviceId("ovsdb:" + ip + ":" + port);
- OvsdbNode node = nodeStore.get(deviceId);
+ public void deleteNode(OvsdbNode ovsdbNode) {
+ if (!nodeStore.containsKey(ovsdbNode.deviceId())) {
+ log.warn("Node {} does not exist", ovsdbNode.host());
+ return;
+ }
+ updateNode(ovsdbNode, DISCONNECT);
+ }
- if (node == null) {
- log.warn("Node with ovsdb-server on {}:{} does not exist", ip, port);
+ @Override
+ public void updateNode(OvsdbNode ovsdbNode, State state) {
+ if (!nodeStore.containsKey(ovsdbNode.deviceId())) {
+ log.warn("Node {} does not exist", ovsdbNode.host());
return;
}
- nodeConnectionManager.disconnectNode(node);
- nodeStore.remove(node.deviceId());
+ DefaultOvsdbNode updatedNode = new DefaultOvsdbNode(ovsdbNode.host(),
+ ovsdbNode.ip(),
+ ovsdbNode.port(),
+ state);
+ nodeStore.put(ovsdbNode.deviceId(), updatedNode);
}
@Override
@@ -193,58 +158,33 @@ public class CordVtn implements CordVtnService {
}
@Override
+ public OvsdbNode getNode(DeviceId deviceId) {
+ return nodeStore.get(deviceId);
+ }
+
+ @Override
public List<OvsdbNode> getNodes() {
return nodeStore.values()
.stream()
.collect(Collectors.toList());
}
- private void initialSetup() {
- // Read ovsdb nodes from network config
- CordVtnConfig config = configService.getConfig(appId, CordVtnConfig.class);
- if (config == null) {
- log.warn("No configuration found");
- return;
- }
- config.ovsdbNodes().forEach(
- node -> addNode(node.hostname(), node.ip(), node.port()));
- }
-
- private synchronized void processLeadershipChange(NodeId leader) {
- // Only the leader performs the initial setup
- if (leader == null || !leader.equals(local)) {
- return;
- }
- initialSetup();
- }
-
- private class InternalLeadershipListener implements LeadershipEventListener {
-
- @Override
- public void event(LeadershipEvent event) {
- if (event.subject().topic().equals(appId.name())) {
- processLeadershipChange(event.subject().leader());
- }
- }
- }
-
private class InternalDeviceListener implements DeviceListener {
@Override
public void event(DeviceEvent event) {
Device device = event.subject();
- ConnectionHandler handler =
- (device.type() == Device.Type.CONTROLLER ? nodeHandler : bridgeHandler);
+ ConnectionHandler handler = (device.type() == SWITCH ? bridgeHandler : ovsdbHandler);
switch (event.type()) {
- case DEVICE_ADDED:
- eventExecutor.submit(() -> handler.connected(device));
- break;
- case DEVICE_AVAILABILITY_CHANGED:
- eventExecutor.submit(() -> handler.disconnected(device));
- break;
- default:
- break;
+ case DEVICE_ADDED:
+ eventExecutor.submit(() -> handler.connected(device));
+ break;
+ case DEVICE_AVAILABILITY_CHANGED:
+ eventExecutor.submit(() -> handler.disconnected(device));
+ break;
+ default:
+ break;
}
}
}
@@ -268,7 +208,7 @@ public class CordVtn implements CordVtnService {
}
}
- private class NodeHandler implements ConnectionHandler<Device> {
+ private class OvsdbHandler implements ConnectionHandler<Device> {
@Override
public void connected(Device device) {
@@ -296,7 +236,7 @@ public class CordVtn implements CordVtnService {
}
}
- private class VirtualMachineHandler implements ConnectionHandler<Host> {
+ private class VmHandler implements ConnectionHandler<Host> {
@Override
public void connected(Host host) {
diff --git a/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnConfig.java b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnConfig.java
index c2c37aba..fdaf752a 100644
--- a/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnConfig.java
+++ b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnConfig.java
@@ -27,12 +27,12 @@ import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
/**
- * Configuration object for CORD VTN service.
+ * Configuration object for CordVtn service.
*/
public class CordVtnConfig extends Config<ApplicationId> {
public static final String OVSDB_NODES = "ovsdbNodes";
- public static final String HOSTNAME = "hostname";
+ public static final String HOST = "host";
public static final String IP = "ip";
public static final String PORT = "port";
@@ -49,7 +49,7 @@ public class CordVtnConfig extends Config<ApplicationId> {
return null;
}
nodes.forEach(jsonNode -> ovsdbNodes.add(new OvsdbNodeConfig(
- jsonNode.path(HOSTNAME).asText(),
+ jsonNode.path(HOST).asText(),
IpAddress.valueOf(jsonNode.path(IP).asText()),
TpPort.tpPort(jsonNode.path(PORT).asInt()))));
@@ -57,27 +57,27 @@ public class CordVtnConfig extends Config<ApplicationId> {
}
/**
- * Configuration for an OVSDB node.
+ * Configuration for an ovsdb node.
*/
public static class OvsdbNodeConfig {
- private final String hostname;
+ private final String host;
private final IpAddress ip;
private final TpPort port;
- public OvsdbNodeConfig(String hostname, IpAddress ip, TpPort port) {
- this.hostname = checkNotNull(hostname);
+ public OvsdbNodeConfig(String host, IpAddress ip, TpPort port) {
+ this.host = checkNotNull(host);
this.ip = checkNotNull(ip);
this.port = checkNotNull(port);
}
/**
- * Returns hostname of the node.
+ * Returns host information of the node.
*
- * @return hostname
+ * @return host
*/
- public String hostname() {
- return this.hostname;
+ public String host() {
+ return this.host;
}
/**
diff --git a/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnConfigManager.java b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnConfigManager.java
new file mode 100644
index 00000000..043b3760
--- /dev/null
+++ b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnConfigManager.java
@@ -0,0 +1,144 @@
+/*
+ * 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.cordvtn;
+
+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.onosproject.cluster.ClusterService;
+import org.onosproject.cluster.LeadershipEvent;
+import org.onosproject.cluster.LeadershipEventListener;
+import org.onosproject.cluster.LeadershipService;
+import org.onosproject.cluster.NodeId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.config.ConfigFactory;
+import org.onosproject.net.config.NetworkConfigEvent;
+import org.onosproject.net.config.NetworkConfigListener;
+import org.onosproject.net.config.NetworkConfigRegistry;
+import org.onosproject.net.config.NetworkConfigService;
+import org.onosproject.net.config.basics.SubjectFactories;
+import org.slf4j.Logger;
+
+import static org.onosproject.cordvtn.OvsdbNode.State.INIT;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Reads node information from the network config file and handles the config
+ * update events.
+ * Only a leader controller performs the node addition or deletion.
+ */
+@Component(immediate = true)
+public class CordVtnConfigManager {
+
+ protected final Logger log = getLogger(getClass());
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CoreService coreService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected NetworkConfigRegistry configRegistry;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected NetworkConfigService configService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected LeadershipService leadershipService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected ClusterService clusterService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CordVtnService cordVtnService;
+
+ private final ConfigFactory configFactory =
+ new ConfigFactory(SubjectFactories.APP_SUBJECT_FACTORY, CordVtnConfig.class, "cordvtn") {
+ @Override
+ public CordVtnConfig createConfig() {
+ return new CordVtnConfig();
+ }
+ };
+
+ private final LeadershipEventListener leadershipListener = new InternalLeadershipListener();
+ private final NetworkConfigListener configListener = new InternalConfigListener();
+
+ private NodeId local;
+ private ApplicationId appId;
+
+ @Activate
+ protected void active() {
+ local = clusterService.getLocalNode().id();
+ appId = coreService.getAppId(CordVtnService.CORDVTN_APP_ID);
+
+ configService.addListener(configListener);
+ configRegistry.registerConfigFactory(configFactory);
+
+ leadershipService.addListener(leadershipListener);
+ leadershipService.runForLeadership(CordVtnService.CORDVTN_APP_ID);
+ }
+
+ @Deactivate
+ protected void deactivate() {
+ leadershipService.removeListener(leadershipListener);
+ leadershipService.withdraw(appId.name());
+
+ configRegistry.unregisterConfigFactory(configFactory);
+ configService.removeListener(configListener);
+ }
+
+ private void readConfiguration() {
+ CordVtnConfig config = configRegistry.getConfig(appId, CordVtnConfig.class);
+
+ if (config == null) {
+ log.warn("No configuration found");
+ return;
+ }
+
+ config.ovsdbNodes().forEach(node -> {
+ DefaultOvsdbNode ovsdbNode =
+ new DefaultOvsdbNode(node.host(), node.ip(), node.port(), INIT);
+ cordVtnService.addNode(ovsdbNode);
+ log.info("Add new node {}", node.host());
+ });
+ }
+
+ private synchronized void processLeadershipChange(NodeId leader) {
+ if (leader == null || !leader.equals(local)) {
+ return;
+ }
+ readConfiguration();
+ }
+
+ private class InternalLeadershipListener implements LeadershipEventListener {
+
+ @Override
+ public void event(LeadershipEvent event) {
+ if (event.subject().topic().equals(appId.name())) {
+ processLeadershipChange(event.subject().leader());
+ }
+ }
+ }
+
+ private class InternalConfigListener implements NetworkConfigListener {
+
+ @Override
+ public void event(NetworkConfigEvent event) {
+ // TODO handle update event
+ }
+ }
+}
diff --git a/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnService.java b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnService.java
index d26a10aa..1f75dceb 100644
--- a/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnService.java
+++ b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnService.java
@@ -15,8 +15,8 @@
*/
package org.onosproject.cordvtn;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.TpPort;
+import org.onosproject.cordvtn.OvsdbNode.State;
+import org.onosproject.net.DeviceId;
import java.util.List;
@@ -24,22 +24,30 @@ import java.util.List;
* Service for provisioning overlay virtual networks on compute nodes.
*/
public interface CordVtnService {
+
+ String CORDVTN_APP_ID = "org.onosproject.cordvtn";
/**
* Adds a new node to the service.
*
- * @param hostname hostname of the node
- * @param ip ip address to access the ovsdb server running on the node
- * @param port port number to access the ovsdb server running on the node
+ * @param ovsdbNode ovsdb node
+ */
+ void addNode(OvsdbNode ovsdbNode);
+
+ /**
+ * Deletes a node from the service.
+ *
+ * @param ovsdbNode ovsdb node
*/
- void addNode(String hostname, IpAddress ip, TpPort port);
+ void deleteNode(OvsdbNode ovsdbNode);
/**
- * Deletes the node from the service.
+ * Updates ovsdb node.
+ * It only used for updating node's connection state.
*
- * @param ip ip address to access the ovsdb server running on the node
- * @param port port number to access the ovsdb server running on the node
+ * @param ovsdbNode ovsdb node
+ * @param state ovsdb connection state
*/
- void deleteNode(IpAddress ip, TpPort port);
+ void updateNode(OvsdbNode ovsdbNode, State state);
/**
* Returns the number of the nodes known to the service.
@@ -49,6 +57,14 @@ public interface CordVtnService {
int getNodeCount();
/**
+ * Returns OvsdbNode with given device id.
+ *
+ * @param deviceId device id
+ * @return ovsdb node
+ */
+ OvsdbNode getNode(DeviceId deviceId);
+
+ /**
* Returns all nodes known to the service.
*
* @return list of nodes
diff --git a/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/DefaultOvsdbNode.java b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/DefaultOvsdbNode.java
index b8cdbe94..ce8b0f1d 100644
--- a/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/DefaultOvsdbNode.java
+++ b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/DefaultOvsdbNode.java
@@ -15,6 +15,7 @@
*/
package org.onosproject.cordvtn;
+import com.google.common.base.MoreObjects;
import org.onlab.packet.IpAddress;
import org.onlab.packet.TpPort;
import org.onosproject.net.DeviceId;
@@ -26,21 +27,15 @@ import java.util.Objects;
*/
public class DefaultOvsdbNode implements OvsdbNode {
- private final String hostname;
+ private final String host;
private final IpAddress ip;
private final TpPort port;
- private final DeviceId deviceId;
- private final DeviceId bridgeId;
private final State state;
- public DefaultOvsdbNode(String hostname, IpAddress ip, TpPort port,
- DeviceId bridgeId, State state) {
- this.hostname = hostname;
+ public DefaultOvsdbNode(String host, IpAddress ip, TpPort port, State state) {
+ this.host = host;
this.ip = ip;
this.port = port;
- this.deviceId = DeviceId.deviceId(
- "ovsdb:" + ip.toString() + ":" + port.toString());
- this.bridgeId = bridgeId;
this.state = state;
}
@@ -55,8 +50,8 @@ public class DefaultOvsdbNode implements OvsdbNode {
}
@Override
- public String hostname() {
- return this.hostname;
+ public String host() {
+ return this.host;
}
@Override
@@ -66,12 +61,12 @@ public class DefaultOvsdbNode implements OvsdbNode {
@Override
public DeviceId deviceId() {
- return this.deviceId;
+ return DeviceId.deviceId("ovsdb:" + this.ip.toString() + ":" + this.port.toString());
}
@Override
- public DeviceId bridgeId() {
- return this.bridgeId;
+ public DeviceId intBrId() {
+ return DeviceId.deviceId("of:" + this.host);
}
@Override
@@ -82,8 +77,9 @@ public class DefaultOvsdbNode implements OvsdbNode {
if (o instanceof DefaultOvsdbNode) {
DefaultOvsdbNode that = (DefaultOvsdbNode) o;
- // We compare the ip and port only.
- if (this.ip.equals(that.ip) && this.port.equals(that.port)) {
+ if (this.host.equals(that.host) &&
+ this.ip.equals(that.ip) &&
+ this.port.equals(that.port)) {
return true;
}
}
@@ -92,6 +88,16 @@ public class DefaultOvsdbNode implements OvsdbNode {
@Override
public int hashCode() {
- return Objects.hash(ip, port);
+ return Objects.hash(host, ip, port);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("host", host)
+ .add("ip", ip)
+ .add("port", port)
+ .add("state", state)
+ .toString();
}
}
diff --git a/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/NodeConnectionManager.java b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/NodeConnectionManager.java
index 0b7029ef..ebba4cd5 100644
--- a/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/NodeConnectionManager.java
+++ b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/NodeConnectionManager.java
@@ -15,12 +15,19 @@
*/
package org.onosproject.cordvtn;
+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.onosproject.cluster.ClusterService;
import org.onosproject.cluster.LeadershipService;
import org.onosproject.cluster.NodeId;
-import org.onosproject.core.ApplicationId;
import org.onosproject.mastership.MastershipService;
-import org.onosproject.net.DeviceId;
-import org.onosproject.store.service.EventuallyConsistentMap;
+import org.onosproject.net.Device;
+import org.onosproject.net.device.DeviceEvent;
+import org.onosproject.net.device.DeviceListener;
+import org.onosproject.net.device.DeviceService;
import org.slf4j.Logger;
import java.util.concurrent.Executors;
@@ -28,118 +35,131 @@ import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.cordvtn.OvsdbNode.State.CONNECTED;
+import static org.onosproject.cordvtn.OvsdbNode.State.DISCONNECTED;
+import static org.onosproject.cordvtn.OvsdbNode.State.READY;
import static org.slf4j.LoggerFactory.getLogger;
/**
- * Node connection manager.
+ * Provides the connection state management of all nodes registered to the service
+ * so that the nodes keep connected unless it is requested to be deleted.
*/
+@Component(immediate = true)
public class NodeConnectionManager {
protected final Logger log = getLogger(getClass());
- private final ApplicationId appId;
- private final NodeId localId;
- private final EventuallyConsistentMap<DeviceId, OvsdbNode> nodeStore;
- private final MastershipService mastershipService;
- private final LeadershipService leadershipService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ MastershipService mastershipService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ LeadershipService leadershipService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ ClusterService clusterService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ DeviceService deviceService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ CordVtnService cordVtnService;
private static final int DELAY_SEC = 5;
- private ScheduledExecutorService connectionExecutor;
-
- /**
- * Creates a new NodeConnectionManager.
- *
- * @param localId local id
- * @param nodeStore node store
- * @param mastershipService mastership service
- */
- public NodeConnectionManager(ApplicationId appId, NodeId localId,
- EventuallyConsistentMap<DeviceId, OvsdbNode> nodeStore,
- MastershipService mastershipService,
- LeadershipService leadershipService) {
- this.appId = appId;
- this.localId = localId;
- this.nodeStore = nodeStore;
- this.mastershipService = mastershipService;
- this.leadershipService = leadershipService;
- }
- /**
- * Starts the node connection manager.
- */
- public void start() {
- connectionExecutor = Executors.newSingleThreadScheduledExecutor(
- groupedThreads("onos/cordvtn", "connection-executor"));
- connectionExecutor.scheduleWithFixedDelay(() -> nodeStore.values()
+ private final DeviceListener deviceListener = new InternalDeviceListener();
+ private final ScheduledExecutorService connectionExecutor = Executors
+ .newSingleThreadScheduledExecutor(groupedThreads("onos/cordvtn", "connection-manager"));
+
+ private NodeId localId;
+
+ @Activate
+ protected void activate() {
+ localId = clusterService.getLocalNode().id();
+ deviceService.addListener(deviceListener);
+
+ connectionExecutor.scheduleWithFixedDelay(() -> cordVtnService.getNodes()
.stream()
.filter(node -> localId.equals(getMaster(node)))
- .forEach(node -> connectNode(node)), 0, DELAY_SEC, TimeUnit.SECONDS);
+ .forEach(node -> {
+ connect(node);
+ disconnect(node);
+ }), 0, DELAY_SEC, TimeUnit.SECONDS);
}
- /**
- * Stops the node connection manager.
- */
+ @Deactivate
public void stop() {
connectionExecutor.shutdown();
+ deviceService.removeListener(deviceListener);
}
- /**
- * Adds a new node to the system.
- *
- * @param ovsdbNode ovsdb node
- */
- public void connectNode(OvsdbNode ovsdbNode) {
+ public void connect(OvsdbNode ovsdbNode) {
switch (ovsdbNode.state()) {
case INIT:
case DISCONNECTED:
- // TODO: set the node to passive mode
+ setPassiveMode(ovsdbNode);
case READY:
- // TODO: initiate connection
- break;
- case CONNECTED:
+ setupConnection(ovsdbNode);
break;
default:
+ break;
}
}
- /**
- * Deletes the ovsdb node.
- *
- * @param ovsdbNode ovsdb node
- */
- public void disconnectNode(OvsdbNode ovsdbNode) {
+ public void disconnect(OvsdbNode ovsdbNode) {
switch (ovsdbNode.state()) {
- case CONNECTED:
+ case DISCONNECT:
// TODO: disconnect
break;
- case INIT:
- case READY:
- case DISCONNECTED:
- break;
default:
+ break;
+ }
+ }
+
+ private class InternalDeviceListener implements DeviceListener {
+
+ @Override
+ public void event(DeviceEvent event) {
+ Device device = event.subject();
+ if (device.type() != Device.Type.CONTROLLER) {
+ return;
+ }
+
+ DefaultOvsdbNode node;
+ switch (event.type()) {
+ case DEVICE_ADDED:
+ node = (DefaultOvsdbNode) cordVtnService.getNode(device.id());
+ if (node != null) {
+ cordVtnService.updateNode(node, CONNECTED);
+ }
+ break;
+ case DEVICE_AVAILABILITY_CHANGED:
+ node = (DefaultOvsdbNode) cordVtnService.getNode(device.id());
+ if (node != null) {
+ cordVtnService.updateNode(node, DISCONNECTED);
+ }
+ break;
+ default:
+ break;
+ }
}
}
private NodeId getMaster(OvsdbNode ovsdbNode) {
- // Return the master of the bridge(switch) if it exist or
- // return the current leader
- if (ovsdbNode.bridgeId() == DeviceId.NONE) {
- return leadershipService.getLeader(this.appId.name());
- } else {
- return mastershipService.getMasterFor(ovsdbNode.bridgeId());
+ NodeId master = mastershipService.getMasterFor(ovsdbNode.intBrId());
+
+ // master is null if there's no such device
+ if (master == null) {
+ master = leadershipService.getLeader(CordVtnService.CORDVTN_APP_ID);
}
+ return master;
}
private void setPassiveMode(OvsdbNode ovsdbNode) {
// TODO: need ovsdb client implementation first
// TODO: set the remove ovsdb server passive mode
- // TODO: set the node state READY if it succeed
- }
-
- private void connect(OvsdbNode ovsdbNode) {
- // TODO: need ovsdb client implementation first
+ cordVtnService.updateNode(ovsdbNode, READY);
}
- private void disconnect(OvsdbNode ovsdbNode) {
- // TODO: need ovsdb client implementation first
+ private void setupConnection(OvsdbNode ovsdbNode) {
+ // TODO initiate connection
}
}
diff --git a/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/OvsdbNode.java b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/OvsdbNode.java
index bb2a0b7d..296bd439 100644
--- a/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/OvsdbNode.java
+++ b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/OvsdbNode.java
@@ -24,51 +24,52 @@ import org.onosproject.net.DeviceId;
*/
public interface OvsdbNode {
/**
- * State of the ovsdb node.
+ * Ovsdb connection state.
*/
enum State {
- INIT, READY, CONNECTED, DISCONNECTED
+ INIT, READY, CONNECTED, DISCONNECT, DISCONNECTED
}
/**
- * Returns the IP address of ovsdb server.
+ * Returns the IP address of the ovsdb server.
*
* @return ip address
*/
IpAddress ip();
/**
- * Returns the port number of ovsdb server.
+ * Returns the port number of the ovsdb server.
*
* @return port number
*/
TpPort port();
/**
- * Returns the hostname of the node.
+ * Returns the host information of the ovsdb server.
+ * It could be hostname or ip address.
*
- * @return hostname
+ * @return host
*/
- String hostname();
+ String host();
/**
- * Returns the state of the node.
+ * Returns the connection state of the ovsdb server.
*
- * @return state of the node
+ * @return connection state
*/
State state();
/**
- * Returns the device ID of the node.
+ * Returns the device id of the ovsdb server.
*
* @return device id
*/
DeviceId deviceId();
/**
- * Returns the device ID of the bridge associated with this node.
+ * Returns the device id of the integration bridge associated with the node.
*
* @return device id
*/
- DeviceId bridgeId();
+ DeviceId intBrId();
}
diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/DhcpStore.java b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/DhcpStore.java
index c9fade9e..5615af1a 100644
--- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/DhcpStore.java
+++ b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/DhcpStore.java
@@ -65,7 +65,7 @@ public interface DhcpStore {
*
* @param hostId the host ID for which the mapping needs to be changed
*/
- void releaseIP(HostId hostId);
+ Ip4Address releaseIP(HostId hostId);
/**
* Returns a collection of all the MacAddress to IPAddress mapping assigned to the hosts.
diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpManager.java b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpManager.java
index 345d5ad0..96d94a2b 100644
--- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpManager.java
+++ b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 Open Networking Laboratory
+ * 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.
@@ -154,6 +154,8 @@ public class DhcpManager implements DhcpService {
private static Ip4Address domainServer = Ip4Address.valueOf("10.0.0.2");
+ private static final Ip4Address IP_BROADCAST = Ip4Address.valueOf("255.255.255.255");
+
protected Timeout timeout;
protected static int timerDelay = 2;
@@ -290,12 +292,18 @@ public class DhcpManager implements DhcpService {
DHCP dhcpPacket = (DHCP) udpPacket.getPayload();
DHCP dhcpReply = new DHCP();
dhcpReply.setOpCode(DHCP.OPCODE_REPLY);
-
- dhcpReply.setYourIPAddress(ipOffered.toInt());
- dhcpReply.setServerIPAddress(myIP.toInt());
-
- dhcpReply.setTransactionId(dhcpPacket.getTransactionId());
+ dhcpReply.setFlags(dhcpPacket.getFlags());
+ dhcpReply.setGatewayIPAddress(dhcpPacket.getGatewayIPAddress());
dhcpReply.setClientHardwareAddress(dhcpPacket.getClientHardwareAddress());
+ dhcpReply.setTransactionId(dhcpPacket.getTransactionId());
+
+ if (outgoingMessageType != DHCPPacketType.DHCPNAK.getValue()) {
+ dhcpReply.setYourIPAddress(ipOffered.toInt());
+ dhcpReply.setServerIPAddress(myIP.toInt());
+ if (dhcpPacket.getGatewayIPAddress() == 0) {
+ ipv4Reply.setDestinationAddress(IP_BROADCAST.toInt());
+ }
+ }
dhcpReply.setHardwareType(DHCP.HWTYPE_ETHERNET);
dhcpReply.setHardwareAddressLength((byte) 6);
@@ -317,54 +325,57 @@ public class DhcpManager implements DhcpService {
option.setData(myIP.toOctets());
optionList.add(option);
- // IP Address Lease Time.
- option = new DHCPOption();
- option.setCode(DHCP.DHCPOptionCode.OptionCode_LeaseTime.getValue());
- option.setLength((byte) 4);
- option.setData(ByteBuffer.allocate(4).putInt(leaseTime).array());
- optionList.add(option);
-
- // IP Address Renewal Time.
- option = new DHCPOption();
- option.setCode(DHCP.DHCPOptionCode.OptionCode_RenewalTime.getValue());
- option.setLength((byte) 4);
- option.setData(ByteBuffer.allocate(4).putInt(renewalTime).array());
- optionList.add(option);
-
- // IP Address Rebinding Time.
- option = new DHCPOption();
- option.setCode(DHCP.DHCPOptionCode.OPtionCode_RebindingTime.getValue());
- option.setLength((byte) 4);
- option.setData(ByteBuffer.allocate(4).putInt(rebindingTime).array());
- optionList.add(option);
-
- // Subnet Mask.
- option = new DHCPOption();
- option.setCode(DHCP.DHCPOptionCode.OptionCode_SubnetMask.getValue());
- option.setLength((byte) 4);
- option.setData(subnetMask.toOctets());
- optionList.add(option);
-
- // Broadcast Address.
- option = new DHCPOption();
- option.setCode(DHCP.DHCPOptionCode.OptionCode_BroadcastAddress.getValue());
- option.setLength((byte) 4);
- option.setData(broadcastAddress.toOctets());
- optionList.add(option);
-
- // Router Address.
- option = new DHCPOption();
- option.setCode(DHCP.DHCPOptionCode.OptionCode_RouterAddress.getValue());
- option.setLength((byte) 4);
- option.setData(routerAddress.toOctets());
- optionList.add(option);
-
- // DNS Server Address.
- option = new DHCPOption();
- option.setCode(DHCP.DHCPOptionCode.OptionCode_DomainServer.getValue());
- option.setLength((byte) 4);
- option.setData(domainServer.toOctets());
- optionList.add(option);
+ if (outgoingMessageType != DHCPPacketType.DHCPNAK.getValue()) {
+
+ // IP Address Lease Time.
+ option = new DHCPOption();
+ option.setCode(DHCP.DHCPOptionCode.OptionCode_LeaseTime.getValue());
+ option.setLength((byte) 4);
+ option.setData(ByteBuffer.allocate(4).putInt(leaseTime).array());
+ optionList.add(option);
+
+ // IP Address Renewal Time.
+ option = new DHCPOption();
+ option.setCode(DHCP.DHCPOptionCode.OptionCode_RenewalTime.getValue());
+ option.setLength((byte) 4);
+ option.setData(ByteBuffer.allocate(4).putInt(renewalTime).array());
+ optionList.add(option);
+
+ // IP Address Rebinding Time.
+ option = new DHCPOption();
+ option.setCode(DHCP.DHCPOptionCode.OPtionCode_RebindingTime.getValue());
+ option.setLength((byte) 4);
+ option.setData(ByteBuffer.allocate(4).putInt(rebindingTime).array());
+ optionList.add(option);
+
+ // Subnet Mask.
+ option = new DHCPOption();
+ option.setCode(DHCP.DHCPOptionCode.OptionCode_SubnetMask.getValue());
+ option.setLength((byte) 4);
+ option.setData(subnetMask.toOctets());
+ optionList.add(option);
+
+ // Broadcast Address.
+ option = new DHCPOption();
+ option.setCode(DHCP.DHCPOptionCode.OptionCode_BroadcastAddress.getValue());
+ option.setLength((byte) 4);
+ option.setData(broadcastAddress.toOctets());
+ optionList.add(option);
+
+ // Router Address.
+ option = new DHCPOption();
+ option.setCode(DHCP.DHCPOptionCode.OptionCode_RouterAddress.getValue());
+ option.setLength((byte) 4);
+ option.setData(routerAddress.toOctets());
+ optionList.add(option);
+
+ // DNS Server Address.
+ option = new DHCPOption();
+ option.setCode(DHCP.DHCPOptionCode.OptionCode_DomainServer.getValue());
+ option.setLength((byte) 4);
+ option.setData(domainServer.toOctets());
+ optionList.add(option);
+ }
// End Option.
option = new DHCPOption();
@@ -447,41 +458,51 @@ public class DhcpManager implements DhcpService {
} else if (incomingPacketType.getValue() == DHCPPacketType.DHCPREQUEST.getValue()) {
- outgoingPacketType = DHCPPacketType.DHCPACK;
-
if (flagIfServerIP && flagIfRequestedIP) {
// SELECTING state
- if (myIP.equals(serverIP) &&
- dhcpStore.assignIP(hostId, requestedIP, leaseTime)) {
+ if (myIP.equals(serverIP)) {
- Ethernet ethReply = buildReply(packet, requestedIP,
- (byte) outgoingPacketType.getValue());
+ if (dhcpStore.assignIP(hostId, requestedIP, leaseTime)) {
+ outgoingPacketType = DHCPPacketType.DHCPACK;
+ discoverHost(context, requestedIP);
+ } else {
+ outgoingPacketType = DHCPPacketType.DHCPNAK;
+ }
+ Ethernet ethReply = buildReply(packet, requestedIP, (byte) outgoingPacketType.getValue());
sendReply(context, ethReply);
- discoverHost(context, requestedIP);
}
} else if (flagIfRequestedIP) {
// INIT-REBOOT state
if (dhcpStore.assignIP(hostId, requestedIP, leaseTime)) {
- Ethernet ethReply = buildReply(packet, requestedIP,
- (byte) outgoingPacketType.getValue());
+ outgoingPacketType = DHCPPacketType.DHCPACK;
+ Ethernet ethReply = buildReply(packet, requestedIP, (byte) outgoingPacketType.getValue());
sendReply(context, ethReply);
discoverHost(context, requestedIP);
}
+
} else {
// RENEWING and REBINDING state
int ciaadr = dhcpPayload.getClientIPAddress();
if (ciaadr != 0) {
Ip4Address clientIaddr = Ip4Address.valueOf(ciaadr);
if (dhcpStore.assignIP(hostId, clientIaddr, leaseTime)) {
- Ethernet ethReply = buildReply(packet, clientIaddr,
- (byte) outgoingPacketType.getValue());
- sendReply(context, ethReply);
+ outgoingPacketType = DHCPPacketType.DHCPACK;
discoverHost(context, clientIaddr);
+ } else if (packet.getEtherType() == Ethernet.TYPE_IPV4 &&
+ ((IPv4) packet.getPayload()).getDestinationAddress() == myIP.toInt()) {
+ outgoingPacketType = DHCPPacketType.DHCPNAK;
+ } else {
+ return;
}
+ Ethernet ethReply = buildReply(packet, clientIaddr, (byte) outgoingPacketType.getValue());
+ sendReply(context, ethReply);
}
}
} else if (incomingPacketType.getValue() == DHCPPacketType.DHCPRELEASE.getValue()) {
- dhcpStore.releaseIP(hostId);
+ Ip4Address ip4Address = dhcpStore.releaseIP(hostId);
+ if (ip4Address != null) {
+ hostProviderService.removeIpFromHost(hostId, ip4Address);
+ }
}
}
}
@@ -666,9 +687,10 @@ public class DhcpManager implements DhcpService {
if ((ipAssignment.assignmentStatus() != IpAssignment.AssignmentStatus.Option_Expired) &&
(ipAssignment.leasePeriod() > 0) && (timeLapsed > (ipAssignment.leasePeriodMs()))) {
- dhcpStore.releaseIP(entry.getKey());
- // TODO remove only the IP from the host entry when the API is in place.
- hostProviderService.hostVanished(entry.getKey());
+ Ip4Address ip4Address = dhcpStore.releaseIP(entry.getKey());
+ if (ip4Address != null) {
+ hostProviderService.removeIpFromHost(entry.getKey(), ipAssignment.ipAddress());
+ }
}
}
timeout = Timer.getTimer().newTimeout(new PurgeListTask(), timerDelay, TimeUnit.MINUTES);
diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DistributedDhcpStore.java b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DistributedDhcpStore.java
index dbdadb34..63f69d40 100644
--- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DistributedDhcpStore.java
+++ b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DistributedDhcpStore.java
@@ -212,7 +212,7 @@ public class DistributedDhcpStore implements DhcpStore {
}
@Override
- public void releaseIP(HostId hostId) {
+ public Ip4Address releaseIP(HostId hostId) {
if (allocationMap.containsKey(hostId)) {
IpAssignment newAssignment = IpAssignment.builder(allocationMap.get(hostId).value())
.assignmentStatus(IpAssignment.AssignmentStatus.Option_Expired)
@@ -222,7 +222,9 @@ public class DistributedDhcpStore implements DhcpStore {
if (ipWithinRange(freeIP)) {
freeIPPool.add(freeIP);
}
+ return freeIP;
}
+ return null;
}
@Override
diff --git a/framework/src/onos/apps/dhcp/src/test/java/org/onosproject/dhcp/impl/DhcpManagerTest.java b/framework/src/onos/apps/dhcp/src/test/java/org/onosproject/dhcp/impl/DhcpManagerTest.java
index 3ea3b1b8..fd4701c6 100644
--- a/framework/src/onos/apps/dhcp/src/test/java/org/onosproject/dhcp/impl/DhcpManagerTest.java
+++ b/framework/src/onos/apps/dhcp/src/test/java/org/onosproject/dhcp/impl/DhcpManagerTest.java
@@ -25,6 +25,7 @@ import org.onlab.packet.DHCPPacketType;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IPv4;
import org.onlab.packet.Ip4Address;
+import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.packet.UDP;
import org.onosproject.core.CoreServiceAdapter;
@@ -234,7 +235,8 @@ public class DhcpManagerTest {
public void setDefaultTimeoutForPurge(int timeInSeconds) {
}
- public void releaseIP(HostId hostId) {
+ public Ip4Address releaseIP(HostId hostId) {
+ return null;
}
public Map<HostId, IpAssignment> listAssignedMapping() {
@@ -331,12 +333,18 @@ public class DhcpManagerTest {
@Override
public void hostDetected(HostId hostId, HostDescription hostDescription, boolean replaceIps) {
+
}
@Override
public void hostVanished(HostId hostId) {
}
+ @Override
+ public void removeIpFromHost(HostId hostId, IpAddress ipAddress) {
+
+ }
+
}
/**
diff --git a/framework/src/onos/apps/flowanalyzer/pom.xml b/framework/src/onos/apps/flowanalyzer/pom.xml
index f5dfcf2b..b0920412 100644
--- a/framework/src/onos/apps/flowanalyzer/pom.xml
+++ b/framework/src/onos/apps/flowanalyzer/pom.xml
@@ -40,6 +40,38 @@
<groupId>org.osgi</groupId>
<artifactId>org.osgi.compendium</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onlab-junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-api</artifactId>
+ <classifier>tests</classifier>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.scr.annotations</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-cli</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.karaf.shell</groupId>
+ <artifactId>org.apache.karaf.shell.console</artifactId>
+ </dependency>
+
</dependencies>
</project>
diff --git a/framework/src/onos/apps/flowanalyzer/src/main/java/org/onosproject/flowanalyzer/FlowAnalysisCommand.java b/framework/src/onos/apps/flowanalyzer/src/main/java/org/onosproject/flowanalyzer/FlowAnalysisCommand.java
new file mode 100644
index 00000000..2c61949b
--- /dev/null
+++ b/framework/src/onos/apps/flowanalyzer/src/main/java/org/onosproject/flowanalyzer/FlowAnalysisCommand.java
@@ -0,0 +1,33 @@
+/*
+ * 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.flowanalyzer;
+
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+
+/**
+ * Analyzes flows for cycles and black holes.
+ */
+@Command(scope = "onos", name = "flow-analysis",
+ description = "Analyzes flows for cycles and black holes")
+public class FlowAnalysisCommand extends AbstractShellCommand {
+
+ @Override
+ protected void execute() {
+ FlowAnalyzer service = get(FlowAnalyzer.class);
+ print(service.analyze());
+ }
+}
diff --git a/framework/src/onos/apps/flowanalyzer/src/main/java/org/onosproject/flowanalyzer/FlowAnalyzer.java b/framework/src/onos/apps/flowanalyzer/src/main/java/org/onosproject/flowanalyzer/FlowAnalyzer.java
index 5d99d746..6aaaaee8 100644
--- a/framework/src/onos/apps/flowanalyzer/src/main/java/org/onosproject/flowanalyzer/FlowAnalyzer.java
+++ b/framework/src/onos/apps/flowanalyzer/src/main/java/org/onosproject/flowanalyzer/FlowAnalyzer.java
@@ -21,12 +21,31 @@ 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.onosproject.net.ConnectPoint;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.FlowEntry;
import org.onosproject.net.flow.FlowRuleService;
-import org.onosproject.net.host.HostService;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.HostId;
+import org.onosproject.net.flow.criteria.Criteria;
+import org.onosproject.net.flow.criteria.Criterion;
+import org.onosproject.net.flow.criteria.PortCriterion;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.Instructions;
+import org.onosproject.net.topology.TopologyService;
+import org.onosproject.net.topology.TopologyGraph;
import org.onosproject.net.link.LinkService;
+import org.onosproject.net.Link;
+import org.onosproject.net.topology.TopologyVertex;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
+import java.util.HashSet;
+import java.util.List;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
import static org.slf4j.LoggerFactory.getLogger;
/**
@@ -42,11 +61,10 @@ public class FlowAnalyzer {
protected FlowRuleService flowRuleService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected LinkService linkService;
+ protected TopologyService topologyService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected HostService hostService;
-
+ protected LinkService linkService;
@Activate
public void activate(ComponentContext context) {
@@ -58,12 +76,193 @@ public class FlowAnalyzer {
log.info("Stopped");
}
+ TopologyGraph graph;
+ Map<FlowEntry, String> label = new HashMap<>();
+ Set<FlowEntry> ignoredFlows = new HashSet<>();
/**
- * ...
+ * Analyzes and prints out a report on the status of every flow entry inside
+ * the network. The possible states are: Cleared (implying that the entry leads to
+ * a host), Cycle (implying that it is part of cycle), and Black Hole (implying
+ * that the entry does not lead to a single host).
*/
- public void analyze() {
- // TODO: implement this
+ public String analyze() {
+ graph = topologyService.getGraph(topologyService.currentTopology());
+ for (TopologyVertex v: graph.getVertexes()) {
+ DeviceId srcDevice = v.deviceId();
+ Iterable<FlowEntry> flowTable = flowRuleService.getFlowEntries(srcDevice);
+ for (FlowEntry flow: flowTable) {
+ dfs(flow);
+ }
+ }
+
+ //analyze the cycles to look for "critical flows" that can be removed
+ //to break the cycle
+ Set<FlowEntry> critpts = new HashSet<>();
+ for (FlowEntry flow: label.keySet()) {
+ if ("Cycle".equals(label.get(flow))) {
+ Map<FlowEntry, String> labelSaved = label;
+ label = new HashMap<FlowEntry, String>();
+ ignoredFlows.add(flow);
+ for (TopologyVertex v: graph.getVertexes()) {
+ DeviceId srcDevice = v.deviceId();
+ Iterable<FlowEntry> flowTable = flowRuleService.getFlowEntries(srcDevice);
+ for (FlowEntry flow1: flowTable) {
+ dfs(flow1);
+ }
+ }
+
+ boolean replacable = true;
+ for (FlowEntry flow2: label.keySet()) {
+ if ("Cleared".equals(labelSaved.get(flow2)) && !("Cleared".equals(label.get(flow2)))) {
+ replacable = false;
+ }
+ }
+ if (replacable) {
+ critpts.add(flow);
+ }
+ label = labelSaved;
+ }
+ }
+
+ for (FlowEntry flow: critpts) {
+ label.put(flow, "Cycle Critical Point");
+ }
+
+ String s = "\n";
+ for (FlowEntry flow: label.keySet()) {
+ s += ("Flow Rule: " + flowEntryRepresentation(flow) + "\n");
+ s += ("Analysis: " + label.get(flow) + "!\n\n");
+ }
+ s += ("Analyzed " + label.keySet().size() + " flows.");
+ //log.info(s);
+ return s;
+ }
+
+ public Map<FlowEntry, String> calcLabels() {
+ analyze();
+ return label;
+ }
+ public String analysisOutput() {
+ analyze();
+ String s = "\n";
+ for (FlowEntry flow: label.keySet()) {
+ s += ("Flow Rule: " + flowEntryRepresentation(flow) + "\n");
+ s += ("Analysis: " + label.get(flow) + "!\n\n");
+ }
+ return s;
+ }
+
+ private boolean dfs(FlowEntry flow) {
+ if (ignoredFlows.contains(flow)) {
+ return false;
+ }
+ if ("Cycle".equals(label.get(flow)) ||
+ "Black Hole".equals(label.get(flow)) ||
+ "Cleared".equals(label.get(flow)) ||
+ "NA".equals(label.get(flow)) ||
+ "Cycle Critical Point".equals(label.get(flow))) {
+
+ // This flow has already been analyzed and there is no need to analyze it further
+ return !"Black Hole".equals(label.get(flow));
+ }
+
+ if ("Visiting".equals(label.get(flow))) {
+ //you've detected a cycle because you reached the same entry again during your dfs
+ //let it continue so you can label the whole cycle
+ label.put(flow, "Cycle");
+ } else {
+ //otherwise, mark off the current flow entry as currently being visited
+ label.put(flow, "Visiting");
+ }
+
+ boolean pointsToLiveEntry = false;
+
+ List<Instruction> instructions = flow.treatment().allInstructions();
+ for (Instruction i: instructions) {
+ if (i instanceof Instructions.OutputInstruction) {
+ pointsToLiveEntry |= analyzeInstruction(i, flow);
+ }
+ if ("NA".equals(label.get(flow))) {
+ return pointsToLiveEntry;
+ }
+ }
+
+ if (!pointsToLiveEntry) {
+ //this entry does not point to any "live" entries thus must be a black hole
+ label.put(flow, "Black Hole");
+ } else if ("Visiting".equals(label.get(flow))) {
+ //the flow is not in a cycle or in a black hole
+ label.put(flow, "Cleared");
+ }
+ return pointsToLiveEntry;
}
+ private boolean analyzeInstruction(Instruction i, FlowEntry flow) {
+ boolean pointsToLiveEntry = false;
+ Instructions.OutputInstruction output = (Instructions.OutputInstruction) i;
+ PortNumber port = output.port();
+ PortNumber outPort = null;
+
+ DeviceId egress = null;
+ boolean hasHost = false;
+
+ ConnectPoint portPt = new ConnectPoint(flow.deviceId(), port);
+ for (Link l: linkService.getEgressLinks(portPt)) {
+ if (l.dst().elementId() instanceof DeviceId) {
+ egress = l.dst().deviceId();
+ outPort = l.dst().port();
+ } else if (l.dst().elementId() instanceof HostId) {
+ //the port leads to a host: therefore it is not a dead link
+ pointsToLiveEntry = true;
+ hasHost = true;
+ }
+ }
+ if (!topologyService.isInfrastructure(topologyService.currentTopology(), portPt) && egress == null) {
+ pointsToLiveEntry = true;
+ hasHost = true;
+ }
+ if (hasHost) {
+ return pointsToLiveEntry;
+ }
+ if (egress == null) {
+ //the port that the flow instructions tells you to send the packet
+ //to doesn't exist or is a controller port
+ label.put(flow, "NA");
+ return pointsToLiveEntry;
+ }
+
+ Iterable<FlowEntry> dstFlowTable = flowRuleService.getFlowEntries(egress);
+
+ Set<Criterion> flowCriteria = flow.selector().criteria();
+
+ //filter the criteria in order to remove port dependency
+ Set<Criterion> filteredCriteria = new HashSet<>();
+ for (Criterion criterion : flowCriteria) {
+ if (!(criterion instanceof PortCriterion)) {
+ filteredCriteria.add(criterion);
+ }
+ }
+
+ //ensure that the in port is equal to the port that it is coming in from
+ filteredCriteria.add(Criteria.matchInPort(outPort));
+
+ for (FlowEntry entry: dstFlowTable) {
+ if (ignoredFlows.contains(entry)) {
+ continue;
+ }
+ if (filteredCriteria.containsAll(entry.selector().criteria())) {
+ dfs(entry);
+
+ if (!"Black Hole".equals(label.get(entry))) {
+ //this entry is "live" i.e not a black hole
+ pointsToLiveEntry = true;
+ }
+ }
+ }
+ return pointsToLiveEntry;
+ }
+ public String flowEntryRepresentation(FlowEntry flow) {
+ return "Device: " + flow.deviceId() + ", " + flow.selector().criteria() + ", " + flow.treatment().immediate();
+ }
}
diff --git a/framework/src/onos/apps/flowanalyzer/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/framework/src/onos/apps/flowanalyzer/src/main/resources/OSGI-INF/blueprint/shell-config.xml
new file mode 100644
index 00000000..93cb27ee
--- /dev/null
+++ b/framework/src/onos/apps/flowanalyzer/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -0,0 +1,23 @@
+<!--
+ ~ 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.
+ -->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+ <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
+ <command>
+ <action class="org.onosproject.flowanalyzer.FlowAnalysisCommand"/>
+ </command>
+
+ </command-bundle>
+</blueprint>
diff --git a/framework/src/onos/apps/flowanalyzer/src/test/java/org/onosproject/flowanalyzer/DefaultMutableTopologyGraph.java b/framework/src/onos/apps/flowanalyzer/src/test/java/org/onosproject/flowanalyzer/DefaultMutableTopologyGraph.java
new file mode 100644
index 00000000..4ea3aa48
--- /dev/null
+++ b/framework/src/onos/apps/flowanalyzer/src/test/java/org/onosproject/flowanalyzer/DefaultMutableTopologyGraph.java
@@ -0,0 +1,28 @@
+package org.onosproject.flowanalyzer;
+
+import org.onlab.graph.MutableAdjacencyListsGraph;
+import org.onosproject.net.topology.TopologyEdge;
+import org.onosproject.net.topology.TopologyGraph;
+import org.onosproject.net.topology.TopologyVertex;
+
+import java.util.Set;
+
+/**
+ * Default implementation of an immutable topology graph based on a generic
+ * implementation of adjacency lists graph.
+ */
+public class DefaultMutableTopologyGraph
+ extends MutableAdjacencyListsGraph<TopologyVertex, TopologyEdge>
+ implements TopologyGraph {
+
+ /**
+ * Creates a topology graph comprising of the specified vertexes and edges.
+ *
+ * @param vertexes set of graph vertexes
+ * @param edges set of graph edges
+ */
+ public DefaultMutableTopologyGraph(Set<TopologyVertex> vertexes, Set<TopologyEdge> edges) {
+ super(vertexes, edges);
+ }
+
+}
diff --git a/framework/src/onos/apps/flowanalyzer/src/test/java/org/onosproject/flowanalyzer/FlowAnalyzerTest.java b/framework/src/onos/apps/flowanalyzer/src/test/java/org/onosproject/flowanalyzer/FlowAnalyzerTest.java
new file mode 100644
index 00000000..faa2f5f9
--- /dev/null
+++ b/framework/src/onos/apps/flowanalyzer/src/test/java/org/onosproject/flowanalyzer/FlowAnalyzerTest.java
@@ -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.flowanalyzer;
+
+import org.junit.Ignore;
+import org.junit.Test;
+
+import org.onosproject.core.DefaultApplicationId;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.DefaultFlowRule;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleExtPayLoad;
+import org.onosproject.net.flow.FlowRuleService;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.instructions.Instructions;
+import org.onosproject.net.topology.TopologyService;
+
+import java.util.Arrays;
+import java.util.TreeSet;
+
+import static org.junit.Assert.assertEquals;
+
+
+/**
+ * Created by nikcheerla on 7/20/15.
+ */
+public class FlowAnalyzerTest {
+
+ FlowRuleService flowRuleService = new MockFlowRuleService();
+ TopologyService topologyService;
+ MockLinkService linkService = new MockLinkService();
+
+ @Test
+ @Ignore("This needs to be reworked to be more robust")
+ public void basic() {
+ flowRuleService = new MockFlowRuleService();
+ flowRuleService.applyFlowRules(genFlow("ATL-001", 110, 90));
+ flowRuleService.applyFlowRules(genFlow("ATL-001", 110, 100));
+ flowRuleService.applyFlowRules(genFlow("ATL-001", 110, 150));
+ flowRuleService.applyFlowRules(genFlow("ATL-002", 80, 70));
+ flowRuleService.applyFlowRules(genFlow("ATL-003", 120, 130));
+ flowRuleService.applyFlowRules(genFlow("ATL-004", 50));
+ flowRuleService.applyFlowRules(genFlow("ATL-005", 140, 10));
+
+ linkService.addLink("H00:00:00:00:00:0660", 160, "ATL-005", 140);
+ linkService.addLink("ATL-005", 10, "ATL-004", 40);
+ linkService.addLink("ATL-004", 50, "ATL-002", 80);
+ linkService.addLink("ATL-002", 70, "ATL-001", 110);
+ linkService.addLink("ATL-001", 150, "H00:00:00:00:00:0770", 170);
+ linkService.addLink("ATL-001", 90, "ATL-004", 30);
+ linkService.addLink("ATL-001", 100, "ATL-003", 120);
+ linkService.addLink("ATL-003", 130, "ATL-005", 20);
+
+ topologyService = new MockTopologyService(linkService.createdGraph);
+
+ FlowAnalyzer flowAnalyzer = new FlowAnalyzer();
+ flowAnalyzer.flowRuleService = flowRuleService;
+ flowAnalyzer.linkService = linkService;
+ flowAnalyzer.topologyService = topologyService;
+
+ String labels = flowAnalyzer.analysisOutput();
+ String correctOutput = "Flow Rule: Device: atl-005, [IN_PORT{port=140}], [OUTPUT{port=10}]\n" +
+ "Analysis: Cleared!\n" +
+ "\n" +
+ "Flow Rule: Device: atl-003, [IN_PORT{port=120}], [OUTPUT{port=130}]\n" +
+ "Analysis: Black Hole!\n" +
+ "\n" +
+ "Flow Rule: Device: atl-001, [IN_PORT{port=110}], [OUTPUT{port=90}]\n" +
+ "Analysis: Cycle Critical Point!\n" +
+ "\n" +
+ "Flow Rule: Device: atl-004, [], [OUTPUT{port=50}]\n" +
+ "Analysis: Cycle!\n" +
+ "\n" +
+ "Flow Rule: Device: atl-001, [IN_PORT{port=110}], [OUTPUT{port=150}]\n" +
+ "Analysis: Cleared!\n" +
+ "\n" +
+ "Flow Rule: Device: atl-001, [IN_PORT{port=110}], [OUTPUT{port=100}]\n" +
+ "Analysis: Black Hole!\n" +
+ "\n" +
+ "Flow Rule: Device: atl-002, [IN_PORT{port=80}], [OUTPUT{port=70}]\n" +
+ "Analysis: Cycle!\n";
+ assertEquals("Wrong labels", new TreeSet(Arrays.asList(labels.replaceAll("\\s+", "").split("!"))),
+ new TreeSet(Arrays.asList(correctOutput.replaceAll("\\s+", "").split("!"))));
+ }
+
+ public FlowRule genFlow(String d, long inPort, long outPort) {
+ DeviceId device = DeviceId.deviceId(d);
+ TrafficSelector ts = DefaultTrafficSelector.builder().matchInPort(PortNumber.portNumber(inPort)).build();
+ TrafficTreatment tt = DefaultTrafficTreatment.builder()
+ .add(Instructions.createOutput(PortNumber.portNumber(outPort))).build();
+ return new DefaultFlowRule(device, ts, tt, 1, new DefaultApplicationId(5000, "of"),
+ 50000, true, FlowRuleExtPayLoad.flowRuleExtPayLoad(new byte[5]));
+ }
+ public FlowRule genFlow(String d, long outPort) {
+ DeviceId device = DeviceId.deviceId(d);
+ TrafficSelector ts = DefaultTrafficSelector.builder().build();
+ TrafficTreatment tt = DefaultTrafficTreatment.builder()
+ .add(Instructions.createOutput(PortNumber.portNumber(outPort))).build();
+ return new DefaultFlowRule(device, ts, tt, 1, new DefaultApplicationId(5000, "of"),
+ 50000, true, FlowRuleExtPayLoad.flowRuleExtPayLoad(new byte[5]));
+ }
+
+}
diff --git a/framework/src/onos/apps/flowanalyzer/src/test/java/org/onosproject/flowanalyzer/MockFlowRuleService.java b/framework/src/onos/apps/flowanalyzer/src/test/java/org/onosproject/flowanalyzer/MockFlowRuleService.java
new file mode 100644
index 00000000..40bb0043
--- /dev/null
+++ b/framework/src/onos/apps/flowanalyzer/src/test/java/org/onosproject/flowanalyzer/MockFlowRuleService.java
@@ -0,0 +1,103 @@
+package org.onosproject.flowanalyzer;
+
+import com.google.common.collect.Sets;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.flow.DefaultFlowEntry;
+import org.onosproject.net.flow.FlowEntry;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleOperations;
+import org.onosproject.net.flow.FlowRuleServiceAdapter;
+
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.stream.Collectors;
+
+/**
+ * Created by nikcheerla on 7/20/15.
+ */
+
+public class MockFlowRuleService extends FlowRuleServiceAdapter {
+
+ final Set<FlowRule> flows = Sets.newHashSet();
+ boolean success;
+
+ int errorFlow = -1;
+ public void setErrorFlow(int errorFlow) {
+ this.errorFlow = errorFlow;
+ }
+
+ public void setFuture(boolean success) {
+ this.success = success;
+ }
+
+ @Override
+ public void apply(FlowRuleOperations ops) {
+ AtomicBoolean thisSuccess = new AtomicBoolean(success);
+ ops.stages().forEach(stage -> stage.forEach(flow -> {
+ if (errorFlow == flow.rule().id().value()) {
+ thisSuccess.set(false);
+ } else {
+ switch (flow.type()) {
+ case ADD:
+ case MODIFY: //TODO is this the right behavior for modify?
+ flows.add(flow.rule());
+ break;
+ case REMOVE:
+ flows.remove(flow.rule());
+ break;
+ default:
+ break;
+ }
+ }
+ }));
+ if (thisSuccess.get()) {
+ ops.callback().onSuccess(ops);
+ } else {
+ ops.callback().onError(ops);
+ }
+ }
+
+ @Override
+ public int getFlowRuleCount() {
+ return flows.size();
+ }
+
+ @Override
+ public Iterable<FlowEntry> getFlowEntries(DeviceId deviceId) {
+ return flows.stream()
+ .filter(flow -> flow.deviceId().equals(deviceId))
+ .map(DefaultFlowEntry::new)
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public void applyFlowRules(FlowRule... flowRules) {
+ for (FlowRule flow : flowRules) {
+ flows.add(flow);
+ }
+ }
+
+ @Override
+ public void removeFlowRules(FlowRule... flowRules) {
+ for (FlowRule flow : flowRules) {
+ flows.remove(flow);
+ }
+ }
+
+ @Override
+ public Iterable<FlowRule> getFlowRulesById(ApplicationId id) {
+ return flows.stream()
+ .filter(flow -> flow.appId() == id.id())
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public Iterable<FlowRule> getFlowRulesByGroupId(ApplicationId appId, short groupId) {
+ return flows.stream()
+ .filter(flow -> flow.appId() == appId.id() && flow.groupId().id() == groupId)
+ .collect(Collectors.toList());
+ }
+}
+
+
diff --git a/framework/src/onos/apps/flowanalyzer/src/test/java/org/onosproject/flowanalyzer/MockLinkService.java b/framework/src/onos/apps/flowanalyzer/src/test/java/org/onosproject/flowanalyzer/MockLinkService.java
new file mode 100644
index 00000000..2171c6f8
--- /dev/null
+++ b/framework/src/onos/apps/flowanalyzer/src/test/java/org/onosproject/flowanalyzer/MockLinkService.java
@@ -0,0 +1,183 @@
+package org.onosproject.flowanalyzer;
+
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.link.LinkServiceAdapter;
+import org.onosproject.net.topology.TopologyEdge;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.ElementId;
+import org.onosproject.net.HostId;
+import org.onosproject.net.Link;
+import org.onosproject.net.Annotations;
+import org.onosproject.net.provider.ProviderId;
+import org.onosproject.net.topology.TopologyVertex;
+
+import java.util.Set;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.HashSet;
+
+import static org.onosproject.net.Link.State.ACTIVE;
+
+
+/**
+ * Created by nikcheerla on 7/21/15.
+ */
+public class MockLinkService extends LinkServiceAdapter {
+ DefaultMutableTopologyGraph createdGraph = new DefaultMutableTopologyGraph(new HashSet<>(), new HashSet<>());
+ List<Link> links = new ArrayList<>();
+
+ @Override
+ public int getLinkCount() {
+ return links.size();
+ }
+
+ @Override
+ public Iterable<Link> getLinks() {
+ return links;
+ }
+
+ @Override
+ public Set<Link> getDeviceLinks(DeviceId deviceId) {
+ Set<Link> egress = getDeviceEgressLinks(deviceId);
+ egress.addAll(getDeviceIngressLinks(deviceId));
+ return egress;
+ }
+
+ @Override
+ public Set<Link> getDeviceEgressLinks(DeviceId deviceId) {
+ Set<Link> setL = new HashSet<>();
+ for (Link l: links) {
+ if (l.src().elementId() instanceof DeviceId && l.src().deviceId().equals(deviceId)) {
+ setL.add(l);
+ }
+ }
+ return setL;
+ }
+
+ @Override
+ public Set<Link> getDeviceIngressLinks(DeviceId deviceId) {
+ Set<Link> setL = new HashSet<>();
+ for (Link l: links) {
+ if (l.dst().elementId() instanceof DeviceId && l.dst().deviceId().equals(deviceId)) {
+ setL.add(l);
+ }
+ }
+ return setL;
+ }
+
+
+ @Override
+ public Set<Link> getEgressLinks(ConnectPoint pt) {
+ Set<Link> setL = new HashSet<>();
+ for (Link l: links) {
+ if (l.src().equals(pt)) {
+ setL.add(l);
+ }
+ }
+ return setL;
+ }
+
+ @Override
+ public Set<Link> getIngressLinks(ConnectPoint pt) {
+ Set<Link> setL = new HashSet<>();
+ for (Link l: links) {
+ if (l.dst().equals(pt)) {
+ setL.add(l);
+ }
+ }
+ return setL;
+ }
+
+ @Override
+ public Set<Link> getLinks(ConnectPoint pt) {
+ Set<Link> setL = new HashSet<>();
+ for (Link l: links) {
+ if (l.src().equals(pt) || l.dst().equals(pt)) {
+ setL.add(l);
+ }
+ }
+ return setL;
+ }
+
+ public void addLink(String device, long port, String device2, long port2) {
+ ElementId d1;
+ if (device.charAt(0) == 'H') {
+ device = device.substring(1, device.length());
+ d1 = HostId.hostId(device);
+ } else {
+ d1 = DeviceId.deviceId(device);
+ }
+
+ ElementId d2;
+ if (device2.charAt(0) == 'H') {
+ d2 = HostId.hostId(device2.substring(1, device2.length()));
+ } else {
+ d2 = DeviceId.deviceId(device2);
+ }
+
+ ConnectPoint src = new ConnectPoint(d1, PortNumber.portNumber(port));
+ ConnectPoint dst = new ConnectPoint(d2, PortNumber.portNumber(port2));
+ Link curLink;
+ curLink = new Link() {
+ @Override
+ public ConnectPoint src() {
+ return src;
+ }
+
+ @Override
+ public ConnectPoint dst() {
+ return dst;
+ }
+
+ @Override
+ public boolean isDurable() {
+ return true;
+ }
+
+ @Override
+ public Annotations annotations() {
+ return null;
+ }
+
+ @Override
+ public Type type() {
+ return null;
+ }
+
+ @Override
+ public ProviderId providerId() {
+ return null;
+ }
+
+ @Override
+ public State state() {
+ return ACTIVE;
+ }
+ };
+ links.add(curLink);
+ if (d1 instanceof DeviceId && d2 instanceof DeviceId) {
+ TopologyVertex v1 = () -> (DeviceId) d1, v2 = () -> (DeviceId) d2;
+ createdGraph.addVertex(v1);
+ createdGraph.addVertex(v2);
+ createdGraph.addEdge(new TopologyEdge() {
+ @Override
+ public Link link() {
+ return curLink;
+ }
+
+ @Override
+ public TopologyVertex src() {
+ return v1;
+ }
+
+ @Override
+ public TopologyVertex dst() {
+ return v2;
+ }
+ });
+ }
+ }
+
+
+}
diff --git a/framework/src/onos/apps/flowanalyzer/src/test/java/org/onosproject/flowanalyzer/MockTopologyService.java b/framework/src/onos/apps/flowanalyzer/src/test/java/org/onosproject/flowanalyzer/MockTopologyService.java
new file mode 100644
index 00000000..0d25c977
--- /dev/null
+++ b/framework/src/onos/apps/flowanalyzer/src/test/java/org/onosproject/flowanalyzer/MockTopologyService.java
@@ -0,0 +1,21 @@
+package org.onosproject.flowanalyzer;
+import org.onosproject.net.topology.Topology;
+import org.onosproject.net.topology.TopologyGraph;
+import org.onosproject.net.topology.TopologyServiceAdapter;
+
+
+/**
+ * Created by nikcheerla on 7/20/15.
+ */
+public class MockTopologyService extends TopologyServiceAdapter {
+ TopologyGraph cur;
+
+ public MockTopologyService(TopologyGraph g) {
+ cur = g;
+ }
+
+ @Override
+ public TopologyGraph getGraph(Topology topology) {
+ return cur;
+ }
+}
diff --git a/framework/src/onos/apps/igmp/pom.xml b/framework/src/onos/apps/igmp/pom.xml
new file mode 100644
index 00000000..7980d2c0
--- /dev/null
+++ b/framework/src/onos/apps/igmp/pom.xml
@@ -0,0 +1,117 @@
+<?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>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-apps</artifactId>
+ <version>1.4.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>onos-app-igmp</artifactId>
+ <packaging>bundle</packaging>
+
+ <description>Internet Group Message Protocol</description>
+
+ <properties>
+ <onos.app.name>org.onosproject.igmp</onos.app.name>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-cli</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onlab-osgi</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onlab-junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <!-- This is needed by ComponentContext, used for tunable configuration -->
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.scr.annotations</artifactId>
+ <version>1.9.8</version>
+ <scope>provided</scope>
+ </dependency>
+
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-SymbolicName>
+ ${project.groupId}.${project.artifactId}
+ </Bundle-SymbolicName>
+ <Import-Package>
+ org.slf4j,
+ org.osgi.framework,
+ org.apache.commons.lang.math.*,
+ com.google.common.*,
+ org.onlab.packet.*,
+ org.onlab.rest.*,
+ org.onosproject.*,
+ org.onosproject.mfwd.impl.*;
+ org.onlab.util.*,
+ org.jboss.netty.util.*
+ </Import-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.5.1</version>
+ <configuration>
+ <source>1.8</source>
+ <target>1.8</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/framework/src/onos/apps/igmp/src/main/java/org/onosproject/igmp/impl/IGMPComponent.java b/framework/src/onos/apps/igmp/src/main/java/org/onosproject/igmp/impl/IGMPComponent.java
new file mode 100644
index 00000000..ae539c62
--- /dev/null
+++ b/framework/src/onos/apps/igmp/src/main/java/org/onosproject/igmp/impl/IGMPComponent.java
@@ -0,0 +1,155 @@
+/*
+ * 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.igmp.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.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.IPv4;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.IGMP;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.packet.InboundPacket;
+import org.onosproject.net.packet.PacketContext;
+import org.onosproject.net.packet.PacketPriority;
+import org.onosproject.net.packet.PacketProcessor;
+import org.onosproject.net.packet.PacketService;
+import org.slf4j.Logger;
+
+/**
+ * Internet Group Management Protocol.
+ */
+@Component(immediate = true)
+public class IGMPComponent {
+ private final Logger log = getLogger(getClass());
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected PacketService packetService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CoreService coreService;
+
+ private IGMPPacketProcessor processor = new IGMPPacketProcessor();
+ private static ApplicationId appId;
+
+ @Activate
+ public void activate() {
+ appId = coreService.registerApplication("org.onosproject.igmp");
+
+ packetService.addProcessor(processor, PacketProcessor.director(1));
+
+ // Build a traffic selector for all multicast traffic
+ TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+ selector.matchEthType(Ethernet.TYPE_IPV4);
+ selector.matchIPProtocol(IPv4.PROTOCOL_IGMP);
+ packetService.requestPackets(selector.build(), PacketPriority.REACTIVE, appId);
+
+ log.info("Started");
+ }
+
+ @Deactivate
+ public void deactivate() {
+ packetService.removeProcessor(processor);
+ processor = null;
+ log.info("Stopped");
+ }
+
+ /**
+ * Packet processor responsible for handling IGMP packets.
+ */
+ private class IGMPPacketProcessor implements PacketProcessor {
+
+ @Override
+ public void process(PacketContext context) {
+ // Stop processing if the packet has been handled, since we
+ // can't do any more to it.
+ if (context.isHandled()) {
+ return;
+ }
+
+ InboundPacket pkt = context.inPacket();
+ Ethernet ethPkt = pkt.parsed();
+ if (ethPkt == null) {
+ return;
+ }
+
+ /*
+ * IPv6 MLD packets are handled by ICMP6. We'll only deal
+ * with IPv4.
+ */
+ if (ethPkt.getEtherType() != Ethernet.TYPE_IPV4) {
+ return;
+ }
+
+ IPv4 ip = (IPv4) ethPkt.getPayload();
+ IpAddress gaddr = IpAddress.valueOf(ip.getDestinationAddress());
+ IpAddress saddr = Ip4Address.valueOf(ip.getSourceAddress());
+ log.debug("Packet (" + saddr.toString() + ", " + gaddr.toString() +
+ "\tingress port: " + context.inPacket().receivedFrom().toString());
+
+ if (ip.getProtocol() != IPv4.PROTOCOL_IGMP) {
+ log.error("IGMP Picked up a non IGMP packet.");
+ return;
+ }
+
+ IpPrefix mcast = IpPrefix.valueOf("224.0.0.0/4");
+ if (!mcast.contains(gaddr)) {
+ log.error("IGMP Picked up a non multicast packet.");
+ return;
+ }
+
+ if (mcast.contains(saddr)) {
+ log.error("IGMP Picked up a packet with a multicast source address.");
+ return;
+ }
+ IpPrefix spfx = IpPrefix.valueOf(saddr, 32);
+ IpPrefix gpfx = IpPrefix.valueOf(gaddr, 32);
+
+ IGMP igmp = (IGMP) ip.getPayload();
+ switch (igmp.getIgmpType()) {
+
+ case IGMP.TYPE_IGMPV3_MEMBERSHIP_REPORT:
+ IGMPProcessMembership.processMembership(igmp, pkt.receivedFrom());
+ break;
+
+ case IGMP.TYPE_IGMPV3_MEMBERSHIP_QUERY:
+ IGMPProcessQuery.processQuery(igmp, pkt.receivedFrom());
+ break;
+
+ case IGMP.TYPE_IGMPV1_MEMBERSHIP_REPORT:
+ case IGMP.TYPE_IGMPV2_MEMBERSHIP_REPORT:
+ case IGMP.TYPE_IGMPV2_LEAVE_GROUP:
+ log.debug("IGMP version 1 & 2 message types are not currently supported. Message type: " +
+ igmp.getIgmpType());
+ break;
+
+ default:
+ log.debug("Unkown IGMP message type: " + igmp.getIgmpType());
+ break;
+ }
+ }
+ }
+}
diff --git a/framework/src/onos/apps/igmp/src/main/java/org/onosproject/igmp/impl/IGMPProcessMembership.java b/framework/src/onos/apps/igmp/src/main/java/org/onosproject/igmp/impl/IGMPProcessMembership.java
new file mode 100644
index 00000000..3d7d6033
--- /dev/null
+++ b/framework/src/onos/apps/igmp/src/main/java/org/onosproject/igmp/impl/IGMPProcessMembership.java
@@ -0,0 +1,39 @@
+/*
+ * 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.igmp.impl;
+
+import org.onlab.packet.IGMP;
+import org.onosproject.net.ConnectPoint;
+
+/**
+ * Process an IGMP Membership Report.
+ */
+public final class IGMPProcessMembership {
+
+ // Hide the default constructor.
+ private IGMPProcessMembership() {
+ }
+
+ /**
+ * Process the IGMP Membership report.
+ *
+ * @param igmp the deserialized IGMP message.
+ * @param receivedFrom the ConnectPoint this message came from.
+ */
+ public static void processMembership(IGMP igmp, ConnectPoint receivedFrom) {
+ }
+
+}
diff --git a/framework/src/onos/apps/igmp/src/main/java/org/onosproject/igmp/impl/IGMPProcessQuery.java b/framework/src/onos/apps/igmp/src/main/java/org/onosproject/igmp/impl/IGMPProcessQuery.java
new file mode 100644
index 00000000..eb256796
--- /dev/null
+++ b/framework/src/onos/apps/igmp/src/main/java/org/onosproject/igmp/impl/IGMPProcessQuery.java
@@ -0,0 +1,39 @@
+/*
+ * 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.igmp.impl;
+
+import org.onlab.packet.IGMP;
+import org.onosproject.net.ConnectPoint;
+
+/**
+ * Process IGMP Query messages.
+ */
+public final class IGMPProcessQuery {
+
+ // Hide the default constructor.
+ private IGMPProcessQuery() {
+ }
+
+ /**
+ * Process the IGMP Membership Query message.
+ *
+ * @param igmp The deserialzed IGMP message
+ * @param receivedFrom the ConnectPoint this message came from.
+ */
+ public static void processQuery(IGMP igmp, ConnectPoint receivedFrom) {
+ }
+
+}
diff --git a/framework/src/onos/apps/mfwd/pom.xml b/framework/src/onos/apps/mfwd/pom.xml
new file mode 100644
index 00000000..835de836
--- /dev/null
+++ b/framework/src/onos/apps/mfwd/pom.xml
@@ -0,0 +1,142 @@
+<?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/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-mfwd</artifactId>
+ <packaging>bundle</packaging>
+
+ <description>Multicast forwarding application</description>
+
+ <properties>
+ <onos.app.name>org.onosproject.mfwd</onos.app.name>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-cli</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.netty</groupId>
+ <artifactId>netty</artifactId>
+ <version>3.9.0.Final</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.karaf.shell</groupId>
+ <artifactId>org.apache.karaf.shell.console</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onlab-rest</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-rest</artifactId>
+ <version>${project.version}</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.onosproject</groupId>
+ <artifactId>onlab-junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.easymock</groupId>
+ <artifactId>easymock</artifactId>
+ <scope>test</scope>
+ </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,
+ org.apache.commons.lang.math.*,
+ 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/cli/McastDeleteCommand.java b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/cli/McastDeleteCommand.java
new file mode 100644
index 00000000..ae5d9e93
--- /dev/null
+++ b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/cli/McastDeleteCommand.java
@@ -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.mfwd.cli;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.mfwd.impl.McastRouteTable;
+
+/**
+ * Deletes a multicast route.
+ */
+@Command(scope = "onos", name = "mcast-delete",
+ description = "Delete a multicast route flow")
+public class McastDeleteCommand extends AbstractShellCommand {
+
+ @Argument(index = 0, name = "sAddr",
+ description = "IP Address of the multicast source. '*' can be used for any source (*, G) entry",
+ required = true, multiValued = false)
+ String sAddr = null;
+
+ @Argument(index = 1, name = "gAddr",
+ description = "IP Address of the multicast group",
+ required = true, multiValued = false)
+ String gAddr = null;
+
+ @Override
+ protected void execute() {
+ McastRouteTable mrib = McastRouteTable.getInstance();
+ mrib.removeRoute(sAddr, gAddr);
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/cli/McastJoinCommand.java b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/cli/McastJoinCommand.java
new file mode 100644
index 00000000..7260fde5
--- /dev/null
+++ b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/cli/McastJoinCommand.java
@@ -0,0 +1,72 @@
+/*
+ * 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.mfwd.cli;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+
+import org.onosproject.mfwd.impl.McastConnectPoint;
+import org.onosproject.mfwd.impl.McastRouteBase;
+import org.onosproject.mfwd.impl.McastRouteTable;
+
+/**
+ * Installs a source, multicast group flow.
+ */
+@Command(scope = "onos", name = "mcast-join",
+ description = "Installs a source, multicast group flow")
+public class McastJoinCommand extends AbstractShellCommand {
+
+ @Argument(index = 0, name = "sAddr",
+ description = "IP Address of the multicast source. '*' can be used for any source (*, G) entry",
+ required = true, multiValued = false)
+ String sAddr = null;
+
+ @Argument(index = 1, name = "gAddr",
+ description = "IP Address of the multicast group",
+ required = true, multiValued = false)
+ String gAddr = null;
+
+ @Argument(index = 2, name = "ingressPort",
+ description = "Ingress port and Egress ports",
+ required = false, multiValued = false)
+ String ingressPort = null;
+
+ @Argument(index = 3, name = "ports",
+ description = "Ingress port and Egress ports",
+ required = false, multiValued = true)
+ String[] ports = null;
+
+ @Override
+ protected void execute() {
+ McastRouteTable mrib = McastRouteTable.getInstance();
+ McastRouteBase mr = mrib.addRoute(sAddr, gAddr);
+
+ // Port format "of:0000000000000023/4"
+ if (ingressPort != null) {
+ String inCP = ingressPort;
+ log.debug("Ingress port provided: " + inCP);
+ mr.addIngressPoint(inCP);
+ }
+
+ for (int i = 0; i < ports.length; i++) {
+ String egCP = ports[i];
+ log.debug("Egress port provided: " + egCP);
+ mr.addEgressPoint(egCP, McastConnectPoint.JoinSource.STATIC);
+ }
+ print("Added the mcast route");
+ }
+}
diff --git a/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/cli/McastShowCommand.java b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/cli/McastShowCommand.java
new file mode 100644
index 00000000..7fa3a13a
--- /dev/null
+++ b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/cli/McastShowCommand.java
@@ -0,0 +1,62 @@
+/*
+ * 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.mfwd.cli;
+
+import org.apache.karaf.shell.commands.Command;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.fasterxml.jackson.databind.JsonNode;
+
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.mfwd.impl.McastRouteTable;
+import org.onosproject.mfwd.impl.MRibCodec;
+
+import org.slf4j.Logger;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Displays the source, multicast group flows entries.
+ */
+@Command(scope = "onos", name = "mcast-show", description = "Displays the source, multicast group flows")
+public class McastShowCommand extends AbstractShellCommand {
+
+ private final Logger log = getLogger(getClass());
+ private static final String MCAST_GROUP = "mcastgroup";
+
+ @Override
+ protected void execute() {
+ McastRouteTable mrt = McastRouteTable.getInstance();
+ if (outputJson()) {
+ print("%s", json(mrt));
+ } else {
+ printMrib4(mrt);
+ }
+ }
+
+ public JsonNode json(McastRouteTable mrt) {
+ ObjectNode pushContent = new MRibCodec().encode(mrt , this);
+ return pushContent;
+ }
+
+ /**
+ * Displays multicast route table entries.
+ *
+ * @param mrt Mutlicast Route Table
+ */
+ protected void printMrib4(McastRouteTable mrt) {
+ print(mrt.printMcastRouteTable());
+ }
+}
diff --git a/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/cli/package-info.java b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/cli/package-info.java
new file mode 100644
index 00000000..7b5ed39a
--- /dev/null
+++ b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/cli/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * Sample Multicast forwarding framework using intents.
+ */
+package org.onosproject.mfwd.cli;
+
diff --git a/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/MRibCodec.java b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/MRibCodec.java
new file mode 100644
index 00000000..c4f18527
--- /dev/null
+++ b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/MRibCodec.java
@@ -0,0 +1,211 @@
+/*
+ * 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.mfwd.impl;
+
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+
+import org.onlab.packet.IpPrefix;
+
+import java.util.Set;
+import java.util.Map;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Optional;
+
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+
+import org.slf4j.Logger;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Encode and Decode the Multicast Route Table in JSON for CLI and REST commands.
+ */
+public class MRibCodec extends JsonCodec<McastRouteTable> {
+
+ private final Logger log = getLogger(getClass());
+ private static final String SOURCE_ADDRESS = "sourceAddress";
+ private static final String GROUP_ADDRESS = "groupAddress";
+ private static final String INGRESS_POINT = "ingressPoint";
+ private static final String EGRESS_POINT = "egressPoint";
+ private static final String MCASTCONNECTPOINT = "McastConnectPoint";
+ private static final String ELEMENTID = "elementId";
+ private static final String PORTNUMBER = "portNumber";
+ private static final String MCAST_GROUP = "mcastGroup";
+
+ /**
+ * Encode the MRIB into json format.
+ *
+ * @param mcastRouteTable McastRouteTable
+ * @param context CodecContext
+ * @return result ObjectNode
+ */
+ @Override
+ public ObjectNode encode(McastRouteTable mcastRouteTable, CodecContext context) {
+
+ final JsonNodeFactory nodeFactory = JsonNodeFactory.instance;
+ final ObjectNode macastRouteTabNode = nodeFactory.objectNode();
+ ArrayNode mcastGroupNode = context.mapper().createArrayNode();
+ Optional<McastRouteTable> mcastRouteTabOpt = Optional.ofNullable(mcastRouteTable);
+
+ //checking whether the McastRouteTable is present.
+ if (mcastRouteTabOpt.isPresent()) {
+ Map<IpPrefix, McastRouteGroup> mrib4 = mcastRouteTabOpt.get().getMrib4();
+ Optional<Map<IpPrefix, McastRouteGroup>> mrib4Opt = Optional.ofNullable(mrib4);
+
+ //checking whether the mrib4 is present.
+ if (mrib4Opt.isPresent()) {
+
+ for (McastRouteGroup mg : mrib4Opt.get().values()) {
+ Collection<McastRouteSource> mcastRoute = mg.getSources().values();
+ Optional<Collection<McastRouteSource>> mcastRouteOpt = Optional.ofNullable(mcastRoute);
+
+ //checking whether the McastRouteSource List is present.
+ if (mcastRouteOpt.isPresent()) {
+ for (McastRouteSource mcastRouteSource : mcastRouteOpt.get()) {
+ mcastGroupNode.add(createMcastGroupNode(mcastRouteSource, context));
+ }
+ macastRouteTabNode.put(MCAST_GROUP, mcastGroupNode);
+ }
+ }
+ }
+ }
+ return macastRouteTabNode;
+ }
+ /**
+ * Method for creating the McastGroup object node.
+ *
+ * @param mcastRouteSource McastRouteSource
+ */
+ private ObjectNode createMcastGroupNode(McastRouteSource mcastRouteSource, CodecContext context) {
+
+ final ObjectNode mcastGroupNode = context.mapper().createObjectNode();
+ final ObjectNode ingressNode = context.mapper().createObjectNode();
+ final ObjectNode egressNode = context.mapper().createObjectNode();
+ final ArrayNode jsonLabelIds = context.mapper().createArrayNode();
+ final String sAddr = mcastRouteSource.getSaddr().toString();
+ final String gAddr = mcastRouteSource.getGaddr().toString();
+
+ Optional<String> saddrOpt = Optional.ofNullable(sAddr);
+ Optional<String> gaddrOpt = Optional.ofNullable(gAddr);
+
+ //checking source address and group address are present.
+ if (saddrOpt.isPresent() && gaddrOpt.isPresent()) {
+ mcastGroupNode.put(SOURCE_ADDRESS, saddrOpt.get().toString());
+ mcastGroupNode.put(GROUP_ADDRESS, gaddrOpt.get().toString());
+ McastConnectPoint mcastIngCP = mcastRouteSource.getIngressPoint();
+ Optional<McastConnectPoint> mcastIngCPOpt = Optional.ofNullable(mcastIngCP);
+
+ //checking whether the ingress connection point is present.
+ if (mcastIngCPOpt.isPresent()) {
+ ingressNode.put(MCASTCONNECTPOINT, mcastConnectPoint(mcastIngCPOpt.get(), context));
+ }
+
+ mcastGroupNode.put(INGRESS_POINT , ingressNode);
+ Set<McastConnectPoint> mcastEgCPSet = mcastRouteSource.getEgressPoints();
+ Optional<Set<McastConnectPoint>> mcastEgCPOpt = Optional.ofNullable(mcastEgCPSet);
+
+ //checking whether the egress connection points are present.
+ if (mcastEgCPOpt.isPresent()) {
+ for (final McastConnectPoint mcastConnectPoint : mcastEgCPOpt.get()) {
+ jsonLabelIds.add(mcastConnectPoint(mcastConnectPoint, context));
+ }
+ }
+
+ egressNode.put(MCASTCONNECTPOINT , jsonLabelIds);
+ mcastGroupNode.put(EGRESS_POINT , egressNode);
+ }
+ return mcastGroupNode;
+ }
+
+ /**
+ * Method for creating the McastConnectPoint object node.
+ *
+ * @param mcastConnectPoint McastConnectPoint
+ * @param context CodecContext
+ * @return mcastCpNode ObjectNode
+ */
+ private ObjectNode mcastConnectPoint(McastConnectPoint mcastConnectPoint, CodecContext context) {
+ final ObjectNode mcastCpNode = context.mapper().createObjectNode();
+ mcastCpNode.put(ELEMENTID , mcastConnectPoint.getConnectPoint().elementId().toString());
+ mcastCpNode.put(PORTNUMBER , mcastConnectPoint.getConnectPoint().port().toLong());
+ return mcastCpNode;
+ }
+
+ /**
+ * Decode json format and insert into the flow table.
+ *
+ * @param json ObjectNode
+ * @param context CodecContext
+ * @return mr McastRouteBase
+ */
+ @Override
+ public McastRouteTable decode(ObjectNode json, CodecContext context) {
+
+ String macAddr = null;
+ String portNo = null;
+ String sAddr = json.path(SOURCE_ADDRESS).asText();
+ String gAddr = json.path(GROUP_ADDRESS).asText();
+ JsonNode inPntObjNode = (JsonNode) json.path(INGRESS_POINT);
+ JsonNode egPntArrNode = (JsonNode) json.path(EGRESS_POINT);
+
+ log.debug("sAddr :" + sAddr + " gAddr :" + gAddr + " inPntObjNode :" + inPntObjNode);
+ log.debug("egPntArrNode :" + egPntArrNode.toString());
+
+ McastRouteTable mrib = McastRouteTable.getInstance();
+ McastRouteBase mr = mrib.addRoute(sAddr, gAddr);
+ Optional<JsonNode> inPntOpt = Optional.ofNullable(inPntObjNode);
+
+ if (inPntOpt.isPresent()) {
+
+ JsonNode inMcastCP = inPntOpt.get().path(MCASTCONNECTPOINT);
+ Optional<JsonNode> inCpOpt = Optional.ofNullable(inMcastCP);
+
+ if (inCpOpt.isPresent()) {
+ macAddr = inCpOpt.get().path(ELEMENTID).asText();
+ portNo = inCpOpt.get().path(PORTNUMBER).asText();
+ mr.addIngressPoint(macAddr + "/" + Long.parseLong(portNo));
+ }
+ }
+
+ Optional<JsonNode> egPntOpt = Optional.ofNullable(egPntArrNode);
+
+ if (egPntOpt.isPresent()) {
+ JsonNode egMcastCP = egPntOpt.get().path(MCASTCONNECTPOINT);
+ Optional<JsonNode> egMcCpOpt = Optional.ofNullable(egMcastCP);
+
+ if (egMcCpOpt.isPresent()) {
+ Iterator<JsonNode> egCpIt = egMcCpOpt.get().elements();
+
+ while (egCpIt.hasNext()) {
+
+ JsonNode egMcastCPObj = egCpIt.next();
+ Optional<JsonNode> egMcCpObOpt = Optional.ofNullable(egMcastCPObj);
+ if (egMcCpObOpt.isPresent()) {
+ macAddr = egMcCpObOpt.get().path(ELEMENTID).asText();
+ portNo = egMcCpObOpt.get().path(PORTNUMBER).asText();
+ log.debug("macAddr egPort : " + macAddr + " portNo egPort :" + portNo);
+ mr.addEgressPoint(macAddr + "/" + Long.parseLong(portNo), McastConnectPoint.JoinSource.STATIC);
+ }
+ }
+ }
+ }
+ return mrib;
+ }
+}
diff --git a/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastConnectPoint.java b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastConnectPoint.java
new file mode 100644
index 00000000..e2a6ff0d
--- /dev/null
+++ b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastConnectPoint.java
@@ -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.mfwd.impl;
+
+import org.onosproject.net.ConnectPoint;
+import java.util.EnumSet;
+import java.util.Set;
+
+/**
+ * Mulitcast ConnectPoint adds a variable to track the usage
+ * of these multicast endpoints.
+ */
+public class McastConnectPoint {
+
+ private ConnectPoint connectPoint;
+
+ public enum JoinSource {
+ STATIC, IGMP, PIM;
+ }
+
+ public EnumSet<JoinSource> interest = EnumSet.noneOf(JoinSource.class);
+
+ public McastConnectPoint(ConnectPoint cp) {
+ this.connectPoint = cp;
+ }
+
+ public McastConnectPoint(ConnectPoint cp, JoinSource src) {
+ this.connectPoint = cp;
+ interest.add(src);
+ }
+
+ public McastConnectPoint(String connectPoint, JoinSource src) {
+ ConnectPoint cp = ConnectPoint.deviceConnectPoint(connectPoint);
+ this.connectPoint = cp;
+ this.interest.add(src);
+ }
+
+ /**
+ * Get the connect point.
+ *
+ * @return connectPoint
+ */
+ public ConnectPoint getConnectPoint() {
+ return connectPoint;
+ }
+
+ /**
+ * Get the sources of interest for this egressPoint.
+ *
+ * @return interest flags
+ */
+ public Set<JoinSource> getInterest() {
+ return interest;
+ }
+}
diff --git a/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastForwarding.java b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastForwarding.java
new file mode 100644
index 00000000..f5bd1e01
--- /dev/null
+++ b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastForwarding.java
@@ -0,0 +1,237 @@
+/*
+ * 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.mfwd.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.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.IPv4;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.ConnectPoint;
+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.packet.DefaultOutboundPacket;
+import org.onosproject.net.packet.InboundPacket;
+import org.onosproject.net.packet.OutboundPacket;
+import org.onosproject.net.packet.PacketContext;
+import org.onosproject.net.packet.PacketPriority;
+import org.onosproject.net.packet.PacketProcessor;
+import org.onosproject.net.packet.PacketService;
+import org.slf4j.Logger;
+
+/**
+ * WORK-IN-PROGRESS: The multicast forwarding application using intent framework.
+ */
+@Component(immediate = true)
+public class McastForwarding {
+
+ private final Logger log = getLogger(getClass());
+ private final IpPrefix mcast = IpPrefix.valueOf("224.0.0.0/4");
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected PacketService packetService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CoreService coreService;
+
+ private ReactivePacketProcessor processor = new ReactivePacketProcessor();
+ private McastRouteTable mrib;
+ private static ApplicationId appId;
+
+ /**
+ * Active MulticastForwardingIntent.
+ */
+ @Activate
+ public void activate() {
+ appId = coreService.registerApplication("org.onosproject.mfwd");
+
+ packetService.addProcessor(processor, PacketProcessor.director(2));
+
+ // Build a traffic selector for all multicast traffic
+ TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+ selector.matchEthType(Ethernet.TYPE_IPV4);
+ selector.matchIPDst(mcast);
+ packetService.requestPackets(selector.build(), PacketPriority.REACTIVE, appId);
+
+ mrib = McastRouteTable.getInstance();
+ log.info("Started");
+ }
+
+ /**
+ * Deactivate Multicast Forwarding Intent.
+ */
+ @Deactivate
+ public void deactivate() {
+ packetService.removeProcessor(processor);
+ processor = null;
+ log.info("Stopped");
+ }
+
+ /**
+ * Get the application ID, used by the McastIntentManager.
+ *
+ * @return the application ID
+ */
+ public static ApplicationId getAppId() {
+ return appId;
+ }
+
+ /**
+ * Packet processor responsible for forwarding packets along their paths.
+ */
+ private class ReactivePacketProcessor implements PacketProcessor {
+
+ /**
+ * Process incoming packets.
+ *
+ * @param context packet processing context
+ */
+ @Override
+ public void process(PacketContext context) {
+ // Stop processing if the packet has been handled, since we
+ // can't do any more to it.
+ if (context.isHandled()) {
+ return;
+ }
+
+ InboundPacket pkt = context.inPacket();
+ Ethernet ethPkt = pkt.parsed();
+
+ if (ethPkt == null) {
+ return;
+ }
+
+ if (ethPkt.getEtherType() != Ethernet.TYPE_IPV4 &&
+ ethPkt.getEtherType() != Ethernet.TYPE_IPV6) {
+ return;
+ }
+
+ if (ethPkt.getEtherType() == Ethernet.TYPE_IPV6) {
+ // Ignore ipv6 at the moment.
+ return;
+ }
+
+ IPv4 ip = (IPv4) ethPkt.getPayload();
+ IpAddress gaddr = IpAddress.valueOf(ip.getDestinationAddress());
+ IpAddress saddr = Ip4Address.valueOf(ip.getSourceAddress());
+
+ log.debug("Packet ({}, {}) has been punted\n" +
+ "\tingress port: {}\n",
+ saddr.toString(),
+ gaddr.toString(),
+ context.inPacket().receivedFrom().toString());
+
+ if (!mcast.contains(gaddr)) {
+ // Yikes, this is a bad group address
+ return;
+ }
+
+ if (mcast.contains(saddr)) {
+ // Yikes, the source address is multicast
+ return;
+ }
+
+ IpPrefix spfx = IpPrefix.valueOf(saddr, 32);
+ IpPrefix gpfx = IpPrefix.valueOf(gaddr, 32);
+
+ /*
+ * Do a best match lookup on the (s, g) of the packet. If an entry does
+ * not exist create one and store it's incoming connect point.
+ *
+ * The connect point is deviceId / portId that the packet entered
+ * the SDN network. This differs from traditional mcast where the
+ * ingress port would be a specific device.
+ */
+ McastRoute entry = mrib.findBestMatch(spfx, gpfx);
+ if (entry == null || entry.getSaddr().equals(IPv4.fromIPv4Address(0))) {
+
+ /*
+ * Create an entry that we can fast drop.
+ */
+ entry = mrib.addRoute(spfx, gpfx);
+ entry.addIngressPoint(context.inPacket().receivedFrom());
+ }
+
+ /*
+ * TODO: If we do not have an ingress or any egress connect points we
+ * should set up a fast drop entry.
+ */
+ if (entry.getIngressPoint() == null) {
+ return;
+ }
+
+ if (entry.getEgressPoints().isEmpty()) {
+ return;
+ }
+
+ /*
+ * This is odd, we should not have received a punted packet if an
+ * intent was installed unless the intent was not installed
+ * correctly. However, we are seeing packets get punted after
+ * the intent has been installed.
+ *
+ * Therefore we are going to forward the packets even if they
+ * should have already been forwarded by the intent fabric.
+ */
+ if (entry.getIntentKey() != null) {
+ return;
+ }
+
+ entry.setIntent();
+ McastIntentManager im = McastIntentManager.getInstance();
+ im.setIntent(entry);
+
+ entry.incrementPuntCount();
+
+ // Send the pack out each of the egress devices & port
+ forwardPacketToDst(context, entry);
+ }
+ }
+
+ /**
+ * Forward the packet to it's multicast destinations.
+ *
+ * @param context The packet context
+ * @param entry The multicast route entry matching this packet
+ */
+ private void forwardPacketToDst(PacketContext context, McastRoute entry) {
+
+ // Send the pack out each of the respective egress ports
+ for (ConnectPoint egress : entry.getEgressConnectPoints()) {
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setOutput(egress.port()).build();
+
+ OutboundPacket packet = new DefaultOutboundPacket(
+ egress.deviceId(),
+ treatment,
+ context.inPacket().unparsed());
+
+ packetService.emit(packet);
+ }
+ }
+}
diff --git a/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastIntentManager.java b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastIntentManager.java
new file mode 100644
index 00000000..90f65c94
--- /dev/null
+++ b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastIntentManager.java
@@ -0,0 +1,133 @@
+/*
+ * 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.mfwd.impl;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onlab.packet.Ethernet;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.SinglePointToMultiPointIntent;
+import org.onosproject.net.intent.IntentService;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+
+@Component(immediate = true)
+@Service(value = org.onosproject.mfwd.impl.McastIntentManager.class)
+public class McastIntentManager {
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected IntentService intentService;
+
+ private static McastIntentManager instance;
+
+ public McastIntentManager() {
+ instance = this;
+ }
+
+ /**
+ * Active this component.
+ */
+ @Activate
+ public void activate() { }
+
+ /**
+ * Deactivate this component.
+ */
+ @Deactivate
+ public void deactivate() {
+ withdrawAllIntents();
+ }
+
+ /**
+ * Get instance of this intentManager.
+ *
+ * @return the instance of this intent manager.
+ */
+ public static McastIntentManager getInstance() {
+ if (instance == null) {
+ instance = new McastIntentManager();
+ }
+ return instance;
+ }
+
+ /**
+ * Install the PointToMultipoint forwarding intent.
+ *
+ * @param mroute multicast route entry
+ * @return the intent that has been set or null otherwise
+ */
+ public SinglePointToMultiPointIntent setIntent(McastRoute mroute) {
+ TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+ TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment();
+
+ if (mroute.getIngressPoint() == null ||
+ mroute.getEgressPoints().isEmpty()) {
+ return null;
+ }
+
+ /*
+ * Match the group AND source addresses. We will also check ether type to
+ * determine if we are doing ipv4 or ipv6.
+ *
+ * If we really wanted to be pendantic we could put in a
+ * condition to make sure the ethernet MAC address was also
+ * mcast.
+ */
+ selector.matchEthType(Ethernet.TYPE_IPV4)
+ .matchIPDst(mroute.getGaddr())
+ .matchIPSrc(mroute.getSaddr());
+
+ SinglePointToMultiPointIntent intent =
+ SinglePointToMultiPointIntent.builder()
+ .appId(McastForwarding.getAppId())
+ .selector(selector.build())
+ .treatment(treatment)
+ .ingressPoint(mroute.getIngressPoint().getConnectPoint())
+ .egressPoints(mroute.getEgressConnectPoints()).
+ build();
+
+ intentService.submit(intent);
+ return intent;
+ }
+
+ /**
+ * Withdraw the intent represented by this route.
+ *
+ * @param mroute the mcast route whose intent we want to remove
+ */
+ public void withdrawIntent(McastRouteBase mroute) {
+ Intent intent = intentService.getIntent(mroute.getIntentKey());
+ intentService.withdraw(intent);
+ }
+
+ /**
+ * Withdraw all intents.
+ *
+ * This will be called from the deactivate method so we don't leave
+ * a mess behind us after we leave.
+ */
+ public void withdrawAllIntents() {
+ for (Intent intent : intentService.getIntents()) {
+ intentService.withdraw(intent);
+ }
+ }
+}
diff --git a/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRoute.java b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRoute.java
new file mode 100644
index 00000000..12b7e6d4
--- /dev/null
+++ b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRoute.java
@@ -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.mfwd.impl;
+
+import org.onlab.packet.IpPrefix;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.intent.Key;
+import org.onosproject.net.intent.SinglePointToMultiPointIntent;
+
+import java.util.Set;
+
+/**
+ * This McastRouteBase interface is implemented by the McastRouteBase class which
+ * in turn acts as the base class for both the McastRouteGroup and McastRouteSource.
+ */
+interface McastRoute {
+
+ /**
+ * Gets the group addresses.
+ *
+ * @return group address
+ */
+ public IpPrefix getGaddr();
+
+ /**
+ * Gets the source address.
+ *
+ * @return the source address
+ */
+ public IpPrefix getSaddr();
+
+ /**
+ * Determines if this is an IPv4 multicast route.
+ *
+ * @return true if it is an IPv4 route
+ */
+ public boolean isIp4();
+
+ /**
+ * Determines if this is an IPv6 multicast route.
+ *
+ * @return true if it is an IPv6 route
+ */
+ public boolean isIp6();
+
+ /**
+ * Add the ingress ConnectPoint.
+ *
+ * @param cpstr string representing a ConnectPoint
+ * @return whether ingress has been added, only add if ingressPoint is null
+ */
+ public boolean addIngressPoint(String cpstr);
+
+ /**
+ * Add the ingress ConnectPoint.
+ *
+ * @param cp the ConnectPoint of incoming traffic.
+ * @return whether ingress has been added, only add if ingressPoint is null
+ */
+ public boolean addIngressPoint(ConnectPoint cp);
+
+ /**
+ * Get the ingress connect point.
+ *
+ * @return the ingress connect point
+ */
+ public McastConnectPoint getIngressPoint();
+
+ /**
+ * Add an egress connect point.
+ *
+ * @param cp the egress McastConnectPoint to be added
+ * @return return the McastConnectPoint
+ */
+ public McastConnectPoint addEgressPoint(ConnectPoint cp);
+
+ /**
+ * Add an egress connect point.
+ *
+ * @param connectPoint deviceId/portNum
+ * @return return the McastConnectPoint
+ */
+ public McastConnectPoint addEgressPoint(String connectPoint);
+
+ /**
+ * Add an egress connect point.
+ *
+ * @param cp the egress McastConnectPoint to be added
+ * @param interest the protocol that has shown interest in this route
+ * @return return the McastConnectPoint
+ */
+ public McastConnectPoint addEgressPoint(ConnectPoint cp, McastConnectPoint.JoinSource interest);
+
+ /**
+ * Add an egress connect point.
+ *
+ * @param connectPoint deviceId/portNum
+ * @param interest the protocol that has shown interest in this route
+ * @return return the McastConnectPoint
+ */
+ public McastConnectPoint addEgressPoint(String connectPoint, McastConnectPoint.JoinSource interest);
+
+ /**
+ * Get the egress connect points.
+ *
+ * @return a set of egress connect points
+ */
+ public Set<McastConnectPoint> getEgressPoints();
+
+ /**
+ * Get the egress connect points.
+ *
+ * @return a set of egress connect points
+ */
+ public Set<ConnectPoint> getEgressConnectPoints();
+
+ /**
+ * Find the egress connect point if it exists.
+ *
+ * @param cp ConnectPoint to search for
+ * @return the connect point when found, null otherwise.
+ */
+ public McastConnectPoint findEgressConnectPoint(ConnectPoint cp);
+
+ /**
+ * remove Interest from a McastConnectPoint.
+ *
+ * @param mcp connect point.
+ * @param interest the protocol interested in this multicast stream
+ * @return whether or not interest was removed
+ */
+ public boolean removeInterest(McastConnectPoint mcp, McastConnectPoint.JoinSource interest);
+
+ /**
+ * Increment the punt count.
+ */
+ public void incrementPuntCount();
+
+ /**
+ * Get the punt count.
+ *
+ * @return the punt count
+ */
+ public int getPuntCount();
+
+ /**
+ * Have the McastIntentManager create an intent, attempt to
+ * install the intent and then save the key.
+ */
+ public void setIntent();
+
+ /**
+ * Set the Intent key.
+ *
+ * @param intent intent
+ */
+ public void setIntent(SinglePointToMultiPointIntent intent);
+
+ /**
+ * Withdraw the intent if it has been installed.
+ */
+ public void withdrawIntent();
+
+ /**
+ * Get the intent key.
+ *
+ * @return the intentKey
+ */
+ public Key getIntentKey();
+
+ /**
+ * Pretty print the the route.
+ *
+ * @return a pretty string
+ */
+ public String toString();
+} \ No newline at end of file
diff --git a/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteBase.java b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteBase.java
new file mode 100644
index 00000000..730acfa7
--- /dev/null
+++ b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteBase.java
@@ -0,0 +1,431 @@
+/*
+ * 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.mfwd.impl;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import org.apache.commons.collections.set.ListOrderedSet;
+import org.onlab.packet.IpPrefix;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.intent.SinglePointToMultiPointIntent;
+import org.onosproject.net.intent.Key;
+
+import java.util.Set;
+import java.util.HashSet;
+
+/**
+ * McastRouteBase base class for McastRouteGroup and McastRouteSource.
+ */
+public class McastRouteBase implements McastRoute {
+ protected final IpPrefix gaddr;
+ protected final IpPrefix saddr;
+
+ protected McastConnectPoint ingressPoint;
+ protected Set<McastConnectPoint> egressPoints;
+
+ protected boolean isGroup = false;
+
+ protected boolean dirty = false;
+
+ /**
+ * How may times has this packet been punted.
+ */
+ private int puntCount = 0;
+
+ /**
+ * If the intentKey is null that means no intent has
+ * been installed.
+ */
+ protected Key intentKey = null;
+
+ /**
+ * Create a multicast route. This is the parent class for both the Group
+ * and the source.
+ *
+ * @param saddr source address
+ * @param gaddr multicast group address
+ */
+ public McastRouteBase(String saddr, String gaddr) {
+ this.gaddr = IpPrefix.valueOf(checkNotNull(gaddr));
+ if (saddr == null || saddr.equals("*")) {
+ this.saddr = IpPrefix.valueOf(0, 0);
+ } else {
+ this.saddr = IpPrefix.valueOf(checkNotNull(gaddr));
+ }
+ this.init();
+ }
+
+ /**
+ * Create a multicast group table entry.
+ * @param gaddr multicast group address
+ */
+ public McastRouteBase(String gaddr) {
+ this("*", gaddr);
+ }
+
+ /**
+ * Set the source and group address value of a (*, G) group.
+ *
+ * @param gpfx the group prefix address
+ */
+ public McastRouteBase(IpPrefix gpfx) {
+ this(IpPrefix.valueOf(0, 0), gpfx);
+ }
+
+ /**
+ * Create a multicast route constructor.
+ *
+ * @param saddr source address
+ * @param gaddr group address
+ */
+ public McastRouteBase(IpPrefix saddr, IpPrefix gaddr) {
+ this.saddr = checkNotNull(saddr);
+ this.gaddr = checkNotNull(gaddr);
+
+ this.init();
+ }
+
+ private void init() {
+ this.isGroup = (this.saddr.prefixLength() == 0);
+ this.ingressPoint = null;
+ this.egressPoints = new HashSet();
+ }
+
+ /**
+ * Get the multicast group address.
+ *
+ * @return the multicast group address
+ */
+ @Override
+ public IpPrefix getGaddr() {
+ return gaddr;
+ }
+
+ /**
+ * Get the multicast source address.
+ *
+ * @return the multicast source address
+ */
+ @Override
+ public IpPrefix getSaddr() {
+ return saddr;
+ }
+
+ /**
+ * Is this an IPv4 multicast route.
+ *
+ * @return true if it is an IPv4 route
+ */
+ @Override
+ public boolean isIp4() {
+ return gaddr.isIp4();
+ }
+
+ /**
+ * Is this an IPv6 multicast route.
+ *
+ * @return true if it is an IPv6 route
+ */
+ @Override
+ public boolean isIp6() {
+ return gaddr.isIp6();
+ }
+
+ /**
+ * Is this a multicast group route?
+ *
+ * @return true if it is a multicast group route.
+ */
+ public boolean isGroup() {
+ return isGroup;
+ }
+
+ /**
+ * @return true if this is (S, G) false if it (*, G).
+ */
+ public boolean isSource() {
+ return (!isGroup);
+ }
+
+ /**
+ * Get the dirty state.
+ *
+ * @return whether this route is dirty or not.
+ */
+ public boolean getDirty() {
+ return this.dirty;
+ }
+
+ /**
+ * Set the dirty state to indicate that something changed.
+ * This may require an update to the flow tables (intents).
+ *
+ * @param dirty set the dirty bit
+ */
+ public void setDirty(boolean dirty) {
+ this.dirty = dirty;
+ }
+
+ /**
+ * Add an ingress point to this route.
+ *
+ * @param ingress incoming connect point
+ * @return whether ingress has been added, only add if ingressPoint is null
+ */
+ public boolean addIngressPoint(ConnectPoint ingress) {
+
+ // Do NOT add the ingressPoint if it is not null.
+ if (this.ingressPoint != null) {
+ // TODO: Log an warning.
+ return false;
+ }
+ this.ingressPoint = new McastConnectPoint(checkNotNull(ingress));
+ setDirty(true);
+ return true;
+ }
+
+ /**
+ * Add or modify the ingress connect point.
+ *
+ * @param connectPoint string switch device Id
+ * @return whether ingress has been added, only add if ingressPoint is null
+ */
+ public boolean addIngressPoint(String connectPoint) {
+
+ if (this.ingressPoint != null) {
+ // TODO: log a warning.
+ return false;
+ }
+ ConnectPoint cp = ConnectPoint.deviceConnectPoint(checkNotNull(connectPoint));
+ return this.addIngressPoint(cp);
+ }
+
+ /**
+ * Get the ingress McastConnectPoint.
+ *
+ * @return the ingress McastConnectPoint
+ */
+ public McastConnectPoint getIngressPoint() {
+ return this.ingressPoint;
+ }
+
+ /**
+ * Add an egress McastConnectPoint.
+ *
+ * @param cp egress connect point
+ * @return return the McastConnectPoint
+ */
+ public McastConnectPoint addEgressPoint(ConnectPoint cp) {
+ McastConnectPoint mcp = this.findEgressConnectPoint(cp);
+ if (mcp == null) {
+ mcp = new McastConnectPoint(checkNotNull(cp));
+ egressPoints.add(mcp);
+ setDirty(true);
+ }
+ return mcp;
+ }
+
+ /**
+ * Add an egress connect point from a string.
+ *
+ * @param connectPoint string representing a connect point
+ * @return the MulticastConnectPoint
+ */
+ public McastConnectPoint addEgressPoint(String connectPoint) {
+ checkNotNull(connectPoint);
+ return this.addEgressPoint(ConnectPoint.deviceConnectPoint(connectPoint));
+ }
+
+ /**
+ * Add an egress McastConnectPoint.
+ *
+ * @param cp the egress connect point
+ * @param interest the source of interest for mcast traffic
+ */
+ public McastConnectPoint addEgressPoint(ConnectPoint cp, McastConnectPoint.JoinSource interest) {
+ checkNotNull(cp);
+ checkNotNull(interest);
+ McastConnectPoint mcp = this.addEgressPoint(cp);
+ if (mcp != null) {
+ mcp.interest.add(interest);
+ setDirty(true);
+ }
+ return mcp;
+ }
+
+ /**
+ * Add an egress McastConnectPoint.
+ *
+ * @param cpstr deviceId/port of the connect point
+ */
+ public McastConnectPoint addEgressPoint(String cpstr, McastConnectPoint.JoinSource interest) {
+ checkNotNull(cpstr);
+ checkNotNull(interest);
+ return this.addEgressPoint(ConnectPoint.deviceConnectPoint(cpstr), interest);
+ }
+
+ /**
+ * Get egress connect points for the route.
+ *
+ * @return Set of egress connect points
+ */
+ public Set<McastConnectPoint> getEgressPoints() {
+ return egressPoints;
+ }
+
+ /**
+ * Get egress McastConnectPoints points as ConnectPoints for intent system.
+ *
+ * @return Set of egress ConnectPoints
+ */
+ public Set<ConnectPoint> getEgressConnectPoints() {
+ Set<ConnectPoint> cps = new ListOrderedSet();
+
+ for (McastConnectPoint mcp : egressPoints) {
+ cps.add(mcp.getConnectPoint());
+ }
+ return cps;
+ }
+
+ /**
+ * Find the Multicast Connect Point that contains the ConnectPoint.
+ *
+ * @param cp the regular ConnectPoint to match
+ * @return the McastConnectPoint that contains cp or null if not found.
+ */
+ public McastConnectPoint findEgressConnectPoint(ConnectPoint cp) {
+ for (McastConnectPoint mcp : this.egressPoints) {
+ if (mcp.getConnectPoint().equals(cp)) {
+ return mcp;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Remove specified interest from the given ConnectPoint.
+ *
+ * @param mcp connect point.
+ * @param interest the protocol interested in this multicast stream
+ * @return true if removed, false otherwise
+ */
+ public boolean removeInterest(McastConnectPoint mcp, McastConnectPoint.JoinSource interest) {
+ checkNotNull(mcp);
+ if (mcp.interest.contains(interest)) {
+ mcp.interest.remove(interest);
+ setDirty(true);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Get the number of times the packet has been punted.
+ *
+ * @return the punt count
+ */
+ @Override
+ public int getPuntCount() {
+ return puntCount;
+ }
+
+ /**
+ * Increment the punt count.
+ *
+ * TODO: we need to handle wrapping.
+ */
+ @Override
+ public void incrementPuntCount() {
+ puntCount++;
+ }
+
+ /**
+ * Have the McastIntentManager create and set the intent, then save the intent key.
+ *
+ * If we already have an intent, we will first withdraw the existing intent and
+ * replace it with a new one. This will support the case where the ingress connectPoint
+ * or group of egress connectPoints change.
+ */
+ @Override
+ public void setIntent() {
+ if (this.intentKey != null) {
+ this.withdrawIntent();
+ }
+ McastIntentManager im = McastIntentManager.getInstance();
+ SinglePointToMultiPointIntent intent = im.setIntent(this);
+ this.intentKey = intent.key();
+ }
+
+ /**
+ * Set the Intent key.
+ *
+ * @param intent the multicast intent
+ */
+ @Override
+ public void setIntent(SinglePointToMultiPointIntent intent) {
+ intentKey = intent.key();
+ }
+
+ /**
+ * Get the intent key represented by this route.
+ *
+ * @return intentKey
+ */
+ @Override
+ public Key getIntentKey() {
+ return this.intentKey;
+ }
+
+
+ /**
+ * Withdraw the intent and set the key to null.
+ */
+ @Override
+ public void withdrawIntent() {
+ if (intentKey == null) {
+ // nothing to withdraw
+ return;
+ }
+ McastIntentManager im = McastIntentManager.getInstance();
+ im.withdrawIntent(this);
+ this.intentKey = null;
+ }
+
+ /**
+ * Pretty Print this Multicast Route. Works for McastRouteSource and McastRouteGroup.
+ *
+ * @return pretty string of the multicast route
+ */
+ @Override
+ public String toString() {
+ String out = String.format("(%s, %s)\n\t",
+ saddr.toString(), gaddr.toString());
+
+ out += "intent: ";
+ out += (intentKey == null) ? "not installed" : this.intentKey.toString();
+ out += "\n\tingress: ";
+ out += (ingressPoint == null) ? "NULL" : ingressPoint.toString();
+ out += "\n\tegress: {\n";
+ if (egressPoints != null && !egressPoints.isEmpty()) {
+ for (McastConnectPoint eg : egressPoints) {
+ out += "\t\t" + eg.getConnectPoint().toString() + "\n";
+ }
+ }
+ out += ("\t}\n");
+ out += ("\tpunted: " + this.getPuntCount() + "\n");
+ return out;
+ }
+}
diff --git a/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteGroup.java b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteGroup.java
new file mode 100644
index 00000000..4a58e1b1
--- /dev/null
+++ b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteGroup.java
@@ -0,0 +1,110 @@
+/*
+ * 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.mfwd.impl;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import java.util.HashMap;
+import org.onlab.packet.IpPrefix;
+
+/**
+ * The McastRouteGroup extends the McastRouteBase class and serves two purposes:
+ * first it represents a (*, G) multicast route entry. Second it serves
+ * as a container for all (S, G) multicast route entries that belong
+ * to the same group address.
+ */
+public class McastRouteGroup extends McastRouteBase {
+ private HashMap<IpPrefix, McastRouteSource> sources;
+
+ /**
+ * Class constructor.
+ *
+ * @param gaddr - String representation of group address.
+ */
+ public McastRouteGroup(String gaddr) {
+ super(checkNotNull(gaddr));
+ this.init();
+ }
+
+ /**
+ * Create a multicast group.
+ *
+ * @param gpfx - Group address
+ */
+ public McastRouteGroup(IpPrefix gpfx) {
+ super(checkNotNull(gpfx));
+ this.init();
+ }
+
+ /**
+ * Common initialization used by constructors.
+ */
+ private void init() {
+ this.sources = new HashMap();
+ super.isGroup = true;
+ }
+
+ /**
+ * Find a specific multicast source address for this group.
+ *
+ * @param saddr the source address
+ * @return the multicast source route or null if it does not exist
+ */
+ public McastRouteSource findSource(IpPrefix saddr) {
+ return this.sources.get(checkNotNull(saddr));
+ }
+
+ /**
+ * Return the entire set of multicast sources for this group.
+ *
+ * @return the set of multicast sources
+ */
+ public HashMap<IpPrefix, McastRouteSource> getSources() {
+ return this.sources;
+ }
+
+ /**
+ * Add a new McastRouteSource to this group.
+ *
+ * @param src the multicast source
+ */
+ public void addSource(McastRouteSource src) {
+ checkNotNull(src);
+ this.sources.put(src.getSaddr(), src);
+ }
+
+ /**
+ * Remove the source with this specific IpPrefix from this group entry.
+ *
+ * @param spfx IP Prefix of the source to be removed
+ * @return the source route that was just removed
+ */
+ public McastRouteSource removeSource(IpPrefix spfx) {
+ McastRouteSource src = this.sources.remove(spfx);
+ src.withdrawIntent();
+ return src;
+ }
+
+ /**
+ * Remove all sources from this.
+ */
+ public void removeSources() {
+ for (McastRouteSource src : this.sources.values()) {
+ src.withdrawIntent();
+ this.sources.remove(src.getSaddr());
+ }
+ }
+
+}
diff --git a/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteSource.java b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteSource.java
new file mode 100644
index 00000000..68edc2e0
--- /dev/null
+++ b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteSource.java
@@ -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.mfwd.impl;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import org.onlab.packet.IpPrefix;
+
+/**
+ * This class represents and specific multicast senders source address. Objects from
+ * this class will belong to the sources collection of the multicast group.
+ */
+public class McastRouteSource extends McastRouteBase {
+
+ // A reference to our parent group
+ private McastRouteGroup group;
+
+ /**
+ * Create a multicast source with IpPrefixes.
+ *
+ * @param source the source address
+ * @param group the group address
+ */
+ public McastRouteSource(IpPrefix source, IpPrefix group) {
+ super(checkNotNull(source), checkNotNull(group));
+ }
+
+ /**
+ * Set our parent multicast group.
+ *
+ * @param group the group this source belongs to
+ */
+ public void setGroup(McastRouteGroup group) {
+ this.group = group;
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteTable.java b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteTable.java
new file mode 100644
index 00000000..5a07bec7
--- /dev/null
+++ b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteTable.java
@@ -0,0 +1,338 @@
+/*
+ * 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.mfwd.impl;
+
+import org.apache.felix.scr.annotations.Service;
+import org.onlab.packet.IpPrefix;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * The Mcast Route Table holds all multicast state for the controller.
+ *
+ * State for IPv4 and IPv6 are maintained. The tables are sets of McastRouteGroup
+ * structures that represent (*, G) state with a series of egress ConnectPoints.
+ * Each (*, G) may also have a set of (S, G) that may have there own set of
+ * ingress and egress ConnectPoints.
+ *
+ * TODO: perhaps should probably create two separate singleton for IPv4 and IPv6 respectively.
+ */
+@Service(value = org.onosproject.mfwd.impl.McastRouteTable.class)
+public final class McastRouteTable {
+
+ /*
+ * Create a map of the McastGroups indexed by the multicast group prefix.
+ * We may choose to change the map data structure in to some form a radix trie
+ * depending on the type of real world usage we see.
+ */
+ private final Map<IpPrefix, McastRouteGroup> mrib4;
+ private final Map<IpPrefix, McastRouteGroup> mrib6;
+ private static McastRouteTable instance = null;
+
+ private Boolean ipv6Enabled = false;
+
+ /**
+ * Create the two v4 & v6 tables.
+ */
+ private McastRouteTable() {
+ mrib4 = new ConcurrentHashMap<IpPrefix, McastRouteGroup>();
+ if (ipv6Enabled) {
+ mrib6 = new ConcurrentHashMap<IpPrefix, McastRouteGroup>();
+ } else {
+ mrib6 = null;
+ }
+ }
+
+ /**
+ * Get the single instance of this multicast group address.
+ *
+ * @return the multicast route table
+ */
+ public static McastRouteTable getInstance() {
+ if (instance == null) {
+ instance = new McastRouteTable();
+ }
+ return instance;
+ }
+
+ /**
+ * Get the IPv4 MRIB.
+ *
+ * @return the IPv4 MRIB
+ */
+ public Map<IpPrefix, McastRouteGroup> getMrib4() {
+ return mrib4;
+ }
+
+ /**
+ * Get the IPv6 MRIB.
+ *
+ * @return Return the set of prefix keyed McastGroups
+ */
+ public Map<IpPrefix, McastRouteGroup> getMrib6() {
+ return mrib6;
+ }
+
+ /**
+ * Save the McastRouteGroup in the address family appropriate mrib.
+ *
+ * @param group The McastRouteGroup to save
+ */
+ private void storeGroup(McastRouteGroup group) {
+ if (group.isIp4()) {
+ mrib4.put(group.getGaddr(), group);
+ } else if (group.isIp6() && ipv6Enabled) {
+ mrib6.put(group.getGaddr(), group);
+ }
+ }
+
+ /**
+ * Remove the group.
+ *
+ * @param group the group to be removed
+ */
+ private void removeGroup(McastRouteGroup group) {
+ IpPrefix gpfx = group.getGaddr();
+ if (gpfx.isIp4()) {
+ mrib4.remove(gpfx);
+ } else if (gpfx.isIp6() && ipv6Enabled) {
+ mrib6.remove(gpfx);
+ }
+ }
+
+ /**
+ * Add a multicast route to the MRIB. This function will.
+ *
+ * @param saddr source address * or x.x.x.x or x.x.x.x/y
+ * @param gaddr group address x.x.x.x or x.x.x.x/y
+ * @return the multicast route
+ */
+ public McastRouteBase addRoute(String saddr, String gaddr) {
+ IpPrefix gpfx = IpPrefix.valueOf(gaddr);
+ IpPrefix spfx = IpPrefix.valueOf(0, 0);
+ if (saddr != null && !saddr.equals("*")) {
+ spfx = IpPrefix.valueOf(saddr);
+ }
+ return addRoute(spfx, gpfx);
+ }
+
+ /**
+ * Add a multicast route to the MRIB. This function will store either
+ * (S, G) or (*, G) in the mrib if an entry does not already exist. If
+ * an entry does exist it is returned to the caller.
+ *
+ * Every (S, G) is stored as part of it's parent group entry which also represents
+ * (*, G) routes. In the case of a (S, G) we will also create the (*, G) entry if needed
+ * then save the (S, G) to the (*, G).
+ *
+ * @param spfx the source prefix
+ * @param gpfx the group prefix
+ * @return the resulting McastRouteSource or McastRouteGroup accordingly.
+ */
+ public McastRouteBase addRoute(IpPrefix spfx, IpPrefix gpfx) {
+
+ /**
+ * If a group route (*, g) does not exist we will need to make so we
+ * can start attaching our sources to the group entry.
+ */
+ McastRouteGroup group = findMcastGroup(gpfx);
+ if (group == null) {
+ group = new McastRouteGroup(gpfx);
+
+ // Save it for later
+ if (gpfx.isIp4()) {
+ this.mrib4.put(gpfx, group);
+ } else if (gpfx.isIp6() && ipv6Enabled) {
+ this.mrib6.put(gpfx, group);
+ }
+ }
+
+ /**
+ * If the source prefix length is 0 then we have our (*, g) entry, we can
+ * just return now.
+ */
+ if (spfx.prefixLength() == 0) {
+ return group;
+ }
+
+ // See if the source already exists. If so just return it.
+ McastRouteSource source = group.findSource(spfx);
+ if (source != null) {
+ return source;
+ }
+
+ /**
+ * We have the group but no source. We need to create the source then add it
+ * to the group.
+ */
+ source = new McastRouteSource(spfx, gpfx);
+
+ // Have the source save it's parent
+ source.setGroup(group);
+
+ // Save this source as part of this group
+ group.addSource(source);
+
+ return source;
+ }
+
+ /**
+ * Delete a multicast route from the MRIB.
+ *
+ * @param saddr source address * or x.x.x.x or x.x.x.x/y
+ * @param gaddr group address x.x.x.x or x.x.x.x/y
+ */
+ public void removeRoute(String saddr, String gaddr) {
+ IpPrefix gpfx = IpPrefix.valueOf(gaddr);
+ IpPrefix spfx = IpPrefix.valueOf(0, 0);
+ if (saddr != null && !saddr.equals("*")) {
+ spfx = IpPrefix.valueOf(saddr);
+ }
+ removeRoute(spfx, gpfx);
+ }
+
+ /**
+ * Remove a multicast route.
+ *
+ * @param spfx the source prefix
+ * @param gpfx the group prefix
+ */
+ public void removeRoute(IpPrefix spfx, IpPrefix gpfx) {
+
+ /**
+ * If a group route (*, g) does not exist we will need to make so we
+ * can start attaching our sources to the group entry.
+ */
+ McastRouteGroup group = findMcastGroup(gpfx);
+ if (group == null) {
+ // The group does not exist, we can't remove it.
+ return;
+ }
+
+ /**
+ * If the source prefix length is 0 then we have a (*, g) entry, which
+ * means we will remove this group and all of it's sources. We will
+ * also withdraw it's intent if need be.
+ */
+ if (spfx.prefixLength() > 0) {
+ group.removeSource(spfx);
+
+ /*
+ * Now a little house keeping. If this group has no more sources
+ * nor egress connectPoints git rid of it.
+ */
+ if (group.getSources().size() == 0 &&
+ group.getEgressPoints().size() == 0) {
+ removeGroup(group);
+ }
+
+ } else {
+ // Group remove has been explicitly requested.
+ group.removeSources();
+ group.withdrawIntent();
+ removeGroup(group);
+ }
+ }
+
+ /**
+ * Find the specific multicast group entry.
+ *
+ * @param group the group address
+ * @return McastRouteGroup the multicast (*, G) group route
+ */
+ public McastRouteGroup findMcastGroup(IpPrefix group) {
+ McastRouteGroup g = null;
+ if (group.isIp4()) {
+ g = mrib4.get(group);
+ } else if (group.isIp6() && ipv6Enabled) {
+ g = mrib6.get(group);
+ }
+ return g;
+ }
+
+ /**
+ * Find the multicast (S, G) entry if it exists.
+ *
+ * @param saddr the source address
+ * @param gaddr the group address
+ * @return The multicast source route entry if it exists, null if it does not.
+ */
+ public McastRouteSource findMcastSource(IpPrefix saddr, IpPrefix gaddr) {
+ McastRouteGroup grp = findMcastGroup(checkNotNull(gaddr));
+ if (grp == null) {
+ return null;
+ }
+ return grp.findSource(saddr);
+ }
+
+ /**
+ * This will first look up a Group entry. If no group entry was found null will
+ * be returned. If the group entry has been found we will then look up the (s, g) entry.
+ * If the (s, g) entry has been found, that will be returned. If no (s, g) was found
+ * the (*, g) group entry will be returned.
+ *
+ * @param saddr the source address
+ * @param gaddr the group address
+ * @return return the best matching McastRouteSource or McastRouteGroup
+ */
+ public McastRoute findBestMatch(IpPrefix saddr, IpPrefix gaddr) {
+ McastRouteGroup grp = this.findMcastGroup(checkNotNull(gaddr));
+ if (grp == null) {
+ return null;
+ }
+
+ // Found a group now look for a source
+ McastRouteSource src = grp.findSource(checkNotNull(saddr));
+ if (src == null) {
+ return grp;
+ }
+
+ return src;
+ }
+
+ /**
+ * Print out the multicast route table in it's entirety.
+ *
+ * TODO: Eventually we will have to implement paging and how to handle large tables.
+ * @return String
+ */
+ public String printMcastRouteTable() {
+ String out = this.toString() + "\n";
+
+ for (McastRouteGroup grp : mrib4.values()) {
+ out += grp.toString() + "\n";
+ for (McastRouteSource src : grp.getSources().values()) {
+ out += src.toString() + "\n";
+ }
+ }
+ return out;
+ }
+
+ /**
+ * Print out a summary of groups in the MRIB.
+ *
+ * @return String
+ */
+ public String toString() {
+ String out = "Mcast Route Table: ";
+ out += mrib4.size() + " IPv4 Multicast Groups\n";
+ if (ipv6Enabled) {
+ out += mrib6.size() + " IPv6 Multicast Groups\n";
+ }
+ return out;
+ }
+}
diff --git a/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/package-info.java b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/package-info.java
new file mode 100644
index 00000000..eaef5fcf
--- /dev/null
+++ b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Sample Multicast forwarding framework using intents.
+ */
+package org.onosproject.mfwd.impl;
diff --git a/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/rest/McastResource.java b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/rest/McastResource.java
new file mode 100644
index 00000000..608e0447
--- /dev/null
+++ b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/rest/McastResource.java
@@ -0,0 +1,149 @@
+/*
+ * 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.mfwd.rest;
+
+import java.io.IOException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.onosproject.mfwd.impl.McastConnectPoint;
+import org.onosproject.mfwd.impl.McastRouteTable;
+import org.onosproject.mfwd.impl.McastRouteBase;
+import org.onosproject.mfwd.impl.MRibCodec;
+import org.onosproject.rest.AbstractWebResource;
+
+import org.slf4j.Logger;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Rest API for Multicast Forwarding.
+ */
+@Path("mcast")
+public class McastResource extends AbstractWebResource {
+
+ private final Logger log = getLogger(getClass());
+ private static final String SOURCE_ADDRESS = "sourceAddress";
+ private static final String GROUP_ADDRESS = "groupAddress";
+ private static final String INGRESS_POINT = "ingressPoint";
+ private static final String EGRESS_POINT = "egressPoint";
+ private static final String MCAST_GROUP = "mcastGroup";
+
+ /**
+ * Retrieve the multicast route table.
+ *
+ * @return the multicast route table.
+ * @throws IOException if an error occurs
+ */
+ @Path("show")
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response showAll() throws IOException {
+ McastRouteTable mrt = McastRouteTable.getInstance();
+ ObjectNode pushContent = new MRibCodec().encode(mrt , this);
+ return ok(pushContent.toString()).build();
+ }
+
+ /**
+ * Static join a multicast flow.
+ *
+ * @param sAddr source address to join
+ * @param gAddr group address to join
+ * @param ports ingress and egress ConnectPoints to join
+ * @return the Result of the join
+ * @throws IOException if something failed with the join command
+ */
+ @Path("/join")
+ @POST
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response join(@QueryParam("src") String sAddr,
+ @QueryParam("grp") String gAddr,
+ @DefaultValue("") @QueryParam("ports") String ports)
+ throws IOException {
+
+ ObjectMapper mapper = new ObjectMapper();
+ log.debug("Source IP Address: " + sAddr);
+ log.debug("Destination IP Address: " + gAddr);
+ log.debug("Ingress and Egress ports: " + ports);
+
+ String output = "Insertion Faild";
+ if (sAddr != null && gAddr != null && ports != null) {
+
+ String[] portArr = ports.split(",");
+ log.debug("Port Array Length: " + portArr.length);
+ McastRouteTable mrt = McastRouteTable.getInstance();
+ McastRouteBase mr = mrt.addRoute(sAddr, gAddr);
+
+ // Port format "of:0000000000000023/4"
+ log.debug("checking inside outer if: " + portArr.length);
+
+ if (mr != null && portArr != null && portArr.length > 0) {
+
+ String inCP = portArr[0];
+ log.debug("Ingress port provided: " + inCP);
+ mr.addIngressPoint(inCP);
+
+ for (int i = 1; i < portArr.length; i++) {
+ String egCP = portArr[i];
+ log.debug("Egress port provided: " + egCP);
+ mr.addEgressPoint(egCP, McastConnectPoint.JoinSource.STATIC);
+ }
+ mrt.printMcastRouteTable();
+ output = "Successfully Inserted";
+ }
+ } else {
+ output = "Please Insert the rest uri correctly";
+ }
+ return Response.ok(output).build();
+ }
+
+ /**
+ * Delete multicast state.
+ *
+ * @param src address to be deleted
+ * @param grp address to be deleted
+ * @return status of delete if successful
+ */
+ @Path("/delete")
+ @DELETE
+ @Consumes(MediaType.TEXT_PLAIN)
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response removeMcastFlow(@QueryParam("src") String src,
+ @QueryParam("grp") String grp) {
+
+ String resp = "Failed to delete";
+ log.info("Source IP Address to delete: " + src);
+ log.info("Destination IP Address to delete: " + grp);
+ McastRouteTable mrt = McastRouteTable.getInstance();
+ if (src != null && grp != null) {
+ mrt.removeRoute(src, grp);
+ resp = "Deleted flow for src " + src + " and grp " + grp;
+ }
+
+ return Response.ok(resp).build();
+ }
+}
diff --git a/framework/src/onos/apps/mfwd/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/framework/src/onos/apps/mfwd/src/main/resources/OSGI-INF/blueprint/shell-config.xml
new file mode 100644
index 00000000..966cb4f2
--- /dev/null
+++ b/framework/src/onos/apps/mfwd/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -0,0 +1,30 @@
+<!--
+ ~ 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.
+ -->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+
+ <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
+ <command>
+ <action class="org.onosproject.mfwd.cli.McastJoinCommand"/>
+ </command>
+ <command>
+ <action class="org.onosproject.mfwd.cli.McastDeleteCommand"/>
+ </command>
+ <command>
+ <action class="org.onosproject.mfwd.cli.McastShowCommand"/>
+ </command>
+ </command-bundle>
+
+</blueprint>
diff --git a/framework/src/onos/apps/mfwd/src/main/webapp/WEB-INF/web.xml b/framework/src/onos/apps/mfwd/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 00000000..c4c4f459
--- /dev/null
+++ b/framework/src/onos/apps/mfwd/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,44 @@
+<?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.
+-->
+<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>ONOS APP MFWD</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.mfwd.rest.McastResource
+ </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>
diff --git a/framework/src/onos/apps/optical/src/main/java/org/onosproject/optical/OpticalPathProvisioner.java b/framework/src/onos/apps/optical/src/main/java/org/onosproject/optical/OpticalPathProvisioner.java
index 85b5de27..8466b95e 100644
--- a/framework/src/onos/apps/optical/src/main/java/org/onosproject/optical/OpticalPathProvisioner.java
+++ b/framework/src/onos/apps/optical/src/main/java/org/onosproject/optical/OpticalPathProvisioner.java
@@ -45,7 +45,8 @@ 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.resource.device.DeviceResourceService;
+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;
@@ -97,11 +98,14 @@ public class OpticalPathProvisioner {
protected DeviceService deviceService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected DeviceResourceService deviceResourceService;
+ protected IntentSetMultimap intentSetMultimap;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected LinkResourceService linkResourceService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected ResourceService resourceService;
+
private ApplicationId appId;
private final InternalOpticalPathProvisioner pathProvisioner = new InternalOpticalPathProvisioner();
@@ -292,7 +296,6 @@ public class OpticalPathProvisioner {
.bidirectional(true)
.build();
intents.add(circuitIntent);
- continue;
} else if (srcPort instanceof OchPort && dstPort instanceof OchPort) {
// Create lightpath
// FIXME: hardcoded ODU signal type
@@ -304,7 +307,6 @@ public class OpticalPathProvisioner {
.bidirectional(true)
.build();
intents.add(opticalIntent);
- continue;
} else {
log.warn("Unsupported cross connect point types {} {}", srcPort.type(), dstPort.type());
return Collections.emptyList();
@@ -377,13 +379,13 @@ public class OpticalPathProvisioner {
private void releaseResources(Intent intent) {
LinkResourceAllocations lra = linkResourceService.getAllocations(intent.id());
if (intent instanceof OpticalConnectivityIntent) {
- deviceResourceService.releasePorts(intent.id());
+ resourceService.release(intent.id());
if (lra != null) {
linkResourceService.releaseResources(lra);
}
} else if (intent instanceof OpticalCircuitIntent) {
- deviceResourceService.releasePorts(intent.id());
- deviceResourceService.releaseMapping(intent.id());
+ resourceService.release(intent.id());
+ intentSetMultimap.releaseMapping(intent.id());
if (lra != null) {
linkResourceService.releaseResources(lra);
}
diff --git a/framework/src/onos/apps/pim/pom.xml b/framework/src/onos/apps/pim/pom.xml
new file mode 100644
index 00000000..83a366b6
--- /dev/null
+++ b/framework/src/onos/apps/pim/pom.xml
@@ -0,0 +1,122 @@
+<?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/xsd/maven-4.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-pim</artifactId>
+ <packaging>bundle</packaging>
+
+ <description>Protocol Independent Multicast Emulation</description>
+
+ <properties>
+ <onos.app.name>org.onosproject.pim</onos.app.name>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-cli</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onlab-osgi</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onlab-junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <!-- This is needed by ComponentContext, used for tunable configuration -->
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.karaf.shell</groupId>
+ <artifactId>org.apache.karaf.shell.console</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.scr.annotations</artifactId>
+ <version>1.9.8</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-SymbolicName>
+ ${project.groupId}.${project.artifactId}
+ </Bundle-SymbolicName>
+ <Import-Package>
+ org.slf4j,
+ org.osgi.framework,
+ org.apache.commons.lang.math.*,
+ com.google.common.*,
+ org.apache.karaf.shell.commands,
+ org.apache.karaf.shell.console,
+ org.onlab.packet.*,
+ org.onlab.rest.*,
+ org.onosproject.*,
+ org.onosproject.mfwd.impl.*;
+ org.onlab.util.*,
+ org.jboss.netty.util.*
+ </Import-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.5.1</version>
+ <configuration>
+ <source>1.8</source>
+ <target>1.8</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/framework/src/onos/apps/pim/src/main/java/org/onosproject/pim/cli/PIMShowCommand.java b/framework/src/onos/apps/pim/src/main/java/org/onosproject/pim/cli/PIMShowCommand.java
new file mode 100644
index 00000000..0ef7e389
--- /dev/null
+++ b/framework/src/onos/apps/pim/src/main/java/org/onosproject/pim/cli/PIMShowCommand.java
@@ -0,0 +1,47 @@
+/*
+ * 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.pim.cli;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.pim.impl.PIMNeighbors;
+import org.onosproject.pim.impl.PIMNeighborsCodec;
+
+import java.util.HashMap;
+
+@Command(scope = "onos", name = "pim-neighbors", description = "Displays the pim neighbors")
+public class PIMShowCommand extends AbstractShellCommand {
+
+ // prints either the json or cli version of the hash map connect point
+ // neighbors from the PIMNeighbors class.
+ @Override
+ protected void execute() {
+ // grab connect point neighbors hash map to send in to json encoder.
+ HashMap<ConnectPoint, PIMNeighbors> pimNbrs = PIMNeighbors.getConnectPointNeighbors();
+ if (outputJson()) {
+ print("%s", json(pimNbrs));
+ } else {
+ print(PIMNeighbors.printPimNeighbors());
+ }
+ }
+
+ private JsonNode json(HashMap<ConnectPoint, PIMNeighbors> pimNbrs) {
+ return new PIMNeighborsCodec().encode(pimNbrs, this);
+ }
+
+} \ No newline at end of file
diff --git a/framework/src/onos/apps/pim/src/main/java/org/onosproject/pim/cli/package-info.java b/framework/src/onos/apps/pim/src/main/java/org/onosproject/pim/cli/package-info.java
new file mode 100644
index 00000000..954dacbb
--- /dev/null
+++ b/framework/src/onos/apps/pim/src/main/java/org/onosproject/pim/cli/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * PIM Multicast forwarding framework using intents.
+ */
+package org.onosproject.pim.cli; \ No newline at end of file
diff --git a/framework/src/onos/apps/pim/src/main/java/org/onosproject/pim/impl/PIMComponent.java b/framework/src/onos/apps/pim/src/main/java/org/onosproject/pim/impl/PIMComponent.java
new file mode 100644
index 00000000..bd5e1486
--- /dev/null
+++ b/framework/src/onos/apps/pim/src/main/java/org/onosproject/pim/impl/PIMComponent.java
@@ -0,0 +1,153 @@
+/*
+ * 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.pim.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.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.IPv4;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.PIM;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.packet.InboundPacket;
+import org.onosproject.net.packet.PacketContext;
+import org.onosproject.net.packet.PacketPriority;
+import org.onosproject.net.packet.PacketProcessor;
+import org.onosproject.net.packet.PacketService;
+import org.slf4j.Logger;
+
+/**
+ * Protocol Independent Multicast Emulation.
+ */
+@Component(immediate = true)
+public class PIMComponent {
+ private final Logger log = getLogger(getClass());
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected PacketService packetService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CoreService coreService;
+
+ private PIMPacketProcessor processor = new PIMPacketProcessor();
+ private static ApplicationId appId;
+
+ @Activate
+ public void activate() {
+ appId = coreService.registerApplication("org.onosproject.pim");
+
+ packetService.addProcessor(processor, PacketProcessor.director(1));
+
+ // Build a traffic selector for all multicast traffic
+ TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+ selector.matchEthType(Ethernet.TYPE_IPV4);
+ selector.matchIPProtocol(IPv4.PROTOCOL_PIM);
+ packetService.requestPackets(selector.build(), PacketPriority.REACTIVE, appId);
+
+ log.info("Started");
+ }
+
+ @Deactivate
+ public void deactivate() {
+ packetService.removeProcessor(processor);
+ processor = null;
+ log.info("Stopped");
+ }
+
+ /**
+ * Packet processor responsible for handling IGMP packets.
+ */
+ private class PIMPacketProcessor implements PacketProcessor {
+
+ @Override
+ public void process(PacketContext context) {
+ // Stop processing if the packet has been handled, since we
+ // can't do any more to it.
+ if (context.isHandled()) {
+ return;
+ }
+
+ InboundPacket pkt = context.inPacket();
+ if (pkt == null) {
+ return;
+ }
+
+ Ethernet ethPkt = pkt.parsed();
+ if (ethPkt == null) {
+ return;
+ }
+
+ /*
+ * IPv6 MLD packets are handled by ICMP6. We'll only deal
+ * with IPv4.
+ */
+ if (ethPkt.getEtherType() != Ethernet.TYPE_IPV4) {
+ return;
+ }
+
+ IPv4 ip = (IPv4) ethPkt.getPayload();
+ IpAddress gaddr = IpAddress.valueOf(ip.getDestinationAddress());
+ IpAddress saddr = Ip4Address.valueOf(ip.getSourceAddress());
+ log.debug("Packet (" + saddr.toString() + ", " + gaddr.toString() +
+ "\tingress port: " + context.inPacket().receivedFrom().toString());
+
+ if (ip.getProtocol() != IPv4.PROTOCOL_PIM) {
+ log.debug("PIM Picked up a non PIM packet: IP protocol: " + ip.getProtocol());
+ return;
+ }
+
+ // TODO: check incoming to be PIM.PIM_ADDRESS or "Our" address.
+ IpPrefix spfx = IpPrefix.valueOf(saddr, 32);
+ IpPrefix gpfx = IpPrefix.valueOf(gaddr, 32);
+
+ PIM pim = (PIM) ip.getPayload();
+ switch (pim.getPimMsgType()) {
+
+ case PIM.TYPE_HELLO:
+ PIMNeighbors.processHello(ethPkt, context.inPacket().receivedFrom());
+ break;
+
+ case PIM.TYPE_JOIN_PRUNE_REQUEST:
+ // Create the function
+ break;
+
+ case PIM.TYPE_ASSERT:
+ case PIM.TYPE_BOOTSTRAP:
+ case PIM.TYPE_CANDIDATE_RP_ADV:
+ case PIM.TYPE_GRAFT:
+ case PIM.TYPE_GRAFT_ACK:
+ case PIM.TYPE_REGISTER:
+ case PIM.TYPE_REGISTER_STOP:
+ log.debug("Unsupported PIM message type: " + pim.getPimMsgType());
+ break;
+
+ default:
+ log.debug("Unkown PIM message type: " + pim.getPimMsgType());
+ break;
+ }
+ }
+ }
+}
diff --git a/framework/src/onos/apps/pim/src/main/java/org/onosproject/pim/impl/PIMNeighbor.java b/framework/src/onos/apps/pim/src/main/java/org/onosproject/pim/impl/PIMNeighbor.java
new file mode 100644
index 00000000..1a96138f
--- /dev/null
+++ b/framework/src/onos/apps/pim/src/main/java/org/onosproject/pim/impl/PIMNeighbor.java
@@ -0,0 +1,340 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in reliance 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.pim.impl;
+
+import org.jboss.netty.util.Timeout;
+import org.jboss.netty.util.TimerTask;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.pim.PIMHello;
+import org.onlab.packet.pim.PIMHelloOption;
+import org.onosproject.net.ConnectPoint;
+import org.slf4j.Logger;
+
+import java.nio.ByteBuffer;
+import java.util.concurrent.TimeUnit;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * PIMNeighbor represents all the PIM routers that have sent us
+ * hello messages, or that possibly have been statically configured.
+ */
+public class PIMNeighbor {
+ private final Logger log = getLogger(getClass());
+
+ // The primary address of this PIM neighbor
+ private IpAddress primaryAddr;
+
+ // The MacAddress of this neighbor
+ private MacAddress macAddress;
+
+ // The ConnectPoint this PIM neighbor is connected to.
+ private ConnectPoint connectPoint;
+
+ // Is this neighbor us?
+ private boolean isThisUs = false;
+
+ // The option values this neighbor has sent us.
+ private int priority = 0;
+ private int genId = 0;
+ private short holdtime = 0;
+
+ // Is this pim neighbor the DR?
+ private boolean isDr = false;
+
+ // Timeout for this neighbor
+ private volatile Timeout timeout;
+
+ private boolean reelect = false;
+
+ // A back pointer the neighbors list this neighbor belongs to.
+ private PIMNeighbors neighbors;
+
+ /**
+ * Construct this neighbor from the address and connect point.
+ *
+ * @param ipaddr IP Address of neighbor
+ * @param macaddr MAC Address of the neighbor
+ * @param cp The ConnectPoint of this neighbor
+ */
+ public PIMNeighbor(IpAddress ipaddr, MacAddress macaddr, ConnectPoint cp) {
+ this.macAddress = macaddr;
+ this.primaryAddr = ipaddr;
+ this.connectPoint = cp;
+ this.resetTimeout();
+ }
+
+ /**
+ * Get the primary address of this neighbor.
+ *
+ * @return the primary IP address.
+ */
+ public IpAddress getPrimaryAddr() {
+ return primaryAddr;
+ }
+
+ /**
+ * Set the primary address of this neighbor.
+ *
+ * @param primaryAddr the address we'll use when sending hello messages
+ */
+ public void setPrimaryAddr(IpAddress primaryAddr) {
+ this.primaryAddr = primaryAddr;
+ }
+
+ /**
+ * Get the priority this neighbor has advertised to us.
+ *
+ * @return the priority
+ */
+ public int getPriority() {
+ return priority;
+ }
+
+ /**
+ * Set the priority for this neighbor.
+ *
+ * @param priority This neighbors priority.
+ */
+ public void setPriority(int priority) {
+ this.priority = priority;
+ }
+
+ /**
+ * Get the generation ID.
+ *
+ * @return the generation ID.
+ */
+ public int getGenId() {
+ return genId;
+ }
+
+ /**
+ * Set the generation ID.
+ *
+ * @param genId the generation ID.
+ */
+ public void setGenId(int genId) {
+ this.genId = genId;
+ }
+
+ /**
+ * Get the holdtime for this neighbor.
+ *
+ * @return the holdtime
+ */
+ public short getHoldtime() {
+ return holdtime;
+ }
+
+ /**
+ * Set the holdtime for this neighbor.
+ *
+ * @param holdtime the holdtime.
+ */
+ public void setholdtime(short holdtime) {
+ this.holdtime = holdtime;
+ }
+
+ /**
+ * Is this neighbor the designated router on this connect point?
+ *
+ * @return true if so, false if not.
+ */
+ public boolean isDr() {
+ return isDr;
+ }
+
+ /**
+ * Set this router as the designated router on this connect point.
+ *
+ * @param isDr True is this neighbor is the DR false otherwise
+ */
+ public void setIsDr(boolean isDr) {
+ this.isDr = isDr;
+ }
+
+ /**
+ * The ConnectPoint this neighbor is connected to.
+ *
+ * @return the ConnectPoint
+ */
+ public ConnectPoint getConnectPoint() {
+ return connectPoint;
+ }
+
+ /**
+ * Set the ConnectPoint this router is connected to.
+ *
+ * @param connectPoint the ConnectPoint this router is connected to.
+ */
+ public void setConnectPoint(ConnectPoint connectPoint) {
+ this.connectPoint = connectPoint;
+ }
+
+ /**
+ * Set a back pointer to the neighbors list this neighbor is a member of.
+ *
+ * @param neighbors the neighbor list this neighbor belongs to
+ */
+ public void setNeighbors(PIMNeighbors neighbors) {
+ this.neighbors = neighbors;
+ }
+
+ /**
+ * We have received a fresh hello from a neighbor, now we need to process it.
+ * Depending on the values received in the the hello options may force a
+ * re-election process.
+ *
+ * We will also refresh the timeout for this neighbor.
+ *
+ * @param hello copy of the hello we'll be able to extract options from.
+ */
+ public void refresh(PIMHello hello) {
+ checkNotNull(hello);
+
+ for (PIMHelloOption opt : hello.getOptions().values()) {
+
+ int len = opt.getOptLength();
+ byte [] value = new byte[len];
+ ByteBuffer bb = ByteBuffer.wrap(value);
+
+ switch (opt.getOptType()) {
+ case PIMHelloOption.OPT_GENID:
+ int newid = bb.getInt();
+ if (this.genId != newid) {
+ // TODO: we have a newly rebooted neighbor. Send them our joins.
+ this.genId = newid;
+ }
+ break;
+
+ case PIMHelloOption.OPT_PRIORITY:
+ int newpri = bb.getInt();
+ if (this.priority != newpri) {
+
+ // The priorities have changed. We may need to re-elect a new DR?
+ if (this.isDr || this.neighbors.getDesignatedRouter().getPriority() < priority) {
+ reelect = true;
+ }
+ this.priority = newpri;
+ }
+ break;
+
+ case PIMHelloOption.OPT_HOLDTIME:
+ short holdtime = bb.getShort();
+ if (this.holdtime != holdtime) {
+ this.holdtime = holdtime;
+ if (holdtime == 0) {
+ // We have a neighbor going down. We can remove all joins
+ // we have learned from them.
+ // TODO: What else do we need to do when a neighbor goes down?
+
+ log.debug("PIM Neighbor has timed out: {}", this.primaryAddr.toString());
+ return;
+ }
+ }
+ break;
+
+ case PIMHelloOption.OPT_PRUNEDELAY:
+ case PIMHelloOption.OPT_ADDRLIST:
+ // TODO: implement prune delay and addr list. Fall through for now.
+
+ default:
+ log.debug("PIM Hello option type: {} not yet supported or unknown.", opt.getOptType());
+ break;
+ }
+ }
+
+ if (reelect) {
+ this.neighbors.electDR(this);
+ }
+
+ // Reset the next timeout timer
+ this.resetTimeout();
+ }
+
+ /* --------------------------------------- Timer functions -------------------------- */
+
+ /**
+ * Restart the timeout task for this neighbor.
+ */
+ private void resetTimeout() {
+
+ if (this.holdtime == 0) {
+
+ // Prepare to die.
+ log.debug("shutting down timer for nbr {}", this.primaryAddr.toString());
+ if (this.timeout != null) {
+ this.timeout.cancel();
+ this.timeout = null;
+ }
+ return;
+ }
+
+ // Cancel the existing timeout and start a fresh new one.
+ if (this.timeout != null) {
+ this.timeout.cancel();
+ }
+
+ this.timeout = PIMTimer.getTimer().newTimeout(new NeighborTimeoutTask(this), holdtime, TimeUnit.SECONDS);
+ }
+
+ /**
+ * The task to run when a neighbor timeout expires.
+ */
+ private final class NeighborTimeoutTask implements TimerTask {
+ PIMNeighbor nbr;
+
+ NeighborTimeoutTask(PIMNeighbor nbr) {
+ this.nbr = nbr;
+ }
+
+ @Override
+ public void run(Timeout timeout) throws Exception {
+
+ // TODO: log.debug;
+ PIMNeighbors neighbors = nbr.neighbors;
+ neighbors.removeNeighbor(nbr.getPrimaryAddr());
+ }
+ }
+
+ /**
+ * Stop the timeout timer.
+ *
+ * This happens when we remove the neighbor.
+ */
+ private final void stopTimeout() {
+ this.timeout.cancel();
+ this.timeout = null;
+ }
+
+ @Override
+ public String toString() {
+ String out = "";
+ if (this.isDr) {
+ out += "*NBR:";
+ } else {
+ out += "NBR:";
+ }
+ out += "\tIP: " + this.primaryAddr.toString();
+ out += "\tPr: " + String.valueOf(this.priority);
+ out += "\tHoldTime: " + String.valueOf(this.holdtime);
+ out += "\tGenID: " + String.valueOf(this.genId) + "\n";
+ return out;
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/apps/pim/src/main/java/org/onosproject/pim/impl/PIMNeighbors.java b/framework/src/onos/apps/pim/src/main/java/org/onosproject/pim/impl/PIMNeighbors.java
new file mode 100644
index 00000000..cad90768
--- /dev/null
+++ b/framework/src/onos/apps/pim/src/main/java/org/onosproject/pim/impl/PIMNeighbors.java
@@ -0,0 +1,395 @@
+
+package org.onosproject.pim.impl;
+
+import org.jboss.netty.util.Timeout;
+import org.jboss.netty.util.TimerTask;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.IPv4;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.PIM;
+import org.onlab.packet.pim.PIMHello;
+import org.onosproject.net.ConnectPoint;
+import java.util.HashMap;
+import java.util.concurrent.TimeUnit;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * PIMNeighbors is a collection of all neighbors we have received
+ * PIM hello messages from. The main structure is a HashMap indexed
+ * by ConnectPoint with another HashMap indexed on the PIM neighbors
+ * IPAddress, it contains all PIM neighbors attached on that ConnectPoint.
+ */
+public final class PIMNeighbors {
+
+ private static Logger log = LoggerFactory.getLogger("PIMNeighbors");
+
+ /**
+ * This is the global container for all PIM neighbors indexed by ConnectPoints.
+ *
+ * NOTE: We'll have a problem if the same neighbor can show up on two interfaces
+ * but that should never happen.
+ */
+ private static HashMap<ConnectPoint, PIMNeighbors> connectPointNeighbors = new HashMap<>();
+
+ // The connect point these neighbors are connected to.
+ private ConnectPoint connectPoint;
+
+ // Pointer to the current designated router on this ConnectPoint.
+ private PIMNeighbor designatedRouter;
+
+ // The list of neighbors we have learned on this ConnectPoint.
+ private HashMap<IpAddress, PIMNeighbor> neighbors = new HashMap<>();
+
+ /*
+ * TODO: turn ourIpAddress, ourPriority and OurHoldTime into config options.
+ */
+ // The IP address we are using to source our PIM hello messages on this connect Point.
+ private IpAddress ourIpAddress;
+
+ // The priority we use on this ConnectPoint.
+ private int ourPriority = 1;
+
+ // The holdtime we are sending out.
+ private int ourHoldtime = 105;
+
+ // Then generation ID we are sending out. 0 means we need to generate a new random ID
+ private int ourGenid = 0;
+
+ // Hello Timer for sending hello messages per ConnectPoint with neighbors.
+ private volatile Timeout helloTimer;
+
+ // The period of which we will be sending out PIM hello messages.
+ private final int defaultPimHelloInterval = 30; // seconds
+
+ /**
+ * Create PIMNeighbors object per ConnectPoint.
+ *
+ * @param cp the ConnectPoint.
+ * @return PIMNeighbors structure
+ */
+ public static PIMNeighbors getConnectPointNeighbors(ConnectPoint cp) {
+ return connectPointNeighbors.get(cp);
+ }
+
+ /**
+ * Process incoming hello message, we will need the Macaddress and IP address of the sender.
+ *
+ * @param ethPkt the ethernet header
+ * @param receivedFrom the connect point we recieved this message from
+ */
+ public static void processHello(Ethernet ethPkt, ConnectPoint receivedFrom) {
+ checkNotNull(ethPkt);
+ checkNotNull(ethPkt);
+
+ MacAddress srcmac = ethPkt.getSourceMAC();
+ IPv4 ip = (IPv4) ethPkt.getPayload();
+ Ip4Address srcip = Ip4Address.valueOf(ip.getSourceAddress());
+
+ PIM pim = (PIM) ip.getPayload();
+ checkNotNull(pim);
+
+ PIMHello hello = (PIMHello) pim.getPayload();
+ checkNotNull(hello);
+
+ PIMNeighbor nbr = PIMNeighbors.findOrCreate(srcip, srcmac, receivedFrom);
+ if (nbr == null) {
+ log.error("Could not create a neighbor for: {1}", srcip.toString());
+ return;
+ }
+
+ nbr.setConnectPoint(receivedFrom);
+ nbr.refresh(hello);
+ }
+
+ /**
+ * Create a PIM Neighbor.
+ *
+ * @param cp The ConnectPoint this neighbor was found on
+ */
+ public PIMNeighbors(ConnectPoint cp) {
+ this.connectPoint = cp;
+
+ // TODO: use network config to assign address.
+ this.ourIpAddress = IpAddress.valueOf("10.2.2.2");
+ this.addIpAddress(this.ourIpAddress);
+ }
+
+ /**
+ * Create a PIM neighbor.
+ *
+ * @param cp the ConnectPoint this neighbor was found on
+ * @param ourIp the IP address of this neighbor
+ */
+ public PIMNeighbors(ConnectPoint cp, IpAddress ourIp) {
+ this.connectPoint = cp;
+ this.addIpAddress(ourIp);
+ }
+
+ /**
+ * Start the hello timer when we have been given an IP address.
+ *
+ * @param ourIp our IP address.
+ */
+ public void addIpAddress(IpAddress ourIp) {
+ this.startHelloTimer();
+
+ // Kick off the first pim hello packet
+ this.sendHelloPacket();
+ }
+
+ /**
+ * Getter for our IP address.
+ *
+ * @return our IP address.
+ */
+ public IpAddress getOurIpAddress() {
+ return this.ourIpAddress;
+ }
+
+ /**
+ * Get our priority.
+ *
+ * @return our priority.
+ */
+ public int getOurPriority() {
+ return this.ourPriority;
+ }
+
+ /**
+ * Get the neighbor list for this specific connectPoint.
+ *
+ * @return PIM neighbors on this ConnectPoint
+ */
+ public HashMap<IpAddress, PIMNeighbor> getOurNeighborsList() {
+ return this.neighbors;
+ }
+
+ /**
+ * Get the designated router on this connection.
+ *
+ * @return the PIMNeighbor representing the DR
+ */
+ public PIMNeighbor getDesignatedRouter() {
+ return designatedRouter;
+ }
+
+ /**
+ * Are we the DR on this CP?
+ *
+ * @return true if we are, false if not
+ */
+ public boolean weAreTheDr() {
+ return (designatedRouter != null &&
+ designatedRouter.getPrimaryAddr().equals(ourIpAddress));
+ }
+
+ /**
+ * Find the neighbor with the given IP address on this CP.
+ *
+ * @param ipaddr the IP address of the neighbor we are interested in
+ * @return the pim neighbor if it exists
+ */
+ public PIMNeighbor findNeighbor(IpAddress ipaddr) {
+ PIMNeighbor nbr = neighbors.get(ipaddr);
+ return nbr;
+ }
+
+ /**
+ * Add a new PIM neighbor to this list.
+ *
+ * @param nbr the neighbor to be added.
+ */
+ public void addNeighbor(PIMNeighbor nbr) {
+ if (neighbors.containsKey(nbr.getPrimaryAddr())) {
+
+ // TODO: Hmmm, how should this be handled?
+ log.debug("We are adding a neighbor that already exists: {}", nbr.toString());
+ neighbors.remove(nbr.getPrimaryAddr(), nbr);
+ }
+ nbr.setNeighbors(this);
+ neighbors.put(nbr.getPrimaryAddr(), nbr);
+ }
+
+ /**
+ * Remove the neighbor from our neighbor list.
+ *
+ * @param ipaddr the IP address of the neighbor to remove
+ */
+ public void removeNeighbor(IpAddress ipaddr) {
+
+ boolean reelect = (designatedRouter == null || designatedRouter.getPrimaryAddr().equals(ipaddr));
+ if (neighbors.containsKey(ipaddr)) {
+ neighbors.remove(ipaddr);
+ }
+ this.electDR();
+ }
+
+ /**
+ * Remove the given neighbor from the neighbor list.
+ *
+ * @param nbr the nbr to be removed.
+ */
+ public void removeNeighbor(PIMNeighbor nbr) {
+
+ boolean reelect = (designatedRouter == null || nbr.isDr());
+ neighbors.remove(nbr.getPrimaryAddr(), nbr);
+ this.electDR();
+ }
+
+ /**
+ * Elect a new DR on this ConnectPoint.
+ *
+ * @return the PIM Neighbor that wins
+ */
+ public PIMNeighbor electDR() {
+
+ for (PIMNeighbor nbr : this.neighbors.values()) {
+ if (this.designatedRouter == null) {
+ this.designatedRouter = nbr;
+ continue;
+ }
+
+ if (nbr.getPriority() > this.designatedRouter.getPriority()) {
+ this.designatedRouter = nbr;
+ continue;
+ }
+
+ // We could sort in ascending order
+ if (this.designatedRouter.getPrimaryAddr().compareTo(nbr.getPrimaryAddr()) > 0) {
+ this.designatedRouter = nbr;
+ continue;
+ }
+ }
+
+ return this.designatedRouter;
+ }
+
+ /**
+ * Elect a new DR given the new neighbor.
+ *
+ * @param nbr the new neighbor to use in DR election.
+ * @return the PIM Neighbor that wins DR election
+ */
+ public PIMNeighbor electDR(PIMNeighbor nbr) {
+
+ // Make sure I have
+ if (this.designatedRouter == null ||
+ this.designatedRouter.getPriority() < nbr.getPriority() ||
+ this.designatedRouter.getPrimaryAddr().compareTo(nbr.getPrimaryAddr()) > 0) {
+ this.designatedRouter = nbr;
+ }
+ return this.designatedRouter;
+ }
+
+ /**
+ * Find or create a pim neighbor with a given ip address and connect point.
+ *
+ * @param ipaddr of the pim neighbor
+ * @param mac The mac address of our sending neighbor
+ * @param cp the connect point the neighbor was learned from
+ * @return an existing or new PIM neighbor
+ */
+ public static PIMNeighbor findOrCreate(IpAddress ipaddr, MacAddress mac, ConnectPoint cp) {
+ PIMNeighbors neighbors = connectPointNeighbors.get(cp);
+ if (neighbors == null) {
+ neighbors = new PIMNeighbors(cp);
+ connectPointNeighbors.put(cp, neighbors);
+ }
+
+ PIMNeighbor nbr = neighbors.findNeighbor(ipaddr);
+ if (nbr == null) {
+ nbr = new PIMNeighbor(ipaddr, mac, cp);
+ neighbors.addNeighbor(nbr);
+ neighbors.electDR(nbr);
+ }
+ return nbr;
+ }
+
+ // Returns the connect point neighbors hash map
+ public static HashMap<ConnectPoint, PIMNeighbors> getConnectPointNeighbors() {
+ return connectPointNeighbors;
+ }
+
+ /* ---------------------------------- PIM Hello Timer ----------------------------------- */
+
+ /**
+ * Start a new hello timer for this ConnectPoint.
+ */
+ private void startHelloTimer() {
+ this.helloTimer = PIMTimer.getTimer().newTimeout(
+ new HelloTimer(this),
+ this.defaultPimHelloInterval,
+ TimeUnit.SECONDS);
+
+ log.trace("Started Hello Timer: " + this.ourIpAddress.toString());
+ }
+
+ /**
+ * This inner class handles transmitting a PIM hello message on this ConnectPoint.
+ */
+ private final class HelloTimer implements TimerTask {
+ PIMNeighbors neighbors;
+
+ HelloTimer(PIMNeighbors neighbors) {
+ this.neighbors = neighbors;
+ }
+
+ @Override
+ public void run(Timeout timeout) throws Exception {
+
+ // Send off a hello packet
+ sendHelloPacket();
+
+ // restart the hello timer
+ neighbors.startHelloTimer();
+ }
+ }
+
+ private void sendHelloPacket() {
+ PIMHello hello = new PIMHello();
+
+ // TODO: we will need to implement the network config service to assign ip addresses & options
+ /*
+ hello.createDefaultOptions();
+
+ Ethernet eth = hello.createPIMHello(this.ourIpAddress);
+ hello.sendPacket(this.connectPoint);
+ */
+ }
+
+ /**
+ * prints the connectPointNeighbors list with each neighbor list.
+ *
+ * @return string of neighbors.
+ */
+ public static String printPimNeighbors() {
+ String out = "PIM Neighbors Table: \n";
+
+ for (PIMNeighbors pn: connectPointNeighbors.values()) {
+
+ out += "CP:\n " + pn.toString();
+ for (PIMNeighbor nbr : pn.neighbors.values()) {
+ out += "\t" + nbr.toString();
+ }
+ }
+ return out;
+ }
+
+ @Override
+ public String toString() {
+ String out = "PIM Neighbors: ";
+ if (this.ourIpAddress != null) {
+ out += "IP: " + this.ourIpAddress.toString();
+ } else {
+ out += "IP: *Null*";
+ }
+ out += "\tPR: " + String.valueOf(this.ourPriority) + "\n";
+ return out;
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/apps/pim/src/main/java/org/onosproject/pim/impl/PIMNeighborsCodec.java b/framework/src/onos/apps/pim/src/main/java/org/onosproject/pim/impl/PIMNeighborsCodec.java
new file mode 100644
index 00000000..ee62eb79
--- /dev/null
+++ b/framework/src/onos/apps/pim/src/main/java/org/onosproject/pim/impl/PIMNeighborsCodec.java
@@ -0,0 +1,97 @@
+/*
+ * 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.pim.impl;
+
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.net.ConnectPoint;
+
+import java.util.HashMap;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * PIM neighbors Codec.
+ */
+public class PIMNeighborsCodec extends JsonCodec<HashMap<ConnectPoint, PIMNeighbors>> {
+ // JSON field names
+ //Return Name
+ private static final String CPNBRLIST = "connect_point_list";
+
+ // PIM Neightbors Fields
+ private static final String IP = "ip";
+ private static final String PRIORITY = "priority";
+ private static final String NBRLIST = "neighbor_list";
+
+ // PIM neighbor Files
+ private static final String DR = "designated";
+ private static final String NBR_IP = "ip";
+ private static final String PR = "priority";
+ private static final String HOLDTIME = "hold_time";
+
+ /**
+ * Encode the PIM Neighbors.
+ *
+ * @param cpn ConnectPoint neighbors
+ * @param context encoding context
+ *
+ * @return Encoded neighbors used by CLI and REST
+ */
+ @Override
+ public ObjectNode encode(HashMap<ConnectPoint, PIMNeighbors> cpn, CodecContext context) {
+ checkNotNull(cpn, "Pim Neighbors cannot be null");
+
+ ObjectNode pimNbrJsonCodec = context.mapper().createObjectNode();
+ ArrayNode cpnList = context.mapper().createArrayNode();
+
+ for (PIMNeighbors pn: cpn.values()) {
+ // get the PimNeighbors Obj, contains Neighbors list
+ // create the json object for a single Entry in the Neighbors list
+ ObjectNode cp = context.mapper().createObjectNode();
+ cp.put(IP, pn.getOurIpAddress().toString());
+ cp.put(PRIORITY, String.valueOf(pn.getOurPriority()));
+
+ // create the array for the neighbors list
+ ArrayNode nbrsList = context.mapper().createArrayNode();
+ for (PIMNeighbor nbr : pn.getOurNeighborsList().values()) {
+ nbrsList.add(neighbor(nbr, context));
+ }
+ // adds pim neighbor to list
+ cp.set(NBRLIST, nbrsList);
+ // adds to arraynode which will represent the connect point neighbors hash map.
+ cpnList.add(cp);
+ }
+ pimNbrJsonCodec.set(CPNBRLIST, cpnList);
+ return pimNbrJsonCodec;
+ }
+
+ /**
+ * Encode a single PIM Neighbor.
+ *
+ * @param nbr the neighbor to be encoded
+ * @param context encoding context
+ * @return the encoded neighbor
+ */
+ private ObjectNode neighbor(PIMNeighbor nbr, CodecContext context) {
+ return context.mapper().createObjectNode()
+ .put(DR, Boolean.toString(nbr.isDr()))
+ .put(NBR_IP, nbr.getPrimaryAddr().toString())
+ .put(PR, String.valueOf(nbr.getPriority()))
+ .put(HOLDTIME, String.valueOf(nbr.getHoldtime()));
+ }
+}
diff --git a/framework/src/onos/apps/pim/src/main/java/org/onosproject/pim/impl/PIMTimer.java b/framework/src/onos/apps/pim/src/main/java/org/onosproject/pim/impl/PIMTimer.java
new file mode 100644
index 00000000..c131a53b
--- /dev/null
+++ b/framework/src/onos/apps/pim/src/main/java/org/onosproject/pim/impl/PIMTimer.java
@@ -0,0 +1,53 @@
+/*
+ * 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.pim.impl;
+
+import org.jboss.netty.util.HashedWheelTimer;
+
+/**
+ * PIM Timer used for PIM Neighbors.
+ */
+public final class PIMTimer {
+
+ private static volatile HashedWheelTimer timer;
+
+ // Ban public construction
+ private PIMTimer() {
+ }
+
+ /**
+ * Returns the singleton hashed-wheel timer.
+ *
+ * @return hashed-wheel timer
+ */
+ public static HashedWheelTimer getTimer() {
+ if (PIMTimer.timer == null) {
+ initTimer();
+ }
+ return PIMTimer.timer;
+ }
+
+ // Start the PIM timer.
+ private static synchronized void initTimer() {
+ if (PIMTimer.timer == null) {
+
+ // Create and start a new hashed wheel timer, if it does not exist.
+ HashedWheelTimer hwTimer = new HashedWheelTimer();
+ hwTimer.start();
+ PIMTimer.timer = hwTimer;
+ }
+ }
+}
diff --git a/framework/src/onos/apps/pim/src/main/java/org/onosproject/pim/impl/package-info.java b/framework/src/onos/apps/pim/src/main/java/org/onosproject/pim/impl/package-info.java
new file mode 100644
index 00000000..29d1ce4e
--- /dev/null
+++ b/framework/src/onos/apps/pim/src/main/java/org/onosproject/pim/impl/package-info.java
@@ -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.
+ */
+
+/**
+ * PIM Emulation speak hello messages and listen to Join/Prunes.
+ */
+package org.onosproject.pim.impl;
diff --git a/framework/src/onos/apps/pim/src/main/resources/OSGI-INF.blueprint/shell-config.xml b/framework/src/onos/apps/pim/src/main/resources/OSGI-INF.blueprint/shell-config.xml
new file mode 100644
index 00000000..c30e3792
--- /dev/null
+++ b/framework/src/onos/apps/pim/src/main/resources/OSGI-INF.blueprint/shell-config.xml
@@ -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.
+ -->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+
+ <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
+ <command>
+ <action class="org.onosproject.pim.cli.PIMShowCommand"/>
+ </command>
+ </command-bundle>
+
+</blueprint>
diff --git a/framework/src/onos/apps/pom.xml b/framework/src/onos/apps/pom.xml
index 334c690b..b955130a 100644
--- a/framework/src/onos/apps/pom.xml
+++ b/framework/src/onos/apps/pom.xml
@@ -53,11 +53,12 @@
<module>olt</module>
<module>cip</module>
<module>flowanalyzer</module>
- <module>vtnrsc</module>
<module>vtn</module>
- <module>vtnweb</module>
<module>dhcp</module>
<module>cordvtn</module>
+ <module>mfwd</module>
+ <module>igmp</module>
+ <module>pim</module>
</modules>
<properties>
diff --git a/framework/src/onos/apps/proxyarp/src/main/java/org/onosproject/proxyarp/ProxyArp.java b/framework/src/onos/apps/proxyarp/src/main/java/org/onosproject/proxyarp/ProxyArp.java
index 2eb96df2..2eb1d5ec 100644
--- a/framework/src/onos/apps/proxyarp/src/main/java/org/onosproject/proxyarp/ProxyArp.java
+++ b/framework/src/onos/apps/proxyarp/src/main/java/org/onosproject/proxyarp/ProxyArp.java
@@ -23,6 +23,8 @@ import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onlab.packet.Ethernet;
+import org.onlab.packet.ICMP6;
+import org.onlab.packet.IPv6;
import org.onosproject.cfg.ComponentConfigService;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
@@ -214,27 +216,35 @@ public class ProxyArp {
if (context.isHandled()) {
return;
}
- // If IPv6 NDP is disabled, don't handle IPv6 frames.
+
InboundPacket pkt = context.inPacket();
Ethernet ethPkt = pkt.parsed();
if (ethPkt == null) {
return;
}
- if (!ipv6NeighborDiscovery && (ethPkt.getEtherType() == TYPE_IPV6)) {
- return;
+
+ if (ethPkt.getEtherType() == TYPE_ARP) {
+ //handle the arp packet.
+ proxyArpService.handlePacket(context);
+ } else if (ipv6NeighborDiscovery && ethPkt.getEtherType() == TYPE_IPV6) {
+ IPv6 ipv6Pkt = (IPv6) ethPkt.getPayload();
+ if (ipv6Pkt.getNextHeader() == IPv6.PROTOCOL_ICMP6) {
+ ICMP6 icmp6Pkt = (ICMP6) ipv6Pkt.getPayload();
+ if (icmp6Pkt.getIcmpType() == NEIGHBOR_SOLICITATION ||
+ icmp6Pkt.getIcmpType() == NEIGHBOR_ADVERTISEMENT) {
+ // handle ICMPv6 solicitations and advertisements
+ proxyArpService.handlePacket(context);
+ }
+ }
}
+ // FIXME why were we listening to IPv4 frames at all?
// Do not ARP for multicast packets. Let mfwd handle them.
if (ethPkt.getEtherType() == Ethernet.TYPE_IPV4) {
if (ethPkt.getDestinationMAC().isMulticast()) {
return;
}
}
-
- //handle the arp packet.
- proxyArpService.handlePacket(context);
}
}
}
-
-
diff --git a/framework/src/onos/apps/reactive-routing/src/main/java/org/onosproject/reactive/routing/LocationType.java b/framework/src/onos/apps/reactive-routing/src/main/java/org/onosproject/reactive/routing/LocationType.java
new file mode 100644
index 00000000..01f4f700
--- /dev/null
+++ b/framework/src/onos/apps/reactive-routing/src/main/java/org/onosproject/reactive/routing/LocationType.java
@@ -0,0 +1,35 @@
+/*
+ * 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.reactive.routing;
+
+/**
+ * Specifies the type of an IP address or an IP prefix location.
+ */
+enum LocationType {
+ /**
+ * The location of an IP address or an IP prefix is in local SDN network.
+ */
+ LOCAL,
+ /**
+ * The location of an IP address or an IP prefix is outside local SDN network.
+ */
+ INTERNET,
+ /**
+ * There is no route for this IP address or IP prefix.
+ */
+ NO_ROUTE
+}
diff --git a/framework/src/onos/apps/reactive-routing/src/main/java/org/onosproject/reactive/routing/ReactiveRoutingFib.java b/framework/src/onos/apps/reactive-routing/src/main/java/org/onosproject/reactive/routing/ReactiveRoutingFib.java
new file mode 100644
index 00000000..8e86056e
--- /dev/null
+++ b/framework/src/onos/apps/reactive-routing/src/main/java/org/onosproject/reactive/routing/ReactiveRoutingFib.java
@@ -0,0 +1,395 @@
+/*
+ * 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.reactive.routing;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Maps;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
+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.Host;
+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.host.HostService;
+import org.onosproject.net.intent.Constraint;
+import org.onosproject.net.intent.Key;
+import org.onosproject.net.intent.MultiPointToSinglePointIntent;
+import org.onosproject.net.intent.constraint.PartialFailureConstraint;
+import org.onosproject.routing.IntentRequestListener;
+import org.onosproject.routing.IntentSynchronizationService;
+import org.onosproject.routing.config.RoutingConfigurationService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * FIB component for reactive routing intents.
+ */
+public class ReactiveRoutingFib implements IntentRequestListener {
+
+ private static final int PRIORITY_OFFSET = 100;
+ private static final int PRIORITY_MULTIPLIER = 5;
+ protected static final ImmutableList<Constraint> CONSTRAINTS
+ = ImmutableList.of(new PartialFailureConstraint());
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ private final ApplicationId appId;
+ private final HostService hostService;
+ private final RoutingConfigurationService configService;
+ private final InterfaceService interfaceService;
+ private final IntentSynchronizationService intentSynchronizer;
+
+ private final Map<IpPrefix, MultiPointToSinglePointIntent> routeIntents;
+
+ /**
+ * Class constructor.
+ *
+ * @param appId application ID to use to generate intents
+ * @param hostService host service
+ * @param configService routing configuration service
+ * @param interfaceService interface service
+ * @param intentSynchronizer intent synchronization service
+ */
+ public ReactiveRoutingFib(ApplicationId appId, HostService hostService,
+ RoutingConfigurationService configService,
+ InterfaceService interfaceService,
+ IntentSynchronizationService intentSynchronizer) {
+ this.appId = appId;
+ this.hostService = hostService;
+ this.configService = configService;
+ this.interfaceService = interfaceService;
+ this.intentSynchronizer = intentSynchronizer;
+
+ routeIntents = Maps.newConcurrentMap();
+ }
+
+ @Override
+ public void setUpConnectivityInternetToHost(IpAddress hostIpAddress) {
+ checkNotNull(hostIpAddress);
+ Set<ConnectPoint> ingressPoints =
+ configService.getBgpPeerConnectPoints();
+
+ TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+
+ if (hostIpAddress.isIp4()) {
+ selector.matchEthType(Ethernet.TYPE_IPV4);
+ } else {
+ selector.matchEthType(Ethernet.TYPE_IPV6);
+ }
+
+ // Match the destination IP prefix at the first hop
+ IpPrefix ipPrefix = hostIpAddress.toIpPrefix();
+ selector.matchIPDst(ipPrefix);
+
+ // Rewrite the destination MAC address
+ MacAddress hostMac = null;
+ ConnectPoint egressPoint = null;
+ for (Host host : hostService.getHostsByIp(hostIpAddress)) {
+ if (host.mac() != null) {
+ hostMac = host.mac();
+ egressPoint = host.location();
+ break;
+ }
+ }
+ if (hostMac == null) {
+ hostService.startMonitoringIp(hostIpAddress);
+ return;
+ }
+
+ TrafficTreatment.Builder treatment =
+ DefaultTrafficTreatment.builder().setEthDst(hostMac);
+ Key key = Key.of(ipPrefix.toString(), appId);
+ int priority = ipPrefix.prefixLength() * PRIORITY_MULTIPLIER
+ + PRIORITY_OFFSET;
+ MultiPointToSinglePointIntent intent =
+ MultiPointToSinglePointIntent.builder()
+ .appId(appId)
+ .key(key)
+ .selector(selector.build())
+ .treatment(treatment.build())
+ .ingressPoints(ingressPoints)
+ .egressPoint(egressPoint)
+ .priority(priority)
+ .constraints(CONSTRAINTS)
+ .build();
+
+ log.trace("Generates ConnectivityInternetToHost intent {}", intent);
+ submitReactiveIntent(ipPrefix, intent);
+ }
+
+ @Override
+ public void setUpConnectivityHostToInternet(IpAddress hostIp, IpPrefix prefix,
+ IpAddress nextHopIpAddress) {
+ // Find the attachment point (egress interface) of the next hop
+ Interface egressInterface = interfaceService.getMatchingInterface(nextHopIpAddress);
+ if (egressInterface == null) {
+ log.warn("No outgoing interface found for {}",
+ nextHopIpAddress);
+ return;
+ }
+
+ Set<Host> hosts = hostService.getHostsByIp(nextHopIpAddress);
+ if (hosts.isEmpty()) {
+ log.warn("No host found for next hop IP address");
+ return;
+ }
+ MacAddress nextHopMacAddress = null;
+ for (Host host : hosts) {
+ nextHopMacAddress = host.mac();
+ break;
+ }
+
+ hosts = hostService.getHostsByIp(hostIp);
+ if (hosts.isEmpty()) {
+ log.warn("No host found for host IP address");
+ return;
+ }
+ Host host = hosts.stream().findFirst().get();
+ ConnectPoint ingressPoint = host.location();
+
+ // Generate the intent itself
+ ConnectPoint egressPort = egressInterface.connectPoint();
+ log.debug("Generating intent for prefix {}, next hop mac {}",
+ prefix, nextHopMacAddress);
+
+ // Match the destination IP prefix at the first hop
+ TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+ if (prefix.isIp4()) {
+ selector.matchEthType(Ethernet.TYPE_IPV4);
+ selector.matchIPDst(prefix);
+ } else {
+ selector.matchEthType(Ethernet.TYPE_IPV6);
+ selector.matchIPv6Dst(prefix);
+ }
+
+ // Rewrite the destination MAC address
+ TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
+ .setEthDst(nextHopMacAddress);
+ if (!egressInterface.vlan().equals(VlanId.NONE)) {
+ treatment.setVlanId(egressInterface.vlan());
+ // If we set VLAN ID, we have to make sure a VLAN tag exists.
+ // TODO support no VLAN -> VLAN routing
+ selector.matchVlanId(VlanId.ANY);
+ }
+
+ int priority = prefix.prefixLength() * PRIORITY_MULTIPLIER + PRIORITY_OFFSET;
+ Key key = Key.of(prefix.toString() + "-reactive", appId);
+ MultiPointToSinglePointIntent intent = MultiPointToSinglePointIntent.builder()
+ .appId(appId)
+ .key(key)
+ .selector(selector.build())
+ .treatment(treatment.build())
+ .ingressPoints(Collections.singleton(ingressPoint))
+ .egressPoint(egressPort)
+ .priority(priority)
+ .constraints(CONSTRAINTS)
+ .build();
+
+ submitReactiveIntent(prefix, intent);
+ }
+
+ @Override
+ public void setUpConnectivityHostToHost(IpAddress dstIpAddress,
+ IpAddress srcIpAddress,
+ MacAddress srcMacAddress,
+ ConnectPoint srcConnectPoint) {
+ checkNotNull(dstIpAddress);
+ checkNotNull(srcIpAddress);
+ checkNotNull(srcMacAddress);
+ checkNotNull(srcConnectPoint);
+
+ IpPrefix srcIpPrefix = srcIpAddress.toIpPrefix();
+ IpPrefix dstIpPrefix = dstIpAddress.toIpPrefix();
+ ConnectPoint dstConnectPoint = null;
+ MacAddress dstMacAddress = null;
+
+ for (Host host : hostService.getHostsByIp(dstIpAddress)) {
+ if (host.mac() != null) {
+ dstMacAddress = host.mac();
+ dstConnectPoint = host.location();
+ break;
+ }
+ }
+ if (dstMacAddress == null) {
+ hostService.startMonitoringIp(dstIpAddress);
+ return;
+ }
+
+ //
+ // Handle intent from source host to destination host
+ //
+ MultiPointToSinglePointIntent srcToDstIntent =
+ hostToHostIntentGenerator(dstIpAddress, dstConnectPoint,
+ dstMacAddress, srcConnectPoint);
+ submitReactiveIntent(dstIpPrefix, srcToDstIntent);
+
+ //
+ // Handle intent from destination host to source host
+ //
+
+ // Since we proactively handle the intent from destination host to
+ // source host, we should check whether there is an exiting intent
+ // first.
+ if (mp2pIntentExists(srcIpPrefix)) {
+ updateExistingMp2pIntent(srcIpPrefix, dstConnectPoint);
+ return;
+ } else {
+ // There is no existing intent, create a new one.
+ MultiPointToSinglePointIntent dstToSrcIntent =
+ hostToHostIntentGenerator(srcIpAddress, srcConnectPoint,
+ srcMacAddress, dstConnectPoint);
+ submitReactiveIntent(srcIpPrefix, dstToSrcIntent);
+ }
+ }
+
+ /**
+ * Generates MultiPointToSinglePointIntent for both source host and
+ * destination host located in local SDN network.
+ *
+ * @param dstIpAddress the destination IP address
+ * @param dstConnectPoint the destination host connect point
+ * @param dstMacAddress the MAC address of destination host
+ * @param srcConnectPoint the connect point where packet-in from
+ * @return the generated MultiPointToSinglePointIntent
+ */
+ private MultiPointToSinglePointIntent hostToHostIntentGenerator(
+ IpAddress dstIpAddress,
+ ConnectPoint dstConnectPoint,
+ MacAddress dstMacAddress,
+ ConnectPoint srcConnectPoint) {
+ checkNotNull(dstIpAddress);
+ checkNotNull(dstConnectPoint);
+ checkNotNull(dstMacAddress);
+ checkNotNull(srcConnectPoint);
+
+ Set<ConnectPoint> ingressPoints = new HashSet<>();
+ ingressPoints.add(srcConnectPoint);
+ IpPrefix dstIpPrefix = dstIpAddress.toIpPrefix();
+
+ TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+ if (dstIpAddress.isIp4()) {
+ selector.matchEthType(Ethernet.TYPE_IPV4);
+ selector.matchIPDst(dstIpPrefix);
+ } else {
+ selector.matchEthType(Ethernet.TYPE_IPV6);
+ selector.matchIPv6Dst(dstIpPrefix);
+ }
+
+ // Rewrite the destination MAC address
+ TrafficTreatment.Builder treatment =
+ DefaultTrafficTreatment.builder().setEthDst(dstMacAddress);
+
+ Key key = Key.of(dstIpPrefix.toString(), appId);
+ int priority = dstIpPrefix.prefixLength() * PRIORITY_MULTIPLIER
+ + PRIORITY_OFFSET;
+ MultiPointToSinglePointIntent intent =
+ MultiPointToSinglePointIntent.builder()
+ .appId(appId)
+ .key(key)
+ .selector(selector.build())
+ .treatment(treatment.build())
+ .ingressPoints(ingressPoints)
+ .egressPoint(dstConnectPoint)
+ .priority(priority)
+ .constraints(CONSTRAINTS)
+ .build();
+
+ log.trace("Generates ConnectivityHostToHost = {} ", intent);
+ return intent;
+ }
+
+ @Override
+ public void updateExistingMp2pIntent(IpPrefix ipPrefix,
+ ConnectPoint ingressConnectPoint) {
+ checkNotNull(ipPrefix);
+ checkNotNull(ingressConnectPoint);
+
+ MultiPointToSinglePointIntent existingIntent =
+ getExistingMp2pIntent(ipPrefix);
+ if (existingIntent != null) {
+ Set<ConnectPoint> ingressPoints = existingIntent.ingressPoints();
+ // Add host connect point into ingressPoints of the existing intent
+ if (ingressPoints.add(ingressConnectPoint)) {
+ MultiPointToSinglePointIntent updatedMp2pIntent =
+ MultiPointToSinglePointIntent.builder()
+ .appId(appId)
+ .key(existingIntent.key())
+ .selector(existingIntent.selector())
+ .treatment(existingIntent.treatment())
+ .ingressPoints(ingressPoints)
+ .egressPoint(existingIntent.egressPoint())
+ .priority(existingIntent.priority())
+ .constraints(CONSTRAINTS)
+ .build();
+
+ log.trace("Update an existing MultiPointToSinglePointIntent "
+ + "to new intent = {} ", updatedMp2pIntent);
+ submitReactiveIntent(ipPrefix, updatedMp2pIntent);
+ }
+ // If adding ingressConnectPoint to ingressPoints failed, it
+ // because between the time interval from checking existing intent
+ // to generating new intent, onos updated this intent due to other
+ // packet-in and the new intent also includes the
+ // ingressConnectPoint. This will not affect reactive routing.
+ }
+ }
+
+ /**
+ * Submits a reactive intent to the intent synchronizer.
+ *
+ * @param ipPrefix IP prefix of the intent
+ * @param intent intent to submit
+ */
+ void submitReactiveIntent(IpPrefix ipPrefix, MultiPointToSinglePointIntent intent) {
+ routeIntents.put(ipPrefix, intent);
+
+ intentSynchronizer.submit(intent);
+ }
+
+ /**
+ * Gets the existing MultiPointToSinglePointIntent from memory for a given
+ * IP prefix.
+ *
+ * @param ipPrefix the IP prefix used to find MultiPointToSinglePointIntent
+ * @return the MultiPointToSinglePointIntent if found, otherwise null
+ */
+ private MultiPointToSinglePointIntent getExistingMp2pIntent(IpPrefix ipPrefix) {
+ checkNotNull(ipPrefix);
+ return routeIntents.get(ipPrefix);
+ }
+
+ @Override
+ public boolean mp2pIntentExists(IpPrefix ipPrefix) {
+ checkNotNull(ipPrefix);
+ return routeIntents.get(ipPrefix) != null;
+ }
+}
diff --git a/framework/src/onos/apps/reactive-routing/src/main/java/org/onosproject/reactive/routing/SdnIpReactiveRouting.java b/framework/src/onos/apps/reactive-routing/src/main/java/org/onosproject/reactive/routing/SdnIpReactiveRouting.java
index ad78a1ce..96aa06ee 100644
--- a/framework/src/onos/apps/reactive-routing/src/main/java/org/onosproject/reactive/routing/SdnIpReactiveRouting.java
+++ b/framework/src/onos/apps/reactive-routing/src/main/java/org/onosproject/reactive/routing/SdnIpReactiveRouting.java
@@ -25,27 +25,39 @@ import org.onlab.packet.EthType;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IPv4;
import org.onlab.packet.Ip4Address;
+import org.onlab.packet.Ip6Address;
import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
+import org.onosproject.incubator.net.intf.Interface;
+import org.onosproject.incubator.net.intf.InterfaceService;
import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.Host;
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.host.HostService;
import org.onosproject.net.packet.DefaultOutboundPacket;
import org.onosproject.net.packet.InboundPacket;
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.routing.IntentRequestListener;
+import org.onosproject.routing.RouteEntry;
import org.onosproject.routing.RoutingService;
+import org.onosproject.routing.SdnIpService;
import org.onosproject.routing.config.RoutingConfigurationService;
import org.slf4j.Logger;
import java.nio.ByteBuffer;
+import java.util.Optional;
+import java.util.Set;
+import static com.google.common.base.Preconditions.checkNotNull;
import static org.onlab.packet.Ethernet.TYPE_ARP;
import static org.onlab.packet.Ethernet.TYPE_IPV4;
import static org.onosproject.net.packet.PacketPriority.REACTIVE;
@@ -74,16 +86,32 @@ public class SdnIpReactiveRouting {
protected RoutingService routingService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected SdnIpService sdnIpService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected RoutingConfigurationService config;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected InterfaceService interfaceService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected HostService hostService;
+
private ApplicationId appId;
+ private IntentRequestListener intentRequestListener;
+
private ReactiveRoutingProcessor processor =
new ReactiveRoutingProcessor();
@Activate
public void activate() {
appId = coreService.registerApplication(APP_NAME);
+
+ intentRequestListener = new ReactiveRoutingFib(appId, hostService,
+ config, interfaceService,
+ sdnIpService.getIntentSynchronizationService());
+
packetService.addProcessor(processor, PacketProcessor.director(2));
requestIntercepts();
log.info("SDN-IP Reactive Routing Started");
@@ -168,12 +196,11 @@ public class SdnIpReactiveRouting {
IpAddress srcIp =
IpAddress.valueOf(ipv4Packet.getSourceAddress());
MacAddress srcMac = ethPkt.getSourceMAC();
- routingService.packetReactiveProcessor(dstIp, srcIp,
- srcConnectPoint, srcMac);
+ packetReactiveProcessor(dstIp, srcIp, srcConnectPoint, srcMac);
// TODO emit packet first or packetReactiveProcessor first
ConnectPoint egressConnectPoint = null;
- egressConnectPoint = routingService.getEgressConnectPoint(dstIp);
+ egressConnectPoint = getEgressConnectPoint(dstIp);
if (egressConnectPoint != null) {
forwardPacketToDst(context, egressConnectPoint);
}
@@ -185,6 +212,173 @@ public class SdnIpReactiveRouting {
}
/**
+ * Routes packet reactively.
+ *
+ * @param dstIpAddress the destination IP address of a packet
+ * @param srcIpAddress the source IP address of a packet
+ * @param srcConnectPoint the connect point where a packet comes from
+ * @param srcMacAddress the source MAC address of a packet
+ */
+ private void packetReactiveProcessor(IpAddress dstIpAddress,
+ IpAddress srcIpAddress,
+ ConnectPoint srcConnectPoint,
+ MacAddress srcMacAddress) {
+ checkNotNull(dstIpAddress);
+ checkNotNull(srcIpAddress);
+ checkNotNull(srcConnectPoint);
+ checkNotNull(srcMacAddress);
+
+ //
+ // Step1: Try to update the existing intent first if it exists.
+ //
+ IpPrefix ipPrefix = null;
+ RouteEntry routeEntry = null;
+ if (config.isIpAddressLocal(dstIpAddress)) {
+ if (dstIpAddress.isIp4()) {
+ ipPrefix = IpPrefix.valueOf(dstIpAddress,
+ Ip4Address.BIT_LENGTH);
+ } else {
+ ipPrefix = IpPrefix.valueOf(dstIpAddress,
+ Ip6Address.BIT_LENGTH);
+ }
+ } else {
+ // Get IP prefix from BGP route table
+ routeEntry = routingService.getLongestMatchableRouteEntry(dstIpAddress);
+ if (routeEntry != null) {
+ ipPrefix = routeEntry.prefix();
+ }
+ }
+ if (ipPrefix != null
+ && intentRequestListener.mp2pIntentExists(ipPrefix)) {
+ intentRequestListener.updateExistingMp2pIntent(ipPrefix,
+ srcConnectPoint);
+ return;
+ }
+
+ //
+ // Step2: There is no existing intent for the destination IP address.
+ // Check whether it is necessary to create a new one. If necessary then
+ // create a new one.
+ //
+ TrafficType trafficType =
+ trafficTypeClassifier(srcConnectPoint, dstIpAddress);
+
+ switch (trafficType) {
+ case HOST_TO_INTERNET:
+ // If the destination IP address is outside the local SDN network.
+ // The Step 1 has already handled it. We do not need to do anything here.
+ intentRequestListener.setUpConnectivityHostToInternet(srcIpAddress,
+ ipPrefix, routeEntry.nextHop());
+ break;
+ case INTERNET_TO_HOST:
+ intentRequestListener.setUpConnectivityInternetToHost(dstIpAddress);
+ break;
+ case HOST_TO_HOST:
+ intentRequestListener.setUpConnectivityHostToHost(dstIpAddress,
+ srcIpAddress, srcMacAddress, srcConnectPoint);
+ break;
+ case INTERNET_TO_INTERNET:
+ log.trace("This is transit traffic, "
+ + "the intent should be preinstalled already");
+ break;
+ case DROP:
+ // TODO here should setUpDropPacketIntent(...);
+ // We need a new type of intent here.
+ break;
+ case UNKNOWN:
+ log.trace("This is unknown traffic, so we do nothing");
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * Classifies the traffic and return the traffic type.
+ *
+ * @param srcConnectPoint the connect point where the packet comes from
+ * @param dstIp the destination IP address in packet
+ * @return the traffic type which this packet belongs to
+ */
+ private TrafficType trafficTypeClassifier(ConnectPoint srcConnectPoint,
+ IpAddress dstIp) {
+ LocationType dstIpLocationType = getLocationType(dstIp);
+ Optional<Interface> srcInterface =
+ interfaceService.getInterfacesByPort(srcConnectPoint).stream().findFirst();
+ Set<ConnectPoint> ingressPoints = config.getBgpPeerConnectPoints();
+
+ switch (dstIpLocationType) {
+ case INTERNET:
+ if (srcInterface.isPresent() &&
+ (!ingressPoints.contains(srcConnectPoint))) {
+ return TrafficType.HOST_TO_INTERNET;
+ } else {
+ return TrafficType.INTERNET_TO_INTERNET;
+ }
+ case LOCAL:
+ if (srcInterface.isPresent() &&
+ (!ingressPoints.contains(srcConnectPoint))) {
+ return TrafficType.HOST_TO_HOST;
+ } else {
+ // TODO Currently we only consider local public prefixes.
+ // In the future, we will consider the local private prefixes.
+ // If dstIpLocationType is a local private, we should return
+ // TrafficType.DROP.
+ return TrafficType.INTERNET_TO_HOST;
+ }
+ case NO_ROUTE:
+ return TrafficType.DROP;
+ default:
+ return TrafficType.UNKNOWN;
+ }
+ }
+
+ /**
+ * Evaluates the location of an IP address and returns the location type.
+ *
+ * @param ipAddress the IP address to evaluate
+ * @return the IP address location type
+ */
+ private LocationType getLocationType(IpAddress ipAddress) {
+ if (config.isIpAddressLocal(ipAddress)) {
+ return LocationType.LOCAL;
+ } else if (routingService.getLongestMatchableRouteEntry(ipAddress) != null) {
+ return LocationType.INTERNET;
+ } else {
+ return LocationType.NO_ROUTE;
+ }
+ }
+
+ public ConnectPoint getEgressConnectPoint(IpAddress dstIpAddress) {
+ LocationType type = getLocationType(dstIpAddress);
+ if (type == LocationType.LOCAL) {
+ Set<Host> hosts = hostService.getHostsByIp(dstIpAddress);
+ if (!hosts.isEmpty()) {
+ return hosts.iterator().next().location();
+ } else {
+ hostService.startMonitoringIp(dstIpAddress);
+ return null;
+ }
+ } else if (type == LocationType.INTERNET) {
+ IpAddress nextHopIpAddress = null;
+ RouteEntry routeEntry = routingService.getLongestMatchableRouteEntry(dstIpAddress);
+ if (routeEntry != null) {
+ nextHopIpAddress = routeEntry.nextHop();
+ Interface it = interfaceService.getMatchingInterface(nextHopIpAddress);
+ if (it != null) {
+ return it.connectPoint();
+ } else {
+ return null;
+ }
+ } else {
+ return null;
+ }
+ } else {
+ return null;
+ }
+ }
+
+ /**
* Emits the specified packet onto the network.
*
* @param context the packet context
diff --git a/framework/src/onos/apps/reactive-routing/src/main/java/org/onosproject/reactive/routing/TrafficType.java b/framework/src/onos/apps/reactive-routing/src/main/java/org/onosproject/reactive/routing/TrafficType.java
new file mode 100644
index 00000000..134126b3
--- /dev/null
+++ b/framework/src/onos/apps/reactive-routing/src/main/java/org/onosproject/reactive/routing/TrafficType.java
@@ -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.reactive.routing;
+
+/**
+ * Specifies the type of traffic.
+ * <p>
+ * We classify traffic by the first packet of each traffic.
+ * </p>
+ */
+enum TrafficType {
+ /**
+ * Traffic from a host located in local SDN network wants to
+ * communicate with destination host located in Internet (outside
+ * local SDN network).
+ */
+ HOST_TO_INTERNET,
+ /**
+ * Traffic from Internet wants to communicate with a host located
+ * in local SDN network.
+ */
+ INTERNET_TO_HOST,
+ /**
+ * Both the source host and destination host of a traffic are in
+ * local SDN network.
+ */
+ HOST_TO_HOST,
+ /**
+ * Traffic from Internet wants to traverse local SDN network.
+ */
+ INTERNET_TO_INTERNET,
+ /**
+ * Any traffic wants to communicate with a destination which has
+ * no route, or traffic from Internet wants to access a local private
+ * IP address.
+ */
+ DROP,
+ /**
+ * Traffic does not belong to the types above.
+ */
+ UNKNOWN
+}
diff --git a/framework/src/onos/apps/routing-api/src/main/java/org/onosproject/routing/IntentRequestListener.java b/framework/src/onos/apps/routing-api/src/main/java/org/onosproject/routing/IntentRequestListener.java
index 2d1bb311..1069ec5a 100644
--- a/framework/src/onos/apps/routing-api/src/main/java/org/onosproject/routing/IntentRequestListener.java
+++ b/framework/src/onos/apps/routing-api/src/main/java/org/onosproject/routing/IntentRequestListener.java
@@ -47,6 +47,16 @@ public interface IntentRequestListener {
ConnectPoint srcConnectPoint);
/**
+ * Sets up connectivity for packet from a local host to the Internet.
+ *
+ * @param hostIp IP address of the local host
+ * @param prefix external IP prefix that the host is talking to
+ * @param nextHopIpAddress IP address of the next hop router for the prefix
+ */
+ void setUpConnectivityHostToInternet(IpAddress hostIp, IpPrefix prefix,
+ IpAddress nextHopIpAddress);
+
+ /**
* Adds one new ingress connect point into ingress points of an existing
* intent and resubmits the new intent.
* <p>
diff --git a/framework/src/onos/apps/routing-api/src/main/java/org/onosproject/routing/IntentSynchronizationService.java b/framework/src/onos/apps/routing-api/src/main/java/org/onosproject/routing/IntentSynchronizationService.java
new file mode 100644
index 00000000..dc6a838d
--- /dev/null
+++ b/framework/src/onos/apps/routing-api/src/main/java/org/onosproject/routing/IntentSynchronizationService.java
@@ -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.routing;
+
+import org.onosproject.net.intent.Intent;
+
+/**
+ * Submits and withdraws intents to the IntentService from a single point in
+ * the cluster at any one time. The provided intents will be synchronized with
+ * the IntentService on leadership change.
+ */
+public interface IntentSynchronizationService {
+
+ /**
+ * Submits and intent to the synchronizer.
+ * <p>
+ * The intent will be submitted directly to the IntentService if this node
+ * is the leader, otherwise it will be stored in the synchronizer for
+ * synchronization if this node becomes the leader.
+ * </p>
+ *
+ * @param intent intent to submit
+ */
+ void submit(Intent intent);
+
+ /**
+ * Withdraws an intent from the synchronizer.
+ * <p>
+ * The intent will be withdrawn directly from the IntentService if this node
+ * is the leader. The intent will be removed from the synchronizer's
+ * in-memory storage.
+ * </p>
+ *
+ * @param intent intent to withdraw
+ */
+ void withdraw(Intent intent);
+}
diff --git a/framework/src/onos/apps/routing-api/src/main/java/org/onosproject/routing/RoutingService.java b/framework/src/onos/apps/routing-api/src/main/java/org/onosproject/routing/RoutingService.java
index 8b7040e2..7399ed75 100644
--- a/framework/src/onos/apps/routing-api/src/main/java/org/onosproject/routing/RoutingService.java
+++ b/framework/src/onos/apps/routing-api/src/main/java/org/onosproject/routing/RoutingService.java
@@ -16,8 +16,6 @@
package org.onosproject.routing;
import org.onlab.packet.IpAddress;
-import org.onlab.packet.MacAddress;
-import org.onosproject.net.ConnectPoint;
import org.onosproject.routing.config.BgpConfig;
import java.util.Collection;
@@ -32,63 +30,6 @@ public interface RoutingService {
Class<BgpConfig> CONFIG_CLASS = BgpConfig.class;
/**
- * Specifies the type of an IP address or an IP prefix location.
- */
- enum LocationType {
- /**
- * The location of an IP address or an IP prefix is in local SDN network.
- */
- LOCAL,
- /**
- * The location of an IP address or an IP prefix is outside local SDN network.
- */
- INTERNET,
- /**
- * There is no route for this IP address or IP prefix.
- */
- NO_ROUTE
- }
-
- /**
- * Specifies the type of traffic.
- * <p>
- * We classify traffic by the first packet of each traffic.
- * </p>
- */
- enum TrafficType {
- /**
- * Traffic from a host located in local SDN network wants to
- * communicate with destination host located in Internet (outside
- * local SDN network).
- */
- HOST_TO_INTERNET,
- /**
- * Traffic from Internet wants to communicate with a host located
- * in local SDN network.
- */
- INTERNET_TO_HOST,
- /**
- * Both the source host and destination host of a traffic are in
- * local SDN network.
- */
- HOST_TO_HOST,
- /**
- * Traffic from Internet wants to traverse local SDN network.
- */
- INTERNET_TO_INTERNET,
- /**
- * Any traffic wants to communicate with a destination which has
- * no route, or traffic from Internet wants to access a local private
- * IP address.
- */
- DROP,
- /**
- * Traffic does not belong to the types above.
- */
- UNKNOWN
- }
-
- /**
* Starts the routing service.
*/
void start();
@@ -101,15 +42,6 @@ public interface RoutingService {
void addFibListener(FibListener fibListener);
/**
- * Adds intent creation and submission listener.
- *
- * @param intentRequestListener listener to send intent creation and
- * submission request to
- */
- void addIntentRequestListener(IntentRequestListener
- intentRequestListener);
-
- /**
* Stops the routing service.
*/
void stop();
@@ -129,14 +61,6 @@ public interface RoutingService {
Collection<RouteEntry> getRoutes6();
/**
- * Evaluates the location of an IP address and returns the location type.
- *
- * @param ipAddress the IP address to evaluate
- * @return the IP address location type
- */
- LocationType getLocationType(IpAddress ipAddress);
-
- /**
* Finds out the route entry which has the longest matchable IP prefix.
*
* @param ipAddress IP address used to find out longest matchable IP prefix
@@ -145,25 +69,4 @@ public interface RoutingService {
*/
RouteEntry getLongestMatchableRouteEntry(IpAddress ipAddress);
- /**
- * Finds out the egress connect point where to emit the first packet
- * based on destination IP address.
- *
- * @param dstIpAddress the destination IP address
- * @return the egress connect point if found, otherwise null
- */
- ConnectPoint getEgressConnectPoint(IpAddress dstIpAddress);
-
- /**
- * Routes packet reactively.
- *
- * @param dstIpAddress the destination IP address of a packet
- * @param srcIpAddress the source IP address of a packet
- * @param srcConnectPoint the connect point where a packet comes from
- * @param srcMacAddress the source MAC address of a packet
- */
- void packetReactiveProcessor(IpAddress dstIpAddress,
- IpAddress srcIpAddress,
- ConnectPoint srcConnectPoint,
- MacAddress srcMacAddress);
}
diff --git a/framework/src/onos/apps/routing-api/src/main/java/org/onosproject/routing/SdnIpService.java b/framework/src/onos/apps/routing-api/src/main/java/org/onosproject/routing/SdnIpService.java
new file mode 100644
index 00000000..0945336c
--- /dev/null
+++ b/framework/src/onos/apps/routing-api/src/main/java/org/onosproject/routing/SdnIpService.java
@@ -0,0 +1,39 @@
+/*
+ * 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.routing;
+
+/**
+ * Service interface exported by SDN-IP.
+ */
+public interface SdnIpService {
+
+ /**
+ * Changes whether this SDN-IP instance is the primary or not based on the
+ * boolean parameter.
+ *
+ * @param isPrimary true if the instance is primary, false if it is not
+ */
+ void modifyPrimary(boolean isPrimary);
+
+ /**
+ * Gets the intent synchronization service.
+ *
+ * @return intent synchronization service
+ */
+ // TODO fix service resolution in SDN-IP
+ IntentSynchronizationService getIntentSynchronizationService();
+
+}
diff --git a/framework/src/onos/apps/routing-api/src/test/java/org/onosproject/routing/RouteEntryTest.java b/framework/src/onos/apps/routing-api/src/test/java/org/onosproject/routing/RouteEntryTest.java
index c47d2768..b89eb2d1 100644
--- a/framework/src/onos/apps/routing-api/src/test/java/org/onosproject/routing/RouteEntryTest.java
+++ b/framework/src/onos/apps/routing-api/src/test/java/org/onosproject/routing/RouteEntryTest.java
@@ -19,10 +19,15 @@ import org.hamcrest.Matchers;
import org.junit.Test;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
+import org.onlab.packet.Ip6Address;
+import org.onlab.packet.Ip6Prefix;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
* Unit tests for the RouteEntry class.
@@ -35,17 +40,22 @@ public class RouteEntryTest {
public void testConstructor() {
Ip4Prefix prefix = Ip4Prefix.valueOf("1.2.3.0/24");
Ip4Address nextHop = Ip4Address.valueOf("5.6.7.8");
-
RouteEntry routeEntry = new RouteEntry(prefix, nextHop);
assertThat(routeEntry.toString(),
is("RouteEntry{prefix=1.2.3.0/24, nextHop=5.6.7.8}"));
+
+ Ip6Prefix prefix6 = Ip6Prefix.valueOf("1000::/64");
+ Ip6Address nextHop6 = Ip6Address.valueOf("2000::1");
+ RouteEntry routeEntry6 = new RouteEntry(prefix6, nextHop6);
+ assertThat(routeEntry6.toString(),
+ is("RouteEntry{prefix=1000::/64, nextHop=2000::1}"));
}
/**
* Tests invalid class constructor for null IPv4 prefix.
*/
@Test(expected = NullPointerException.class)
- public void testInvalidConstructorNullPrefix() {
+ public void testInvalidConstructorNullIpv4Prefix() {
Ip4Prefix prefix = null;
Ip4Address nextHop = Ip4Address.valueOf("5.6.7.8");
@@ -53,10 +63,21 @@ public class RouteEntryTest {
}
/**
+ * Tests invalid class constructor for null IPv6 prefix.
+ */
+ @Test(expected = NullPointerException.class)
+ public void testInvalidConstructorNullIpv6Prefix() {
+ Ip6Prefix prefix = null;
+ Ip6Address nextHop = Ip6Address.valueOf("2000::1");
+
+ new RouteEntry(prefix, nextHop);
+ }
+
+ /**
* Tests invalid class constructor for null IPv4 next-hop.
*/
@Test(expected = NullPointerException.class)
- public void testInvalidConstructorNullNextHop() {
+ public void testInvalidConstructorNullIpv4NextHop() {
Ip4Prefix prefix = Ip4Prefix.valueOf("1.2.3.0/24");
Ip4Address nextHop = null;
@@ -64,16 +85,32 @@ public class RouteEntryTest {
}
/**
+ * Tests invalid class constructor for null IPv6 next-hop.
+ */
+ @Test(expected = NullPointerException.class)
+ public void testInvalidConstructorNullIpv6NextHop() {
+ Ip6Prefix prefix = Ip6Prefix.valueOf("1000::/64");
+ Ip6Address nextHop = null;
+
+ new RouteEntry(prefix, nextHop);
+ }
+
+ /**
* Tests getting the fields of a route entry.
*/
@Test
public void testGetFields() {
Ip4Prefix prefix = Ip4Prefix.valueOf("1.2.3.0/24");
Ip4Address nextHop = Ip4Address.valueOf("5.6.7.8");
-
RouteEntry routeEntry = new RouteEntry(prefix, nextHop);
assertThat(routeEntry.prefix(), is(prefix));
assertThat(routeEntry.nextHop(), is(nextHop));
+
+ Ip6Prefix prefix6 = Ip6Prefix.valueOf("1000::/64");
+ Ip6Address nextHop6 = Ip6Address.valueOf("2000::1");
+ RouteEntry routeEntry6 = new RouteEntry(prefix6, nextHop6);
+ assertThat(routeEntry6.prefix(), is(prefix6));
+ assertThat(routeEntry6.nextHop(), is(nextHop6));
}
/**
@@ -105,6 +142,33 @@ public class RouteEntryTest {
prefix = Ip4Prefix.valueOf("255.255.255.255/32");
assertThat(RouteEntry.createBinaryString(prefix),
is("11111111111111111111111111111111"));
+
+ Ip6Prefix prefix6;
+ Pattern pattern;
+ Matcher matcher;
+
+ prefix6 = Ip6Prefix.valueOf("::/0");
+ assertThat(RouteEntry.createBinaryString(prefix6), is(""));
+
+ prefix6 = Ip6Prefix.valueOf("2000::1000/112");
+ pattern = Pattern.compile("00100{108}");
+ matcher = pattern.matcher(RouteEntry.createBinaryString(prefix6));
+ assertTrue(matcher.matches());
+
+ prefix6 = Ip6Prefix.valueOf("2000::1000/116");
+ pattern = Pattern.compile("00100{108}0001");
+ matcher = pattern.matcher(RouteEntry.createBinaryString(prefix6));
+ assertTrue(matcher.matches());
+
+ prefix6 = Ip6Prefix.valueOf("2000::2000/116");
+ pattern = Pattern.compile("00100{108}0010");
+ matcher = pattern.matcher(RouteEntry.createBinaryString(prefix6));
+ assertTrue(matcher.matches());
+
+ prefix6 = Ip6Prefix.valueOf("2000::1234/128");
+ pattern = Pattern.compile("00100{108}0001001000110100");
+ matcher = pattern.matcher(RouteEntry.createBinaryString(prefix6));
+ assertTrue(matcher.matches());
}
/**
@@ -121,6 +185,16 @@ public class RouteEntryTest {
RouteEntry routeEntry2 = new RouteEntry(prefix2, nextHop2);
assertThat(routeEntry1, is(routeEntry2));
+
+ Ip6Prefix prefix3 = Ip6Prefix.valueOf("1000::/64");
+ Ip6Address nextHop3 = Ip6Address.valueOf("2000::2");
+ RouteEntry routeEntry3 = new RouteEntry(prefix3, nextHop3);
+
+ Ip6Prefix prefix4 = Ip6Prefix.valueOf("1000::/64");
+ Ip6Address nextHop4 = Ip6Address.valueOf("2000::2");
+ RouteEntry routeEntry4 = new RouteEntry(prefix4, nextHop4);
+
+ assertThat(routeEntry3, is(routeEntry4));
}
/**
@@ -142,6 +216,21 @@ public class RouteEntryTest {
assertThat(routeEntry1, Matchers.is(not(routeEntry2)));
assertThat(routeEntry1, Matchers.is(not(routeEntry3)));
+
+ Ip6Prefix prefix4 = Ip6Prefix.valueOf("1000::/64");
+ Ip6Address nextHop4 = Ip6Address.valueOf("2000::1");
+ RouteEntry routeEntry4 = new RouteEntry(prefix4, nextHop4);
+
+ Ip6Prefix prefix5 = Ip6Prefix.valueOf("1000::/65");
+ Ip6Address nextHop5 = Ip6Address.valueOf("2000::1");
+ RouteEntry routeEntry5 = new RouteEntry(prefix5, nextHop5);
+
+ Ip6Prefix prefix6 = Ip6Prefix.valueOf("1000::/64");
+ Ip6Address nextHop6 = Ip6Address.valueOf("2000::2");
+ RouteEntry routeEntry6 = new RouteEntry(prefix6, nextHop6);
+
+ assertThat(routeEntry4, Matchers.is(not(routeEntry5)));
+ assertThat(routeEntry4, Matchers.is(not(routeEntry6)));
}
/**
@@ -155,5 +244,12 @@ public class RouteEntryTest {
assertThat(routeEntry.toString(),
is("RouteEntry{prefix=1.2.3.0/24, nextHop=5.6.7.8}"));
+
+ Ip6Prefix prefix6 = Ip6Prefix.valueOf("1000::/64");
+ Ip6Address nextHop6 = Ip6Address.valueOf("2000::1");
+ RouteEntry routeEntry6 = new RouteEntry(prefix6, nextHop6);
+
+ assertThat(routeEntry6.toString(),
+ is("RouteEntry{prefix=1000::/64, nextHop=2000::1}"));
}
}
diff --git a/framework/src/onos/apps/routing/src/main/java/org/onosproject/routing/config/impl/Configuration.java b/framework/src/onos/apps/routing/src/main/java/org/onosproject/routing/config/impl/Configuration.java
index 45206903..c58bc1b9 100644
--- a/framework/src/onos/apps/routing/src/main/java/org/onosproject/routing/config/impl/Configuration.java
+++ b/framework/src/onos/apps/routing/src/main/java/org/onosproject/routing/config/impl/Configuration.java
@@ -32,8 +32,8 @@ import java.util.List;
public class Configuration {
// We call the BGP routers in our SDN network the BGP speakers, and call
// the BGP routers outside our SDN network the BGP peers.
- private List<BgpSpeaker> bgpSpeakers;
- private List<BgpPeer> peers;
+ private List<BgpSpeaker> bgpSpeakers = Collections.emptyList();
+ private List<BgpPeer> peers = Collections.emptyList();
private MacAddress virtualGatewayMacAddress;
// All IP prefixes from the configuration are local
diff --git a/framework/src/onos/apps/routing/src/main/java/org/onosproject/routing/config/impl/RoutingConfigurationImpl.java b/framework/src/onos/apps/routing/src/main/java/org/onosproject/routing/config/impl/RoutingConfigurationImpl.java
index 0a6f9d4c..19c3f70b 100644
--- a/framework/src/onos/apps/routing/src/main/java/org/onosproject/routing/config/impl/RoutingConfigurationImpl.java
+++ b/framework/src/onos/apps/routing/src/main/java/org/onosproject/routing/config/impl/RoutingConfigurationImpl.java
@@ -195,13 +195,16 @@ public class RoutingConfigurationImpl implements RoutingConfigurationService {
}
BgpConfig bgpConfig = configService.getConfig(routerAppId, BgpConfig.class);
-
- return bgpConfig.bgpSpeakers().stream()
- .flatMap(speaker -> speaker.peers().stream())
- .map(peer -> interfaceService.getMatchingInterface(peer))
- .filter(intf -> intf != null)
- .map(intf -> intf.connectPoint())
- .collect(Collectors.toSet());
+ if (bgpConfig == null) {
+ return Collections.emptySet();
+ } else {
+ return bgpConfig.bgpSpeakers().stream()
+ .flatMap(speaker -> speaker.peers().stream())
+ .map(peer -> interfaceService.getMatchingInterface(peer))
+ .filter(intf -> intf != null)
+ .map(intf -> intf.connectPoint())
+ .collect(Collectors.toSet());
+ }
}
@Override
diff --git a/framework/src/onos/apps/routing/src/main/java/org/onosproject/routing/impl/Router.java b/framework/src/onos/apps/routing/src/main/java/org/onosproject/routing/impl/Router.java
index 6700d530..75d789ab 100644
--- a/framework/src/onos/apps/routing/src/main/java/org/onosproject/routing/impl/Router.java
+++ b/framework/src/onos/apps/routing/src/main/java/org/onosproject/routing/impl/Router.java
@@ -35,9 +35,7 @@ import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onosproject.core.CoreService;
-import org.onosproject.incubator.net.intf.Interface;
import org.onosproject.incubator.net.intf.InterfaceService;
-import org.onosproject.net.ConnectPoint;
import org.onosproject.net.Host;
import org.onosproject.net.host.HostEvent;
import org.onosproject.net.host.HostListener;
@@ -46,7 +44,6 @@ import org.onosproject.routing.BgpService;
import org.onosproject.routing.FibEntry;
import org.onosproject.routing.FibListener;
import org.onosproject.routing.FibUpdate;
-import org.onosproject.routing.IntentRequestListener;
import org.onosproject.routing.RouteEntry;
import org.onosproject.routing.RouteListener;
import org.onosproject.routing.RouteUpdate;
@@ -61,7 +58,6 @@ 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.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
@@ -100,7 +96,6 @@ public class Router implements RoutingService {
private final Map<IpAddress, MacAddress> ip2Mac = new ConcurrentHashMap<>();
private FibListener fibComponent;
- private IntentRequestListener intentRequestListener;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CoreService coreService;
@@ -145,12 +140,6 @@ public class Router implements RoutingService {
@Override
public void addFibListener(FibListener fibListener) {
this.fibComponent = checkNotNull(fibListener);
-
- }
-
- @Override
- public void addIntentRequestListener(IntentRequestListener intentRequestListener) {
- this.intentRequestListener = checkNotNull(intentRequestListener);
}
@Override
@@ -287,12 +276,10 @@ public class Router implements RoutingService {
void addRibRoute(RouteEntry routeEntry) {
if (routeEntry.isIp4()) {
// IPv4
- ribTable4.put(createBinaryString(routeEntry.prefix()),
- routeEntry);
+ ribTable4.put(createBinaryString(routeEntry.prefix()), routeEntry);
} else {
// IPv6
- ribTable6.put(createBinaryString(routeEntry.prefix()),
- routeEntry);
+ ribTable6.put(createBinaryString(routeEntry.prefix()), routeEntry);
}
}
@@ -553,17 +540,6 @@ public class Router implements RoutingService {
}
@Override
- public LocationType getLocationType(IpAddress ipAddress) {
- if (routingConfigurationService.isIpAddressLocal(ipAddress)) {
- return LocationType.LOCAL;
- } else if (getLongestMatchableRouteEntry(ipAddress) != null) {
- return LocationType.INTERNET;
- } else {
- return LocationType.NO_ROUTE;
- }
- }
-
- @Override
public RouteEntry getLongestMatchableRouteEntry(IpAddress ipAddress) {
RouteEntry routeEntry = null;
Iterable<RouteEntry> routeEntries;
@@ -587,142 +563,4 @@ public class Router implements RoutingService {
return routeEntry;
}
- @Override
- public ConnectPoint getEgressConnectPoint(IpAddress dstIpAddress) {
- LocationType type = getLocationType(dstIpAddress);
- if (type == LocationType.LOCAL) {
- Set<Host> hosts = hostService.getHostsByIp(dstIpAddress);
- if (!hosts.isEmpty()) {
- return hosts.iterator().next().location();
- } else {
- hostService.startMonitoringIp(dstIpAddress);
- return null;
- }
- } else if (type == LocationType.INTERNET) {
- IpAddress nextHopIpAddress = null;
- RouteEntry routeEntry = getLongestMatchableRouteEntry(dstIpAddress);
- if (routeEntry != null) {
- nextHopIpAddress = routeEntry.nextHop();
- Interface it = interfaceService.getMatchingInterface(nextHopIpAddress);
- if (it != null) {
- return it.connectPoint();
- } else {
- return null;
- }
- } else {
- return null;
- }
- } else {
- return null;
- }
- }
-
- @Override
- public void packetReactiveProcessor(IpAddress dstIpAddress,
- IpAddress srcIpAddress,
- ConnectPoint srcConnectPoint,
- MacAddress srcMacAddress) {
- checkNotNull(dstIpAddress);
- checkNotNull(srcIpAddress);
- checkNotNull(srcConnectPoint);
- checkNotNull(srcMacAddress);
-
- //
- // Step1: Try to update the existing intent first if it exists.
- //
- IpPrefix ipPrefix = null;
- if (routingConfigurationService.isIpAddressLocal(dstIpAddress)) {
- if (dstIpAddress.isIp4()) {
- ipPrefix = IpPrefix.valueOf(dstIpAddress,
- Ip4Address.BIT_LENGTH);
- } else {
- ipPrefix = IpPrefix.valueOf(dstIpAddress,
- Ip6Address.BIT_LENGTH);
- }
- } else {
- // Get IP prefix from BGP route table
- RouteEntry routeEntry = getLongestMatchableRouteEntry(dstIpAddress);
- if (routeEntry != null) {
- ipPrefix = routeEntry.prefix();
- }
- }
- if (ipPrefix != null
- && intentRequestListener.mp2pIntentExists(ipPrefix)) {
- intentRequestListener.updateExistingMp2pIntent(ipPrefix,
- srcConnectPoint);
- return;
- }
-
- //
- // Step2: There is no existing intent for the destination IP address.
- // Check whether it is necessary to create a new one. If necessary then
- // create a new one.
- //
- TrafficType trafficType =
- trafficTypeClassifier(srcConnectPoint, dstIpAddress);
-
- switch (trafficType) {
- case HOST_TO_INTERNET:
- // If the destination IP address is outside the local SDN network.
- // The Step 1 has already handled it. We do not need to do anything here.
- break;
- case INTERNET_TO_HOST:
- intentRequestListener.setUpConnectivityInternetToHost(dstIpAddress);
- break;
- case HOST_TO_HOST:
- intentRequestListener.setUpConnectivityHostToHost(dstIpAddress,
- srcIpAddress, srcMacAddress, srcConnectPoint);
- break;
- case INTERNET_TO_INTERNET:
- log.trace("This is transit traffic, "
- + "the intent should be preinstalled already");
- break;
- case DROP:
- // TODO here should setUpDropPaccketIntent(...);
- // We need a new type of intent here.
- break;
- case UNKNOWN:
- log.trace("This is unknown traffic, so we do nothing");
- break;
- default:
- break;
- }
- }
-
- /**
- * Classifies the traffic and return the traffic type.
- *
- * @param srcConnectPoint the connect point where the packet comes from
- * @param dstIp the destination IP address in packet
- * @return the traffic type which this packet belongs to
- */
- private TrafficType trafficTypeClassifier(ConnectPoint srcConnectPoint,
- IpAddress dstIp) {
- LocationType dstIpLocationType = getLocationType(dstIp);
- Optional<Interface> srcInterface =
- interfaceService.getInterfacesByPort(srcConnectPoint).stream().findFirst();
-
- switch (dstIpLocationType) {
- case INTERNET:
- if (!srcInterface.isPresent()) {
- return TrafficType.HOST_TO_INTERNET;
- } else {
- return TrafficType.INTERNET_TO_INTERNET;
- }
- case LOCAL:
- if (!srcInterface.isPresent()) {
- return TrafficType.HOST_TO_HOST;
- } else {
- // TODO Currently we only consider local public prefixes.
- // In the future, we will consider the local private prefixes.
- // If dstIpLocationType is a local private, we should return
- // TrafficType.DROP.
- return TrafficType.INTERNET_TO_HOST;
- }
- case NO_ROUTE:
- return TrafficType.DROP;
- default:
- return TrafficType.UNKNOWN;
- }
- }
}
diff --git a/framework/src/onos/apps/routing/src/main/java/org/onosproject/routing/impl/StaticRouter.java b/framework/src/onos/apps/routing/src/main/java/org/onosproject/routing/impl/StaticRouter.java
index 29526fff..3c868202 100644
--- a/framework/src/onos/apps/routing/src/main/java/org/onosproject/routing/impl/StaticRouter.java
+++ b/framework/src/onos/apps/routing/src/main/java/org/onosproject/routing/impl/StaticRouter.java
@@ -18,10 +18,7 @@ package org.onosproject.routing.impl;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Service;
import org.onlab.packet.IpAddress;
-import org.onlab.packet.MacAddress;
-import org.onosproject.net.ConnectPoint;
import org.onosproject.routing.FibListener;
-import org.onosproject.routing.IntentRequestListener;
import org.onosproject.routing.RouteEntry;
import org.onosproject.routing.RoutingService;
import org.onosproject.routing.StaticRoutingService;
@@ -49,11 +46,6 @@ public class StaticRouter implements RoutingService, StaticRoutingService {
}
@Override
- public void addIntentRequestListener(IntentRequestListener intentRequestListener) {
-
- }
-
- @Override
public void stop() {
}
@@ -69,27 +61,11 @@ public class StaticRouter implements RoutingService, StaticRoutingService {
}
@Override
- public LocationType getLocationType(IpAddress ipAddress) {
- return null;
- }
-
- @Override
public RouteEntry getLongestMatchableRouteEntry(IpAddress ipAddress) {
return null;
}
@Override
- public ConnectPoint getEgressConnectPoint(IpAddress dstIpAddress) {
- return null;
- }
-
- @Override
- public void packetReactiveProcessor(IpAddress dstIpAddress, IpAddress srcIpAddress,
- ConnectPoint srcConnectPoint, MacAddress srcMacAddress) {
-
- }
-
- @Override
public FibListener getFibListener() {
return fibListener;
}
diff --git a/framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/impl/RouterTest.java b/framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/impl/RouterTest.java
index 45bc309f..c73e18cb 100644
--- a/framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/impl/RouterTest.java
+++ b/framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/impl/RouterTest.java
@@ -22,6 +22,8 @@ import org.junit.Before;
import org.junit.Test;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
+import org.onlab.packet.Ip6Address;
+import org.onlab.packet.Ip6Prefix;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
@@ -81,6 +83,13 @@ public class RouterTest {
DeviceId.deviceId("of:0000000000000004"),
PortNumber.portNumber(1));
+ private static final ConnectPoint SW5_ETH1 = new ConnectPoint(
+ DeviceId.deviceId("of:0000000000000005"),
+ PortNumber.portNumber(1));
+
+ private static final ConnectPoint SW6_ETH1 = new ConnectPoint(
+ DeviceId.deviceId("of:0000000000000006"),
+ PortNumber.portNumber(1));
private Router router;
@Before
@@ -132,7 +141,6 @@ public class RouterTest {
hostService.startMonitoringIp(host1Address);
expectLastCall().anyTimes();
-
IpAddress host2Address = IpAddress.valueOf("192.168.20.1");
Host host2 = new DefaultHost(ProviderId.NONE, HostId.NONE,
MacAddress.valueOf("00:00:00:00:00:02"), VlanId.NONE,
@@ -148,7 +156,7 @@ public class RouterTest {
IpAddress host3Address = IpAddress.valueOf("192.168.40.1");
Host host3 = new DefaultHost(ProviderId.NONE, HostId.NONE,
MacAddress.valueOf("00:00:00:00:00:03"), VlanId.vlanId((short) 1),
- new HostLocation(SW4_ETH1, 1),
+ new HostLocation(SW3_ETH1, 1),
Sets.newHashSet(host3Address));
expect(hostService.getHostsByIp(host3Address))
@@ -156,6 +164,41 @@ public class RouterTest {
hostService.startMonitoringIp(host3Address);
expectLastCall().anyTimes();
+ IpAddress host4Address = IpAddress.valueOf("1000::1");
+ Host host4 = new DefaultHost(ProviderId.NONE, HostId.NONE,
+ MacAddress.valueOf("00:00:00:00:00:04"), VlanId.NONE,
+ new HostLocation(SW4_ETH1, 1),
+ Sets.newHashSet(host4Address));
+
+ expect(hostService.getHostsByIp(host4Address))
+ .andReturn(Sets.newHashSet(host4)).anyTimes();
+ hostService.startMonitoringIp(host4Address);
+ expectLastCall().anyTimes();
+
+ IpAddress host5Address = IpAddress.valueOf("2000::1");
+ Host host5 = new DefaultHost(ProviderId.NONE, HostId.NONE,
+ MacAddress.valueOf("00:00:00:00:00:05"), VlanId.NONE,
+ new HostLocation(SW5_ETH1, 1),
+ Sets.newHashSet(host5Address));
+
+ expect(hostService.getHostsByIp(host5Address))
+ .andReturn(Sets.newHashSet(host5)).anyTimes();
+ hostService.startMonitoringIp(host5Address);
+ expectLastCall().anyTimes();
+
+ // Next hop on a VLAN
+ IpAddress host6Address = IpAddress.valueOf("3000::1");
+ Host host6 = new DefaultHost(ProviderId.NONE, HostId.NONE,
+ MacAddress.valueOf("00:00:00:00:00:06"), VlanId.vlanId((short) 1),
+ new HostLocation(SW6_ETH1, 1),
+ Sets.newHashSet(host6Address));
+
+ expect(hostService.getHostsByIp(host6Address))
+ .andReturn(Sets.newHashSet(host6)).anyTimes();
+ hostService.startMonitoringIp(host6Address);
+ expectLastCall().anyTimes();
+
+
// Called during shutdown
hostService.removeListener(anyObject(HostListener.class));
@@ -163,10 +206,10 @@ public class RouterTest {
}
/**
- * Tests adding a route entry.
+ * Tests adding a IPv4 route entry.
*/
@Test
- public void testRouteAdd() {
+ public void testIpv4RouteAdd() {
// Construct a route entry
IpPrefix prefix = Ip4Prefix.valueOf("1.1.1.0/24");
IpAddress nextHopIp = Ip4Address.valueOf("192.168.10.1");
@@ -175,7 +218,34 @@ public class RouterTest {
// Expected FIB entry
FibEntry fibEntry = new FibEntry(prefix, nextHopIp,
- MacAddress.valueOf("00:00:00:00:00:01"));
+ MacAddress.valueOf("00:00:00:00:00:01"));
+
+ fibListener.update(Collections.singletonList(new FibUpdate(
+ FibUpdate.Type.UPDATE, fibEntry)), Collections.emptyList());
+
+ replay(fibListener);
+
+ router.processRouteUpdates(Collections.singletonList(
+ new RouteUpdate(RouteUpdate.Type.UPDATE, routeEntry)));
+
+ verify(fibListener);
+ }
+
+
+ /**
+ * Tests adding a IPv6 route entry.
+ */
+ @Test
+ public void testIpv6RouteAdd() {
+ // Construct a route entry
+ IpPrefix prefix = Ip6Prefix.valueOf("4000::/64");
+ IpAddress nextHopIp = Ip6Address.valueOf("1000::1");
+
+ RouteEntry routeEntry = new RouteEntry(prefix, nextHopIp);
+
+ // Expected FIB entry
+ FibEntry fibEntry = new FibEntry(prefix, nextHopIp,
+ MacAddress.valueOf("00:00:00:00:00:04"));
fibListener.update(Collections.singletonList(new FibUpdate(
FibUpdate.Type.UPDATE, fibEntry)), Collections.emptyList());
@@ -188,13 +258,14 @@ public class RouterTest {
verify(fibListener);
}
+
/**
- * Tests updating a route entry.
+ * Tests updating a IPv4 route entry.
*/
@Test
public void testRouteUpdate() {
// Firstly add a route
- testRouteAdd();
+ testIpv4RouteAdd();
// Route entry with updated next hop for the original prefix
RouteEntry routeEntryUpdate = new RouteEntry(
@@ -230,12 +301,53 @@ public class RouterTest {
}
/**
- * Tests deleting a route entry.
+ * Tests updating a IPv6 route entry.
*/
@Test
- public void testRouteDelete() {
+ public void testIpv6RouteUpdate() {
// Firstly add a route
- testRouteAdd();
+ testIpv6RouteAdd();
+
+ // Route entry with updated next hop for the original prefix
+ RouteEntry routeEntryUpdate = new RouteEntry(
+ Ip6Prefix.valueOf("4000::/64"),
+ Ip6Address.valueOf("2000::1"));
+
+ // The old FIB entry will be withdrawn
+ FibEntry withdrawFibEntry = new FibEntry(
+ Ip6Prefix.valueOf("4000::/64"), null, null);
+
+ // A new FIB entry will be added
+ FibEntry updateFibEntry = new FibEntry(
+ Ip6Prefix.valueOf("4000::/64"),
+ Ip6Address.valueOf("2000::1"),
+ MacAddress.valueOf("00:00:00:00:00:05"));
+
+ reset(fibListener);
+ fibListener.update(Collections.singletonList(new FibUpdate(
+ FibUpdate.Type.UPDATE, updateFibEntry)),
+ Collections.singletonList(new FibUpdate(
+ FibUpdate.Type.DELETE, withdrawFibEntry)));
+ replay(fibListener);
+
+ reset(routingConfigurationService);
+ expect(routingConfigurationService.isIpPrefixLocal(
+ anyObject(IpPrefix.class))).andReturn(false);
+ replay(routingConfigurationService);
+
+ router.processRouteUpdates(Collections.singletonList(new RouteUpdate(
+ RouteUpdate.Type.UPDATE, routeEntryUpdate)));
+
+ verify(fibListener);
+ }
+
+ /**
+ * Tests deleting a IPv4 route entry.
+ */
+ @Test
+ public void testIpv4RouteDelete() {
+ // Firstly add a route
+ testIpv4RouteAdd();
RouteEntry deleteRouteEntry = new RouteEntry(
Ip4Prefix.valueOf("1.1.1.0/24"),
@@ -257,10 +369,37 @@ public class RouterTest {
}
/**
- * Tests adding a route whose next hop is the local BGP speaker.
+ * Tests deleting a IPv6 route entry.
*/
@Test
- public void testLocalRouteAdd() {
+ public void testIpv6RouteDelete() {
+ // Firstly add a route
+ testIpv6RouteAdd();
+
+ RouteEntry deleteRouteEntry = new RouteEntry(
+ Ip6Prefix.valueOf("4000::/64"),
+ Ip6Address.valueOf("1000::1"));
+
+ FibEntry deleteFibEntry = new FibEntry(
+ Ip6Prefix.valueOf("4000::/64"), null, null);
+
+ reset(fibListener);
+ fibListener.update(Collections.emptyList(), Collections.singletonList(
+ new FibUpdate(FibUpdate.Type.DELETE, deleteFibEntry)));
+
+ replay(fibListener);
+
+ router.processRouteUpdates(Collections.singletonList(
+ new RouteUpdate(RouteUpdate.Type.DELETE, deleteRouteEntry)));
+
+ verify(fibListener);
+ }
+
+ /**
+ * Tests adding a IPv4 route whose next hop is the local BGP speaker.
+ */
+ @Test
+ public void testIpv4LocalRouteAdd() {
// Construct a route entry, the next hop is the local BGP speaker
RouteEntry routeEntry = new RouteEntry(
Ip4Prefix.valueOf("1.1.1.0/24"),
@@ -284,4 +423,33 @@ public class RouterTest {
assertTrue(router.getRoutes4().contains(routeEntry));
verify(fibListener);
}
+
+ /**
+ * Tests adding a IPv6 route whose next hop is the local BGP speaker.
+ */
+ @Test
+ public void testIpv6LocalRouteAdd() {
+ // Construct a route entry, the next hop is the local BGP speaker
+ RouteEntry routeEntry = new RouteEntry(
+ Ip6Prefix.valueOf("4000::/64"),
+ Ip6Address.valueOf("::"));
+
+ // No methods on the FIB listener should be called
+ replay(fibListener);
+
+ reset(routingConfigurationService);
+ expect(routingConfigurationService.isIpPrefixLocal(
+ anyObject(IpPrefix.class))).andReturn(true);
+ replay(routingConfigurationService);
+
+ // Call the processRouteUpdates() method in Router class
+ RouteUpdate routeUpdate = new RouteUpdate(RouteUpdate.Type.UPDATE,
+ routeEntry);
+ router.processRouteUpdates(Collections.singletonList(routeUpdate));
+
+ // Verify
+ assertEquals(1, router.getRoutes6().size());
+ assertTrue(router.getRoutes6().contains(routeEntry));
+ verify(fibListener);
+ }
}
diff --git a/framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/IntentSynchronizer.java b/framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/IntentSynchronizer.java
index d8d8f45d..eaabed33 100644
--- a/framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/IntentSynchronizer.java
+++ b/framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/IntentSynchronizer.java
@@ -15,118 +15,79 @@
*/
package org.onosproject.sdnip;
-import com.google.common.collect.ImmutableList;
-import com.google.common.util.concurrent.ThreadFactoryBuilder;
-import org.onlab.packet.Ethernet;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.IpPrefix;
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.VlanId;
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.Host;
-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.flow.criteria.Criterion;
-import org.onosproject.net.flow.criteria.IPCriterion;
-import org.onosproject.net.host.HostService;
-import org.onosproject.net.intent.Constraint;
import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentService;
import org.onosproject.net.intent.IntentState;
import org.onosproject.net.intent.Key;
-import org.onosproject.net.intent.MultiPointToSinglePointIntent;
-import org.onosproject.net.intent.PointToPointIntent;
-import org.onosproject.net.intent.constraint.PartialFailureConstraint;
-import org.onosproject.routing.FibListener;
-import org.onosproject.routing.FibUpdate;
-import org.onosproject.routing.IntentRequestListener;
-import org.onosproject.routing.config.RoutingConfigurationService;
+import org.onosproject.routing.IntentSynchronizationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.Collection;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Semaphore;
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
+import static java.util.concurrent.Executors.newSingleThreadExecutor;
+import static org.onlab.util.Tools.groupedThreads;
/**
* Synchronizes intents between the in-memory intent store and the
* IntentService.
*/
-public class IntentSynchronizer implements FibListener, IntentRequestListener {
- private static final int PRIORITY_OFFSET = 100;
- private static final int PRIORITY_MULTIPLIER = 5;
- protected static final ImmutableList<Constraint> CONSTRAINTS
- = ImmutableList.of(new PartialFailureConstraint());
+public class IntentSynchronizer implements IntentSynchronizationService {
private static final Logger log =
LoggerFactory.getLogger(IntentSynchronizer.class);
private final ApplicationId appId;
private final IntentService intentService;
- private final HostService hostService;
- private final InterfaceService interfaceService;
- private final Map<IntentKey, PointToPointIntent> peerIntents;
- private final Map<IpPrefix, MultiPointToSinglePointIntent> routeIntents;
+
+ private final Map<Key, Intent> intents;
//
// State to deal with SDN-IP Leader election and pushing Intents
//
private final ExecutorService bgpIntentsSynchronizerExecutor;
- private final Semaphore intentsSynchronizerSemaphore = new Semaphore(0);
private volatile boolean isElectedLeader = false;
private volatile boolean isActivatedLeader = false;
- private final RoutingConfigurationService configService;
+ /**
+ * Class constructor.
+ *
+ * @param appId the Application ID
+ * @param intentService the intent service
+ */
+ IntentSynchronizer(ApplicationId appId, IntentService intentService) {
+ this(appId, intentService,
+ newSingleThreadExecutor(groupedThreads("onos/sdnip", "sync")));
+ }
/**
* Class constructor.
*
* @param appId the Application ID
* @param intentService the intent service
- * @param hostService the host service
- * @param configService the SDN-IP configuration service
- * @param interfaceService the interface service
+ * @param executorService executor service for synchronization thread
*/
IntentSynchronizer(ApplicationId appId, IntentService intentService,
- HostService hostService,
- RoutingConfigurationService configService,
- InterfaceService interfaceService) {
+ ExecutorService executorService) {
this.appId = appId;
this.intentService = intentService;
- this.hostService = hostService;
- this.interfaceService = interfaceService;
- peerIntents = new ConcurrentHashMap<>();
- routeIntents = new ConcurrentHashMap<>();
- this.configService = configService;
+ intents = new ConcurrentHashMap<>();
- bgpIntentsSynchronizerExecutor = Executors.newSingleThreadExecutor(
- new ThreadFactoryBuilder()
- .setNameFormat("sdnip-intents-synchronizer-%d").build());
+ bgpIntentsSynchronizerExecutor = executorService;
}
/**
* Starts the synchronizer.
*/
public void start() {
- bgpIntentsSynchronizerExecutor.execute(this::doIntentSynchronizationThread);
+
}
/**
@@ -187,794 +148,118 @@ public class IntentSynchronizer implements FibListener, IntentRequestListener {
}
}
- /**
- * Signals the synchronizer that the SDN-IP leadership has changed.
- *
- * @param isLeader true if this instance is now the leader, otherwise false
- */
- public void leaderChanged(boolean isLeader) {
- log.debug("SDN-IP Leader changed: {}", isLeader);
-
- if (!isLeader) {
- this.isElectedLeader = false;
- this.isActivatedLeader = false;
- return; // Nothing to do
- }
- this.isActivatedLeader = false;
- this.isElectedLeader = true;
-
- //
- // Tell the Intents Synchronizer thread to start the synchronization
- //
- intentsSynchronizerSemaphore.release();
- }
-
- /**
- * Gets the route intents.
- *
- * @return the route intents
- */
- public Collection<MultiPointToSinglePointIntent> getRouteIntents() {
- List<MultiPointToSinglePointIntent> result = new LinkedList<>();
-
- for (Map.Entry<IpPrefix, MultiPointToSinglePointIntent> entry :
- routeIntents.entrySet()) {
- result.add(entry.getValue());
- }
- return result;
- }
-
- /**
- * Thread for Intent Synchronization.
- */
- private void doIntentSynchronizationThread() {
- boolean interrupted = false;
- try {
- while (!interrupted) {
- try {
- intentsSynchronizerSemaphore.acquire();
- //
- // Drain all permits, because a single synchronization is
- // sufficient.
- //
- intentsSynchronizerSemaphore.drainPermits();
- } catch (InterruptedException e) {
- interrupted = true;
- break;
- }
- synchronizeIntents();
- }
- } finally {
- if (interrupted) {
- Thread.currentThread().interrupt();
- }
- }
- }
-
- /**
- * Submits a collection of point-to-point intents.
- *
- * @param intents the intents to submit
- */
- void submitPeerIntents(Collection<PointToPointIntent> intents) {
+ @Override
+ public void submit(Intent intent) {
synchronized (this) {
- // Store the intents in memory
- for (PointToPointIntent intent : intents) {
- peerIntents.put(new IntentKey(intent), intent);
- }
-
- // Push the intents
+ intents.put(intent.key(), intent);
if (isElectedLeader && isActivatedLeader) {
- log.debug("SDN-IP Submitting all Peer Intents...");
- for (Intent intent : intents) {
- log.trace("SDN-IP Submitting intents: {}", intent);
- intentService.submit(intent);
- }
+ log.trace("SDN-IP Submitting intent: {}", intent);
+ intentService.submit(intent);
}
}
}
- /**
- * Submits a MultiPointToSinglePointIntent for reactive routing.
- *
- * @param ipPrefix the IP prefix to match in a MultiPointToSinglePointIntent
- * @param intent the intent to submit
- */
- void submitReactiveIntent(IpPrefix ipPrefix, MultiPointToSinglePointIntent intent) {
+ @Override
+ public void withdraw(Intent intent) {
synchronized (this) {
- // Store the intent in memory
- routeIntents.put(ipPrefix, intent);
-
- // Push the intent
+ intents.remove(intent.key(), intent);
if (isElectedLeader && isActivatedLeader) {
- log.trace("SDN-IP submitting reactive routing intent: {}", intent);
- intentService.submit(intent);
+ log.trace("SDN-IP Withdrawing intent: {}", intent);
+ intentService.withdraw(intent);
}
}
}
/**
- * Generates a route intent for a prefix, the next hop IP address, and
- * the next hop MAC address.
- * <p/>
- * This method will find the egress interface for the intent.
- * Intent will match dst IP prefix and rewrite dst MAC address at all other
- * border switches, then forward packets according to dst MAC address.
+ * Signals the synchronizer that the SDN-IP leadership has changed.
*
- * @param prefix IP prefix of the route to add
- * @param nextHopIpAddress IP address of the next hop
- * @param nextHopMacAddress MAC address of the next hop
- * @return the generated intent, or null if no intent should be submitted
+ * @param isLeader true if this instance is now the leader, otherwise false
*/
- private MultiPointToSinglePointIntent generateRouteIntent(
- IpPrefix prefix,
- IpAddress nextHopIpAddress,
- MacAddress nextHopMacAddress) {
-
- // Find the attachment point (egress interface) of the next hop
- Interface egressInterface = interfaceService.getMatchingInterface(nextHopIpAddress);
- if (egressInterface == null) {
- log.warn("No outgoing interface found for {}",
- nextHopIpAddress);
- return null;
- }
-
- //
- // Generate the intent itself
- //
- Set<ConnectPoint> ingressPorts = new HashSet<>();
- ConnectPoint egressPort = egressInterface.connectPoint();
- log.debug("Generating intent for prefix {}, next hop mac {}",
- prefix, nextHopMacAddress);
-
- for (Interface intf : interfaceService.getInterfaces()) {
- // TODO this should be only peering interfaces
- if (!intf.connectPoint().equals(egressInterface.connectPoint())) {
- ConnectPoint srcPort = intf.connectPoint();
- ingressPorts.add(srcPort);
- }
- }
-
- // Match the destination IP prefix at the first hop
- TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
- if (prefix.isIp4()) {
- selector.matchEthType(Ethernet.TYPE_IPV4);
- selector.matchIPDst(prefix);
- } else {
- selector.matchEthType(Ethernet.TYPE_IPV6);
- selector.matchIPv6Dst(prefix);
- }
-
- // Rewrite the destination MAC address
- TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
- .setEthDst(nextHopMacAddress);
- if (!egressInterface.vlan().equals(VlanId.NONE)) {
- treatment.setVlanId(egressInterface.vlan());
- // If we set VLAN ID, we have to make sure a VLAN tag exists.
- // TODO support no VLAN -> VLAN routing
- selector.matchVlanId(VlanId.ANY);
- }
-
- int priority =
- prefix.prefixLength() * PRIORITY_MULTIPLIER + PRIORITY_OFFSET;
- Key key = Key.of(prefix.toString(), appId);
- return MultiPointToSinglePointIntent.builder()
- .appId(appId)
- .key(key)
- .selector(selector.build())
- .treatment(treatment.build())
- .ingressPoints(ingressPorts)
- .egressPoint(egressPort)
- .priority(priority)
- .constraints(CONSTRAINTS)
- .build();
- }
-
- @Override
- public void setUpConnectivityInternetToHost(IpAddress hostIpAddress) {
- checkNotNull(hostIpAddress);
- Set<ConnectPoint> ingressPoints =
- configService.getBgpPeerConnectPoints();
-
- TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
-
- if (hostIpAddress.isIp4()) {
- selector.matchEthType(Ethernet.TYPE_IPV4);
- } else {
- selector.matchEthType(Ethernet.TYPE_IPV6);
- }
+ public void leaderChanged(boolean isLeader) {
+ log.debug("SDN-IP Leader changed: {}", isLeader);
- // Match the destination IP prefix at the first hop
- IpPrefix ipPrefix = hostIpAddress.toIpPrefix();
- selector.matchIPDst(ipPrefix);
-
- // Rewrite the destination MAC address
- MacAddress hostMac = null;
- ConnectPoint egressPoint = null;
- for (Host host : hostService.getHostsByIp(hostIpAddress)) {
- if (host.mac() != null) {
- hostMac = host.mac();
- egressPoint = host.location();
- break;
- }
- }
- if (hostMac == null) {
- hostService.startMonitoringIp(hostIpAddress);
- return;
+ if (!isLeader) {
+ this.isElectedLeader = false;
+ this.isActivatedLeader = false;
+ return; // Nothing to do
}
+ this.isActivatedLeader = false;
+ this.isElectedLeader = true;
- TrafficTreatment.Builder treatment =
- DefaultTrafficTreatment.builder().setEthDst(hostMac);
- Key key = Key.of(ipPrefix.toString(), appId);
- int priority = ipPrefix.prefixLength() * PRIORITY_MULTIPLIER
- + PRIORITY_OFFSET;
- MultiPointToSinglePointIntent intent =
- MultiPointToSinglePointIntent.builder()
- .appId(appId)
- .key(key)
- .selector(selector.build())
- .treatment(treatment.build())
- .ingressPoints(ingressPoints)
- .egressPoint(egressPoint)
- .priority(priority)
- .constraints(CONSTRAINTS)
- .build();
-
- log.trace("Generates ConnectivityInternetToHost intent {}", intent);
- submitReactiveIntent(ipPrefix, intent);
- }
-
-
- @Override
- public void update(Collection<FibUpdate> updates, Collection<FibUpdate> withdraws) {
- //
- // NOTE: Semantically, we MUST withdraw existing intents before
- // submitting new intents.
- //
- synchronized (this) {
- MultiPointToSinglePointIntent intent;
-
- log.debug("SDN-IP submitting intents = {} withdrawing = {}",
- updates.size(), withdraws.size());
-
- //
- // Prepare the Intent batch operations for the intents to withdraw
- //
- for (FibUpdate withdraw : withdraws) {
- checkArgument(withdraw.type() == FibUpdate.Type.DELETE,
- "FibUpdate with wrong type in withdraws list");
-
- IpPrefix prefix = withdraw.entry().prefix();
- intent = routeIntents.remove(prefix);
- if (intent == null) {
- log.trace("SDN-IP No intent in routeIntents to delete " +
- "for prefix: {}", prefix);
- continue;
- }
- if (isElectedLeader && isActivatedLeader) {
- log.trace("SDN-IP Withdrawing intent: {}", intent);
- intentService.withdraw(intent);
- }
- }
-
- //
- // Prepare the Intent batch operations for the intents to submit
- //
- for (FibUpdate update : updates) {
- checkArgument(update.type() == FibUpdate.Type.UPDATE,
- "FibUpdate with wrong type in updates list");
-
- IpPrefix prefix = update.entry().prefix();
- intent = generateRouteIntent(prefix, update.entry().nextHopIp(),
- update.entry().nextHopMac());
-
- if (intent == null) {
- // This preserves the old semantics - if an intent can't be
- // generated, we don't do anything with that prefix. But
- // perhaps we should withdraw the old intent anyway?
- continue;
- }
-
- MultiPointToSinglePointIntent oldIntent =
- routeIntents.put(prefix, intent);
- if (isElectedLeader && isActivatedLeader) {
- if (oldIntent != null) {
- log.trace("SDN-IP Withdrawing old intent: {}",
- oldIntent);
- intentService.withdraw(oldIntent);
- }
- log.trace("SDN-IP Submitting intent: {}", intent);
- intentService.submit(intent);
- }
- }
- }
+ // Run the synchronization method off-thread
+ bgpIntentsSynchronizerExecutor.execute(this::synchronizeIntents);
}
- /**
- * Synchronize the in-memory Intents with the Intents in the Intent
- * framework.
- */
- void synchronizeIntents() {
- synchronized (this) {
-
- Map<IntentKey, Intent> localIntents = new HashMap<>();
- Map<IntentKey, Intent> fetchedIntents = new HashMap<>();
- Collection<Intent> storeInMemoryIntents = new LinkedList<>();
- Collection<Intent> addIntents = new LinkedList<>();
- Collection<Intent> deleteIntents = new LinkedList<>();
-
- if (!isElectedLeader) {
- return; // Nothing to do: not the leader anymore
- }
- log.debug("SDN-IP synchronizing all intents...");
-
- // Prepare the local intents
- for (Intent intent : routeIntents.values()) {
- localIntents.put(new IntentKey(intent), intent);
- }
- for (Intent intent : peerIntents.values()) {
- localIntents.put(new IntentKey(intent), intent);
+ private void synchronizeIntents() {
+ Map<Key, Intent> serviceIntents = new HashMap<>();
+ intentService.getIntents().forEach(i -> {
+ if (i.appId().equals(appId)) {
+ serviceIntents.put(i.key(), i);
}
+ });
- // Fetch all intents for this application
- for (Intent intent : intentService.getIntents()) {
- if (!intent.appId().equals(appId)) {
- continue;
- }
- fetchedIntents.put(new IntentKey(intent), intent);
- }
- if (log.isDebugEnabled()) {
- for (Intent intent: fetchedIntents.values()) {
- log.trace("SDN-IP Intent Synchronizer: fetched intent: {}",
- intent);
- }
- }
-
- computeIntentsDelta(localIntents, fetchedIntents,
- storeInMemoryIntents, addIntents,
- deleteIntents);
+ List<Intent> intentsToAdd = new LinkedList<>();
+ List<Intent> intentsToRemove = new LinkedList<>();
- //
- // Perform the actions:
- // 1. Store in memory fetched intents that are same. Can be done
- // even if we are not the leader anymore
- // 2. Delete intents: check if the leader before the operation
- // 3. Add intents: check if the leader before the operation
- //
- for (Intent intent : storeInMemoryIntents) {
- // Store the intent in memory based on its type
- if (intent instanceof MultiPointToSinglePointIntent) {
- MultiPointToSinglePointIntent mp2pIntent =
- (MultiPointToSinglePointIntent) intent;
- // Find the IP prefix
- Criterion c =
- mp2pIntent.selector().getCriterion(Criterion.Type.IPV4_DST);
- if (c == null) {
- // Try IPv6
- c =
- mp2pIntent.selector().getCriterion(Criterion.Type.IPV6_DST);
- }
- if (c != null && c instanceof IPCriterion) {
- IPCriterion ipCriterion = (IPCriterion) c;
- IpPrefix ipPrefix = ipCriterion.ip();
- if (ipPrefix == null) {
- continue;
- }
- log.trace("SDN-IP Intent Synchronizer: updating " +
- "in-memory Route Intent for prefix {}",
- ipPrefix);
- routeIntents.put(ipPrefix, mp2pIntent);
- } else {
- log.warn("SDN-IP no IPV4_DST or IPV6_DST criterion found for Intent {}",
- mp2pIntent.id());
- }
- continue;
- }
- if (intent instanceof PointToPointIntent) {
- PointToPointIntent p2pIntent = (PointToPointIntent) intent;
- log.trace("SDN-IP Intent Synchronizer: updating " +
- "in-memory Peer Intent {}", p2pIntent);
- peerIntents.put(new IntentKey(intent), p2pIntent);
- continue;
- }
- }
-
- // Withdraw Intents
- for (Intent intent : deleteIntents) {
- intentService.withdraw(intent);
- log.trace("SDN-IP Intent Synchronizer: withdrawing intent: {}",
- intent);
- }
- if (!isElectedLeader) {
- log.trace("SDN-IP Intent Synchronizer: cannot withdraw intents: " +
- "not elected leader anymore");
- isActivatedLeader = false;
- return;
- }
-
- // Add Intents
- for (Intent intent : addIntents) {
- intentService.submit(intent);
- log.trace("SDN-IP Intent Synchronizer: submitting intent: {}",
- intent);
- }
- if (!isElectedLeader) {
- log.trace("SDN-IP Intent Synchronizer: cannot submit intents: " +
- "not elected leader anymore");
- isActivatedLeader = false;
- return;
- }
-
- if (isElectedLeader) {
- isActivatedLeader = true; // Allow push of Intents
+ for (Intent localIntent : intents.values()) {
+ Intent serviceIntent = serviceIntents.remove(localIntent.key());
+ if (serviceIntent == null) {
+ intentsToAdd.add(localIntent);
} else {
- isActivatedLeader = false;
- }
- log.debug("SDN-IP intent synchronization completed");
- }
- }
-
- /**
- * Computes the delta in two sets of Intents: local in-memory Intents,
- * and intents fetched from the Intent framework.
- *
- * @param localIntents the local in-memory Intents
- * @param fetchedIntents the Intents fetched from the Intent framework
- * @param storeInMemoryIntents the Intents that should be stored in memory.
- * Note: This Collection must be allocated by the caller, and it will
- * be populated by this method.
- * @param addIntents the Intents that should be added to the Intent
- * framework. Note: This Collection must be allocated by the caller, and
- * it will be populated by this method.
- * @param deleteIntents the Intents that should be deleted from the Intent
- * framework. Note: This Collection must be allocated by the caller, and
- * it will be populated by this method.
- */
- private void computeIntentsDelta(
- final Map<IntentKey, Intent> localIntents,
- final Map<IntentKey, Intent> fetchedIntents,
- Collection<Intent> storeInMemoryIntents,
- Collection<Intent> addIntents,
- Collection<Intent> deleteIntents) {
-
- //
- // Compute the deltas between the LOCAL in-memory Intents and the
- // FETCHED Intents:
- // - If an Intent is in both the LOCAL and FETCHED sets:
- // If the FETCHED Intent is WITHDRAWING or WITHDRAWN, then
- // the LOCAL Intent should be added/installed; otherwise the
- // FETCHED intent should be stored in the local memory
- // (i.e., override the LOCAL Intent) to preserve the original
- // Intent ID.
- // - if a LOCAL Intent is not in the FETCHED set, then the LOCAL
- // Intent should be added/installed.
- // - If a FETCHED Intent is not in the LOCAL set, then the FETCHED
- // Intent should be deleted/withdrawn.
- //
- for (Map.Entry<IntentKey, Intent> entry : localIntents.entrySet()) {
- IntentKey intentKey = entry.getKey();
- Intent localIntent = entry.getValue();
- Intent fetchedIntent = fetchedIntents.get(intentKey);
-
- if (fetchedIntent == null) {
- //
- // No FETCHED Intent found: push the LOCAL Intent.
- //
- addIntents.add(localIntent);
- continue;
- }
-
- IntentState state =
- intentService.getIntentState(fetchedIntent.key());
- if (state == null ||
- state == IntentState.WITHDRAWING ||
- state == IntentState.WITHDRAWN) {
- // The intent has been withdrawn but according to our route
- // table it should be installed. We'll reinstall it.
- addIntents.add(localIntent);
- continue;
+ IntentState state = intentService.getIntentState(serviceIntent.key());
+ if (!IntentUtils.equals(serviceIntent, localIntent) || state == null ||
+ state == IntentState.WITHDRAW_REQ ||
+ state == IntentState.WITHDRAWING ||
+ state == IntentState.WITHDRAWN) {
+ intentsToAdd.add(localIntent);
+ }
}
- storeInMemoryIntents.add(fetchedIntent);
}
- for (Map.Entry<IntentKey, Intent> entry : fetchedIntents.entrySet()) {
- IntentKey intentKey = entry.getKey();
- Intent fetchedIntent = entry.getValue();
- Intent localIntent = localIntents.get(intentKey);
-
- if (localIntent != null) {
- continue;
+ for (Intent serviceIntent : serviceIntents.values()) {
+ IntentState state = intentService.getIntentState(serviceIntent.key());
+ if (state != null && state != IntentState.WITHDRAW_REQ
+ && state != IntentState.WITHDRAWING
+ && state != IntentState.WITHDRAWN) {
+ intentsToRemove.add(serviceIntent);
}
-
- IntentState state =
- intentService.getIntentState(fetchedIntent.key());
- if (state == null ||
- state == IntentState.WITHDRAWING ||
- state == IntentState.WITHDRAWN) {
- // Nothing to do. The intent has been already withdrawn.
- continue;
- }
- //
- // No LOCAL Intent found: delete/withdraw the FETCHED Intent.
- //
- deleteIntents.add(fetchedIntent);
- }
- }
-
- /**
- * Helper class that can be used to compute the key for an Intent by
- * by excluding the Intent ID.
- */
- static final class IntentKey {
- private final Intent intent;
-
- /**
- * Constructor.
- *
- * @param intent the intent to use
- */
- IntentKey(Intent intent) {
- checkArgument((intent instanceof MultiPointToSinglePointIntent) ||
- (intent instanceof PointToPointIntent),
- "Intent type not recognized", intent);
- this.intent = intent;
}
- /**
- * Compares two Multi-Point to Single-Point Intents whether they
- * represent same logical intention.
- *
- * @param intent1 the first Intent to compare
- * @param intent2 the second Intent to compare
- * @return true if both Intents represent same logical intention,
- * otherwise false
- */
- static boolean equalIntents(MultiPointToSinglePointIntent intent1,
- MultiPointToSinglePointIntent intent2) {
- return Objects.equals(intent1.appId(), intent2.appId()) &&
- Objects.equals(intent1.selector(), intent2.selector()) &&
- Objects.equals(intent1.treatment(), intent2.treatment()) &&
- Objects.equals(intent1.ingressPoints(), intent2.ingressPoints()) &&
- Objects.equals(intent1.egressPoint(), intent2.egressPoint());
- }
+ log.debug("SDN-IP Intent Synchronizer: submitting {}, withdrawing {}",
+ intentsToAdd.size(), intentsToRemove.size());
- /**
- * Compares two Point-to-Point Intents whether they represent
- * same logical intention.
- *
- * @param intent1 the first Intent to compare
- * @param intent2 the second Intent to compare
- * @return true if both Intents represent same logical intention,
- * otherwise false
- */
- static boolean equalIntents(PointToPointIntent intent1,
- PointToPointIntent intent2) {
- return Objects.equals(intent1.appId(), intent2.appId()) &&
- Objects.equals(intent1.selector(), intent2.selector()) &&
- Objects.equals(intent1.treatment(), intent2.treatment()) &&
- Objects.equals(intent1.ingressPoint(), intent2.ingressPoint()) &&
- Objects.equals(intent1.egressPoint(), intent2.egressPoint());
+ // Withdraw Intents
+ for (Intent intent : intentsToRemove) {
+ intentService.withdraw(intent);
+ log.trace("SDN-IP Intent Synchronizer: withdrawing intent: {}",
+ intent);
}
-
- @Override
- public int hashCode() {
- if (intent instanceof PointToPointIntent) {
- PointToPointIntent p2pIntent = (PointToPointIntent) intent;
- return Objects.hash(p2pIntent.appId(),
- p2pIntent.resources(),
- p2pIntent.selector(),
- p2pIntent.treatment(),
- p2pIntent.constraints(),
- p2pIntent.ingressPoint(),
- p2pIntent.egressPoint());
- }
- if (intent instanceof MultiPointToSinglePointIntent) {
- MultiPointToSinglePointIntent m2pIntent =
- (MultiPointToSinglePointIntent) intent;
- return Objects.hash(m2pIntent.appId(),
- m2pIntent.resources(),
- m2pIntent.selector(),
- m2pIntent.treatment(),
- m2pIntent.constraints(),
- m2pIntent.ingressPoints(),
- m2pIntent.egressPoint());
- }
- checkArgument(false, "Intent type not recognized", intent);
- return 0;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if ((obj == null) || (!(obj instanceof IntentKey))) {
- return false;
- }
- IntentKey other = (IntentKey) obj;
-
- if (this.intent instanceof PointToPointIntent) {
- if (!(other.intent instanceof PointToPointIntent)) {
- return false;
- }
- return equalIntents((PointToPointIntent) this.intent,
- (PointToPointIntent) other.intent);
- }
- if (this.intent instanceof MultiPointToSinglePointIntent) {
- if (!(other.intent instanceof MultiPointToSinglePointIntent)) {
- return false;
- }
- return equalIntents(
- (MultiPointToSinglePointIntent) this.intent,
- (MultiPointToSinglePointIntent) other.intent);
- }
- checkArgument(false, "Intent type not recognized", intent);
- return false;
+ if (!isElectedLeader) {
+ log.debug("SDN-IP Intent Synchronizer: cannot withdraw intents: " +
+ "not elected leader anymore");
+ isActivatedLeader = false;
+ return;
}
- }
- @Override
- public void setUpConnectivityHostToHost(IpAddress dstIpAddress,
- IpAddress srcIpAddress,
- MacAddress srcMacAddress,
- ConnectPoint srcConnectPoint) {
- checkNotNull(dstIpAddress);
- checkNotNull(srcIpAddress);
- checkNotNull(srcMacAddress);
- checkNotNull(srcConnectPoint);
-
- IpPrefix srcIpPrefix = srcIpAddress.toIpPrefix();
- IpPrefix dstIpPrefix = dstIpAddress.toIpPrefix();
- ConnectPoint dstConnectPoint = null;
- MacAddress dstMacAddress = null;
-
- for (Host host : hostService.getHostsByIp(dstIpAddress)) {
- if (host.mac() != null) {
- dstMacAddress = host.mac();
- dstConnectPoint = host.location();
- break;
- }
+ // Add Intents
+ for (Intent intent : intentsToAdd) {
+ intentService.submit(intent);
+ log.trace("SDN-IP Intent Synchronizer: submitting intent: {}",
+ intent);
}
- if (dstMacAddress == null) {
- hostService.startMonitoringIp(dstIpAddress);
+ if (!isElectedLeader) {
+ log.debug("SDN-IP Intent Synchronizer: cannot submit intents: " +
+ "not elected leader anymore");
+ isActivatedLeader = false;
return;
}
- //
- // Handle intent from source host to destination host
- //
- MultiPointToSinglePointIntent srcToDstIntent =
- hostToHostIntentGenerator(dstIpAddress, dstConnectPoint,
- dstMacAddress, srcConnectPoint);
- submitReactiveIntent(dstIpPrefix, srcToDstIntent);
-
- //
- // Handle intent from destination host to source host
- //
-
- // Since we proactively handle the intent from destination host to
- // source host, we should check whether there is an exiting intent
- // first.
- if (mp2pIntentExists(srcIpPrefix)) {
- updateExistingMp2pIntent(srcIpPrefix, dstConnectPoint);
- return;
+ if (isElectedLeader) {
+ isActivatedLeader = true; // Allow push of Intents
} else {
- // There is no existing intent, create a new one.
- MultiPointToSinglePointIntent dstToSrcIntent =
- hostToHostIntentGenerator(srcIpAddress, srcConnectPoint,
- srcMacAddress, dstConnectPoint);
- submitReactiveIntent(srcIpPrefix, dstToSrcIntent);
+ isActivatedLeader = false;
}
+ log.debug("SDN-IP intent synchronization completed");
}
- /**
- * Generates MultiPointToSinglePointIntent for both source host and
- * destination host located in local SDN network.
- *
- * @param dstIpAddress the destination IP address
- * @param dstConnectPoint the destination host connect point
- * @param dstMacAddress the MAC address of destination host
- * @param srcConnectPoint the connect point where packet-in from
- * @return the generated MultiPointToSinglePointIntent
- */
- private MultiPointToSinglePointIntent hostToHostIntentGenerator(
- IpAddress dstIpAddress,
- ConnectPoint dstConnectPoint,
- MacAddress dstMacAddress,
- ConnectPoint srcConnectPoint) {
- checkNotNull(dstIpAddress);
- checkNotNull(dstConnectPoint);
- checkNotNull(dstMacAddress);
- checkNotNull(srcConnectPoint);
-
- Set<ConnectPoint> ingressPoints = new HashSet<>();
- ingressPoints.add(srcConnectPoint);
- IpPrefix dstIpPrefix = dstIpAddress.toIpPrefix();
-
- TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
- if (dstIpAddress.isIp4()) {
- selector.matchEthType(Ethernet.TYPE_IPV4);
- selector.matchIPDst(dstIpPrefix);
- } else {
- selector.matchEthType(Ethernet.TYPE_IPV6);
- selector.matchIPv6Dst(dstIpPrefix);
- }
-
- // Rewrite the destination MAC address
- TrafficTreatment.Builder treatment =
- DefaultTrafficTreatment.builder().setEthDst(dstMacAddress);
-
- Key key = Key.of(dstIpPrefix.toString(), appId);
- int priority = dstIpPrefix.prefixLength() * PRIORITY_MULTIPLIER
- + PRIORITY_OFFSET;
- MultiPointToSinglePointIntent intent =
- MultiPointToSinglePointIntent.builder()
- .appId(appId)
- .key(key)
- .selector(selector.build())
- .treatment(treatment.build())
- .ingressPoints(ingressPoints)
- .egressPoint(dstConnectPoint)
- .priority(priority)
- .constraints(CONSTRAINTS)
- .build();
-
- log.trace("Generates ConnectivityHostToHost = {} ", intent);
- return intent;
- }
-
- @Override
- public void updateExistingMp2pIntent(IpPrefix ipPrefix,
- ConnectPoint ingressConnectPoint) {
- checkNotNull(ipPrefix);
- checkNotNull(ingressConnectPoint);
-
- MultiPointToSinglePointIntent existingIntent =
- getExistingMp2pIntent(ipPrefix);
- if (existingIntent != null) {
- Set<ConnectPoint> ingressPoints = existingIntent.ingressPoints();
- // Add host connect point into ingressPoints of the existing intent
- if (ingressPoints.add(ingressConnectPoint)) {
- MultiPointToSinglePointIntent updatedMp2pIntent =
- MultiPointToSinglePointIntent.builder()
- .appId(appId)
- .key(existingIntent.key())
- .selector(existingIntent.selector())
- .treatment(existingIntent.treatment())
- .ingressPoints(ingressPoints)
- .egressPoint(existingIntent.egressPoint())
- .priority(existingIntent.priority())
- .constraints(CONSTRAINTS)
- .build();
-
- log.trace("Update an existing MultiPointToSinglePointIntent "
- + "to new intent = {} ", updatedMp2pIntent);
- submitReactiveIntent(ipPrefix, updatedMp2pIntent);
- }
- // If adding ingressConnectPoint to ingressPoints failed, it
- // because between the time interval from checking existing intent
- // to generating new intent, onos updated this intent due to other
- // packet-in and the new intent also includes the
- // ingressConnectPoint. This will not affect reactive routing.
- }
- }
-
- @Override
- public boolean mp2pIntentExists(IpPrefix ipPrefix) {
- checkNotNull(ipPrefix);
- return routeIntents.get(ipPrefix) != null;
- }
-
- /**
- * Gets the existing MultiPointToSinglePointIntent from memory for a given
- * IP prefix.
- *
- * @param ipPrefix the IP prefix used to find MultiPointToSinglePointIntent
- * @return the MultiPointToSinglePointIntent if found, otherwise null
- */
- private MultiPointToSinglePointIntent getExistingMp2pIntent(IpPrefix
- ipPrefix) {
- checkNotNull(ipPrefix);
- return routeIntents.get(ipPrefix);
- }
}
diff --git a/framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/IntentUtils.java b/framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/IntentUtils.java
new file mode 100644
index 00000000..8e2a3df3
--- /dev/null
+++ b/framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/IntentUtils.java
@@ -0,0 +1,81 @@
+/*
+ * 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.sdnip;
+
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.MultiPointToSinglePointIntent;
+import org.onosproject.net.intent.PointToPointIntent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Objects;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+/**
+ * Utilities for dealing with intents.
+ */
+public final class IntentUtils {
+
+ private static final Logger log = LoggerFactory.getLogger(IntentUtils.class);
+
+ private IntentUtils() {
+
+ }
+
+ /**
+ * Checks if two intents represent the same value.
+ *
+ * <p>({@link Intent#equals(Object)} only checks ID equality)</p>
+ *
+ * <p>Both intents must be of the same type.</p>
+ *
+ * @param one first intent
+ * @param two second intent
+ * @return true if the two intents represent the same value, otherwise false
+ */
+ public static boolean equals(Intent one, Intent two) {
+ checkArgument(one.getClass() == two.getClass(),
+ "Intents are not the same type");
+
+ if (!(Objects.equals(one.appId(), two.appId()) &&
+ Objects.equals(one.key(), two.key()))) {
+ return false;
+ }
+
+ if (one instanceof MultiPointToSinglePointIntent) {
+ MultiPointToSinglePointIntent intent1 = (MultiPointToSinglePointIntent) one;
+ MultiPointToSinglePointIntent intent2 = (MultiPointToSinglePointIntent) two;
+
+ return Objects.equals(intent1.selector(), intent2.selector()) &&
+ Objects.equals(intent1.treatment(), intent2.treatment()) &&
+ Objects.equals(intent1.ingressPoints(), intent2.ingressPoints()) &&
+ Objects.equals(intent1.egressPoint(), intent2.egressPoint());
+ } else if (one instanceof PointToPointIntent) {
+ PointToPointIntent intent1 = (PointToPointIntent) one;
+ PointToPointIntent intent2 = (PointToPointIntent) two;
+
+ return Objects.equals(intent1.selector(), intent2.selector()) &&
+ Objects.equals(intent1.treatment(), intent2.treatment()) &&
+ Objects.equals(intent1.ingressPoint(), intent2.ingressPoint()) &&
+ Objects.equals(intent1.egressPoint(), intent2.egressPoint());
+ } else {
+ log.error("Unimplemented intent type");
+ return false;
+ }
+ }
+}
diff --git a/framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/PeerConnectivityManager.java b/framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/PeerConnectivityManager.java
index 459db2b7..b2ce0f8a 100644
--- a/framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/PeerConnectivityManager.java
+++ b/framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/PeerConnectivityManager.java
@@ -15,6 +15,8 @@
*/
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;
@@ -22,16 +24,18 @@ import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.TpPort;
import org.onosproject.core.ApplicationId;
-import org.onosproject.net.config.NetworkConfigService;
import org.onosproject.incubator.net.intf.Interface;
import org.onosproject.incubator.net.intf.InterfaceService;
import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.config.NetworkConfigService;
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.host.InterfaceIpAddress;
+import org.onosproject.net.intent.Key;
import org.onosproject.net.intent.PointToPointIntent;
+import org.onosproject.routing.IntentSynchronizationService;
import org.onosproject.routing.RoutingService;
import org.onosproject.routing.config.BgpConfig;
import org.slf4j.Logger;
@@ -49,18 +53,26 @@ import static com.google.common.base.Preconditions.checkNotNull;
public class PeerConnectivityManager {
private static final int PRIORITY_OFFSET = 1000;
+ private static final String SUFFIX_DST = "dst";
+ private static final String SUFFIX_SRC = "src";
+ private static final String SUFFIX_ICMP = "icmp";
+
private static final Logger log = LoggerFactory.getLogger(
PeerConnectivityManager.class);
private static final short BGP_PORT = 179;
- private final IntentSynchronizer intentSynchronizer;
+ private final IntentSynchronizationService intentSynchronizer;
private final NetworkConfigService configService;
private final InterfaceService interfaceService;
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;
+
/**
* Creates a new PeerConnectivityManager.
*
@@ -71,7 +83,7 @@ public class PeerConnectivityManager {
* @param routerAppId application ID
*/
public PeerConnectivityManager(ApplicationId appId,
- IntentSynchronizer intentSynchronizer,
+ IntentSynchronizationService intentSynchronizer,
NetworkConfigService configService,
ApplicationId routerAppId,
InterfaceService interfaceService) {
@@ -80,6 +92,8 @@ public class PeerConnectivityManager {
this.configService = configService;
this.routerAppId = routerAppId;
this.interfaceService = interfaceService;
+
+ peerIntents = HashMultimap.create();
}
/**
@@ -100,8 +114,6 @@ public class PeerConnectivityManager {
* BGP speakers and external BGP peers.
*/
private void setUpConnectivity() {
- List<PointToPointIntent> intents = new ArrayList<>();
-
BgpConfig config = configService.getConfig(routerAppId, RoutingService.CONFIG_CLASS);
if (config == null) {
@@ -113,11 +125,12 @@ public class PeerConnectivityManager {
log.debug("Start to set up BGP paths for BGP speaker: {}",
bgpSpeaker);
- intents.addAll(buildSpeakerIntents(bgpSpeaker));
- }
+ buildSpeakerIntents(bgpSpeaker).forEach(i -> {
+ peerIntents.put(bgpSpeaker, i);
+ intentSynchronizer.submit(i);
+ });
- // Submit all the intents.
- intentSynchronizer.submitPeerIntents(intents);
+ }
}
private Collection<PointToPointIntent> buildSpeakerIntents(BgpConfig.BgpSpeakerConfig speaker) {
@@ -167,8 +180,8 @@ public class PeerConnectivityManager {
List<PointToPointIntent> intents = new ArrayList<>();
TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment();
-
TrafficSelector selector;
+ Key key;
byte tcpProtocol;
byte icmpProtocol;
@@ -188,8 +201,11 @@ public class PeerConnectivityManager {
null,
BGP_PORT);
+ key = buildKey(ipOne, ipTwo, SUFFIX_DST);
+
intents.add(PointToPointIntent.builder()
.appId(appId)
+ .key(key)
.selector(selector)
.treatment(treatment)
.ingressPoint(portOne)
@@ -204,8 +220,11 @@ public class PeerConnectivityManager {
BGP_PORT,
null);
+ key = buildKey(ipOne, ipTwo, SUFFIX_SRC);
+
intents.add(PointToPointIntent.builder()
.appId(appId)
+ .key(key)
.selector(selector)
.treatment(treatment)
.ingressPoint(portOne)
@@ -220,8 +239,11 @@ public class PeerConnectivityManager {
null,
BGP_PORT);
+ key = buildKey(ipTwo, ipOne, SUFFIX_DST);
+
intents.add(PointToPointIntent.builder()
.appId(appId)
+ .key(key)
.selector(selector)
.treatment(treatment)
.ingressPoint(portTwo)
@@ -236,8 +258,11 @@ public class PeerConnectivityManager {
BGP_PORT,
null);
+ key = buildKey(ipTwo, ipOne, SUFFIX_SRC);
+
intents.add(PointToPointIntent.builder()
.appId(appId)
+ .key(key)
.selector(selector)
.treatment(treatment)
.ingressPoint(portTwo)
@@ -252,8 +277,11 @@ public class PeerConnectivityManager {
null,
null);
+ key = buildKey(ipOne, ipTwo, SUFFIX_ICMP);
+
intents.add(PointToPointIntent.builder()
.appId(appId)
+ .key(key)
.selector(selector)
.treatment(treatment)
.ingressPoint(portOne)
@@ -268,8 +296,11 @@ public class PeerConnectivityManager {
null,
null);
+ key = buildKey(ipTwo, ipOne, SUFFIX_ICMP);
+
intents.add(PointToPointIntent.builder()
.appId(appId)
+ .key(key)
.selector(selector)
.treatment(treatment)
.ingressPoint(portTwo)
@@ -316,4 +347,27 @@ public class PeerConnectivityManager {
return builder.build();
}
+ /**
+ * Builds an intent Key for a point-to-point intent based off the source
+ * and destination IP address, as well as a suffix String to distinguish
+ * between different types of intents between the same source and
+ * destination.
+ *
+ * @param srcIp source IP address
+ * @param dstIp destination IP address
+ * @param suffix suffix string
+ * @return
+ */
+ private Key buildKey(IpAddress srcIp, IpAddress dstIp, String suffix) {
+ String keyString = new StringBuilder()
+ .append(srcIp.toString())
+ .append("-")
+ .append(dstIp.toString())
+ .append("-")
+ .append(suffix)
+ .toString();
+
+ return Key.of(keyString, appId);
+ }
+
}
diff --git a/framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/SdnIp.java b/framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/SdnIp.java
index 3d1fe65c..1b3eda9d 100644
--- a/framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/SdnIp.java
+++ b/framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/SdnIp.java
@@ -32,7 +32,9 @@ import org.onosproject.net.config.NetworkConfigService;
import org.onosproject.incubator.net.intf.InterfaceService;
import org.onosproject.net.host.HostService;
import org.onosproject.net.intent.IntentService;
+import org.onosproject.routing.IntentSynchronizationService;
import org.onosproject.routing.RoutingService;
+import org.onosproject.routing.SdnIpService;
import org.onosproject.routing.config.RoutingConfigurationService;
import org.slf4j.Logger;
@@ -79,6 +81,7 @@ public class SdnIp implements SdnIpService {
private IntentSynchronizer intentSynchronizer;
private PeerConnectivityManager peerConnectivity;
+ private SdnIpFib fib;
private LeadershipEventListener leadershipEventListener =
new InnerLeadershipEventListener();
@@ -93,10 +96,7 @@ public class SdnIp implements SdnIpService {
localControllerNode = clusterService.getLocalNode();
- intentSynchronizer = new IntentSynchronizer(appId, intentService,
- hostService,
- config,
- interfaceService);
+ intentSynchronizer = new IntentSynchronizer(appId, intentService);
intentSynchronizer.start();
peerConnectivity = new PeerConnectivityManager(appId,
@@ -106,8 +106,9 @@ public class SdnIp implements SdnIpService {
interfaceService);
peerConnectivity.start();
- routingService.addFibListener(intentSynchronizer);
- routingService.addIntentRequestListener(intentSynchronizer);
+ fib = new SdnIpFib(appId, interfaceService, intentSynchronizer);
+
+ routingService.addFibListener(fib);
routingService.start();
leadershipService.addListener(leadershipEventListener);
@@ -131,6 +132,11 @@ public class SdnIp implements SdnIpService {
intentSynchronizer.leaderChanged(isPrimary);
}
+ @Override
+ public IntentSynchronizationService getIntentSynchronizationService() {
+ return intentSynchronizer;
+ }
+
/**
* Converts DPIDs of the form xx:xx:xx:xx:xx:xx:xx to OpenFlow provider
* device URIs.
diff --git a/framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/SdnIpFib.java b/framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/SdnIpFib.java
new file mode 100644
index 00000000..c0001bdc
--- /dev/null
+++ b/framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/SdnIpFib.java
@@ -0,0 +1,216 @@
+/*
+ * 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.sdnip;
+
+import com.google.common.collect.ImmutableList;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
+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.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.intent.Constraint;
+import org.onosproject.net.intent.Key;
+import org.onosproject.net.intent.MultiPointToSinglePointIntent;
+import org.onosproject.net.intent.constraint.PartialFailureConstraint;
+import org.onosproject.routing.FibListener;
+import org.onosproject.routing.FibUpdate;
+import org.onosproject.routing.IntentSynchronizationService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+/**
+ * FIB component of SDN-IP.
+ */
+public class SdnIpFib implements FibListener {
+ private Logger log = LoggerFactory.getLogger(getClass());
+
+ private static final int PRIORITY_OFFSET = 100;
+ private static final int PRIORITY_MULTIPLIER = 5;
+ protected static final ImmutableList<Constraint> CONSTRAINTS
+ = ImmutableList.of(new PartialFailureConstraint());
+
+ private final Map<IpPrefix, MultiPointToSinglePointIntent> routeIntents;
+
+ private final ApplicationId appId;
+ private final InterfaceService interfaceService;
+ private final IntentSynchronizationService intentSynchronizer;
+
+ /**
+ * Class constructor.
+ *
+ * @param appId application ID to use when generating intents
+ * @param interfaceService interface service
+ * @param intentSynchronizer intent synchronizer
+ */
+ public SdnIpFib(ApplicationId appId, InterfaceService interfaceService,
+ IntentSynchronizationService intentSynchronizer) {
+ routeIntents = new ConcurrentHashMap<>();
+
+ this.appId = appId;
+ this.interfaceService = interfaceService;
+ this.intentSynchronizer = intentSynchronizer;
+ }
+
+
+ @Override
+ public void update(Collection<FibUpdate> updates, Collection<FibUpdate> withdraws) {
+ int submitCount = 0, withdrawCount = 0;
+ //
+ // NOTE: Semantically, we MUST withdraw existing intents before
+ // submitting new intents.
+ //
+ synchronized (this) {
+ MultiPointToSinglePointIntent intent;
+
+ //
+ // Prepare the Intent batch operations for the intents to withdraw
+ //
+ for (FibUpdate withdraw : withdraws) {
+ checkArgument(withdraw.type() == FibUpdate.Type.DELETE,
+ "FibUpdate with wrong type in withdraws list");
+
+ IpPrefix prefix = withdraw.entry().prefix();
+ intent = routeIntents.remove(prefix);
+ if (intent == null) {
+ log.trace("SDN-IP No intent in routeIntents to delete " +
+ "for prefix: {}", prefix);
+ continue;
+ }
+ intentSynchronizer.withdraw(intent);
+ withdrawCount++;
+ }
+
+ //
+ // Prepare the Intent batch operations for the intents to submit
+ //
+ for (FibUpdate update : updates) {
+ checkArgument(update.type() == FibUpdate.Type.UPDATE,
+ "FibUpdate with wrong type in updates list");
+
+ IpPrefix prefix = update.entry().prefix();
+ intent = generateRouteIntent(prefix, update.entry().nextHopIp(),
+ update.entry().nextHopMac());
+
+ if (intent == null) {
+ // This preserves the old semantics - if an intent can't be
+ // generated, we don't do anything with that prefix. But
+ // perhaps we should withdraw the old intent anyway?
+ continue;
+ }
+
+ routeIntents.put(prefix, intent);
+ intentSynchronizer.submit(intent);
+ submitCount++;
+ }
+
+ log.debug("SDN-IP submitted {}/{}, withdrew = {}/{}", submitCount,
+ updates.size(), withdrawCount, withdraws.size());
+ }
+ }
+
+ /**
+ * Generates a route intent for a prefix, the next hop IP address, and
+ * the next hop MAC address.
+ * <p/>
+ * This method will find the egress interface for the intent.
+ * Intent will match dst IP prefix and rewrite dst MAC address at all other
+ * border switches, then forward packets according to dst MAC address.
+ *
+ * @param prefix IP prefix of the route to add
+ * @param nextHopIpAddress IP address of the next hop
+ * @param nextHopMacAddress MAC address of the next hop
+ * @return the generated intent, or null if no intent should be submitted
+ */
+ private MultiPointToSinglePointIntent generateRouteIntent(
+ IpPrefix prefix,
+ IpAddress nextHopIpAddress,
+ MacAddress nextHopMacAddress) {
+
+ // Find the attachment point (egress interface) of the next hop
+ Interface egressInterface = interfaceService.getMatchingInterface(nextHopIpAddress);
+ if (egressInterface == null) {
+ log.warn("No outgoing interface found for {}",
+ nextHopIpAddress);
+ return null;
+ }
+
+ // Generate the intent itself
+ Set<ConnectPoint> ingressPorts = new HashSet<>();
+ ConnectPoint egressPort = egressInterface.connectPoint();
+ log.debug("Generating intent for prefix {}, next hop mac {}",
+ prefix, nextHopMacAddress);
+
+ for (Interface intf : interfaceService.getInterfaces()) {
+ // TODO this should be only peering interfaces
+ if (!intf.connectPoint().equals(egressInterface.connectPoint())) {
+ ConnectPoint srcPort = intf.connectPoint();
+ ingressPorts.add(srcPort);
+ }
+ }
+
+ // Match the destination IP prefix at the first hop
+ TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+ if (prefix.isIp4()) {
+ selector.matchEthType(Ethernet.TYPE_IPV4);
+ selector.matchIPDst(prefix);
+ } else {
+ selector.matchEthType(Ethernet.TYPE_IPV6);
+ selector.matchIPv6Dst(prefix);
+ }
+
+ // Rewrite the destination MAC address
+ TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
+ .setEthDst(nextHopMacAddress);
+ if (!egressInterface.vlan().equals(VlanId.NONE)) {
+ treatment.setVlanId(egressInterface.vlan());
+ // If we set VLAN ID, we have to make sure a VLAN tag exists.
+ // TODO support no VLAN -> VLAN routing
+ selector.matchVlanId(VlanId.ANY);
+ }
+
+ int priority =
+ prefix.prefixLength() * PRIORITY_MULTIPLIER + PRIORITY_OFFSET;
+ Key key = Key.of(prefix.toString(), appId);
+ return MultiPointToSinglePointIntent.builder()
+ .appId(appId)
+ .key(key)
+ .selector(selector.build())
+ .treatment(treatment.build())
+ .ingressPoints(ingressPorts)
+ .egressPoint(egressPort)
+ .priority(priority)
+ .constraints(CONSTRAINTS)
+ .build();
+ }
+
+}
diff --git a/framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/PrimaryChangeCommand.java b/framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/PrimaryChangeCommand.java
index 72cc112e..7a17cfe0 100644
--- a/framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/PrimaryChangeCommand.java
+++ b/framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/PrimaryChangeCommand.java
@@ -18,7 +18,7 @@ package org.onosproject.sdnip.cli;
import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.sdnip.SdnIpService;
+import org.onosproject.routing.SdnIpService;
/**
* Command to change whether this SDNIP instance is primary or not.
diff --git a/framework/src/onos/apps/sdnip/src/test/java/org/onosproject/sdnip/IntentSyncTest.java b/framework/src/onos/apps/sdnip/src/test/java/org/onosproject/sdnip/IntentSyncTest.java
index fc5782e4..6dc3ce10 100644
--- a/framework/src/onos/apps/sdnip/src/test/java/org/onosproject/sdnip/IntentSyncTest.java
+++ b/framework/src/onos/apps/sdnip/src/test/java/org/onosproject/sdnip/IntentSyncTest.java
@@ -16,6 +16,7 @@
package org.onosproject.sdnip;
import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.MoreExecutors;
import org.junit.Before;
import org.junit.Test;
import org.onlab.junit.TestUtils;
@@ -27,10 +28,9 @@ import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
+import org.onosproject.TestApplicationId;
import org.onosproject.core.ApplicationId;
-import org.onosproject.net.config.NetworkConfigService;
import org.onosproject.incubator.net.intf.Interface;
-import org.onosproject.incubator.net.intf.InterfaceService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
@@ -43,20 +43,13 @@ import org.onosproject.net.intent.AbstractIntentTest;
import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentService;
import org.onosproject.net.intent.IntentState;
+import org.onosproject.net.intent.Key;
import org.onosproject.net.intent.MultiPointToSinglePointIntent;
-import org.onosproject.routing.FibEntry;
-import org.onosproject.routing.FibUpdate;
import org.onosproject.routing.RouteEntry;
-import org.onosproject.routing.config.BgpPeer;
-import org.onosproject.routing.config.RoutingConfigurationService;
-import org.onosproject.sdnip.IntentSynchronizer.IntentKey;
import java.util.Collections;
-import java.util.HashMap;
import java.util.HashSet;
-import java.util.Map;
import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
@@ -64,11 +57,8 @@ import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.reset;
import static org.easymock.EasyMock.verify;
import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.onosproject.sdnip.TestIntentServiceHelper.eqExceptId;
/**
* This class tests the intent synchronization function in the
@@ -76,10 +66,7 @@ import static org.onosproject.sdnip.TestIntentServiceHelper.eqExceptId;
*/
public class IntentSyncTest extends AbstractIntentTest {
- private RoutingConfigurationService routingConfig;
- private InterfaceService interfaceService;
private IntentService intentService;
- private NetworkConfigService configService;
private static final ConnectPoint SW1_ETH1 = new ConnectPoint(
DeviceId.deviceId("of:0000000000000001"),
@@ -100,65 +87,18 @@ public class IntentSyncTest extends AbstractIntentTest {
private IntentSynchronizer intentSynchronizer;
private final Set<Interface> interfaces = Sets.newHashSet();
- private static final ApplicationId APPID = new ApplicationId() {
- @Override
- public short id() {
- return 1;
- }
-
- @Override
- public String name() {
- return "SDNIP";
- }
- };
+ private static final ApplicationId APPID = TestApplicationId.create("SDNIP");
@Before
public void setUp() throws Exception {
super.setUp();
- routingConfig = createMock(RoutingConfigurationService.class);
- interfaceService = createMock(InterfaceService.class);
- configService = createMock(NetworkConfigService.class);
-
- // These will set expectations on routingConfig
setUpInterfaceService();
- setUpBgpPeers();
-
- replay(routingConfig);
- replay(interfaceService);
intentService = createMock(IntentService.class);
intentSynchronizer = new IntentSynchronizer(APPID, intentService,
- null, routingConfig,
- interfaceService);
- }
-
- /**
- * Sets up BGP peers in external networks.
- */
- private void setUpBgpPeers() {
-
- Map<IpAddress, BgpPeer> peers = new HashMap<>();
-
- String peerSw1Eth1 = "192.168.10.1";
- peers.put(IpAddress.valueOf(peerSw1Eth1),
- new BgpPeer("00:00:00:00:00:00:00:01", 1, peerSw1Eth1));
-
- // Two BGP peers are connected to switch 2 port 1.
- String peer1Sw2Eth1 = "192.168.20.1";
- peers.put(IpAddress.valueOf(peer1Sw2Eth1),
- new BgpPeer("00:00:00:00:00:00:00:02", 1, peer1Sw2Eth1));
-
- String peer2Sw2Eth1 = "192.168.20.2";
- peers.put(IpAddress.valueOf(peer2Sw2Eth1),
- new BgpPeer("00:00:00:00:00:00:00:02", 1, peer2Sw2Eth1));
-
- String peer1Sw4Eth1 = "192.168.40.1";
- peers.put(IpAddress.valueOf(peer1Sw4Eth1),
- new BgpPeer("00:00:00:00:00:00:00:04", 1, peer1Sw4Eth1));
-
- expect(routingConfig.getBgpPeers()).andReturn(peers).anyTimes();
+ MoreExecutors.newDirectExecutorService());
}
/**
@@ -200,267 +140,13 @@ public class IntentSyncTest extends AbstractIntentTest {
MacAddress.valueOf("00:00:00:00:00:04"),
VlanId.vlanId((short) 1));
- expect(interfaceService.getInterfacesByPort(SW4_ETH1)).andReturn(
- Collections.singleton(sw4Eth1)).anyTimes();
- expect(interfaceService.getMatchingInterface(Ip4Address.valueOf("192.168.40.1")))
- .andReturn(sw4Eth1).anyTimes();
-
interfaces.add(sw4Eth1);
-
- expect(interfaceService.getInterfacesByPort(SW1_ETH1)).andReturn(
- Collections.singleton(sw1Eth1)).anyTimes();
- expect(interfaceService.getMatchingInterface(Ip4Address.valueOf("192.168.10.1")))
- .andReturn(sw1Eth1).anyTimes();
- expect(interfaceService.getInterfacesByPort(SW2_ETH1)).andReturn(
- Collections.singleton(sw2Eth1)).anyTimes();
- expect(interfaceService.getMatchingInterface(Ip4Address.valueOf("192.168.20.1")))
- .andReturn(sw2Eth1).anyTimes();
- expect(interfaceService.getInterfacesByPort(SW3_ETH1)).andReturn(
- Collections.singleton(sw3Eth1)).anyTimes();
- expect(interfaceService.getMatchingInterface(Ip4Address.valueOf("192.168.30.1")))
- .andReturn(sw3Eth1).anyTimes();
- expect(interfaceService.getInterfaces()).andReturn(interfaces).anyTimes();
- }
-
- /**
- * Tests adding a FIB entry to the IntentSynchronizer.
- *
- * We verify that the synchronizer records the correct state and that the
- * correct intent is submitted to the IntentService.
- *
- * @throws TestUtilsException
- */
- @Test
- public void testFibAdd() throws TestUtilsException {
- FibEntry fibEntry = new FibEntry(
- Ip4Prefix.valueOf("1.1.1.0/24"),
- Ip4Address.valueOf("192.168.10.1"),
- MacAddress.valueOf("00:00:00:00:00:01"));
-
- // Construct a MultiPointToSinglePointIntent intent
- TrafficSelector.Builder selectorBuilder =
- DefaultTrafficSelector.builder();
- selectorBuilder.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(
- fibEntry.prefix());
-
- TrafficTreatment.Builder treatmentBuilder =
- DefaultTrafficTreatment.builder();
- treatmentBuilder.setEthDst(MacAddress.valueOf("00:00:00:00:00:01"));
-
- Set<ConnectPoint> ingressPoints = new HashSet<>();
- ingressPoints.add(SW2_ETH1);
- ingressPoints.add(SW3_ETH1);
- ingressPoints.add(SW4_ETH1);
-
- MultiPointToSinglePointIntent intent =
- MultiPointToSinglePointIntent.builder()
- .appId(APPID)
- .selector(selectorBuilder.build())
- .treatment(treatmentBuilder.build())
- .ingressPoints(ingressPoints)
- .egressPoint(SW1_ETH1)
- .constraints(IntentSynchronizer.CONSTRAINTS)
- .build();
-
- // Setup the expected intents
- intentService.submit(eqExceptId(intent));
- replay(intentService);
-
- intentSynchronizer.leaderChanged(true);
- TestUtils.setField(intentSynchronizer, "isActivatedLeader", true);
-
- FibUpdate fibUpdate = new FibUpdate(FibUpdate.Type.UPDATE,
- fibEntry);
- intentSynchronizer.update(Collections.singleton(fibUpdate),
- Collections.emptyList());
-
- assertEquals(intentSynchronizer.getRouteIntents().size(), 1);
- Intent firstIntent =
- intentSynchronizer.getRouteIntents().iterator().next();
- IntentKey firstIntentKey = new IntentKey(firstIntent);
- IntentKey intentKey = new IntentKey(intent);
- assertTrue(firstIntentKey.equals(intentKey));
- verify(intentService);
- }
-
- /**
- * Tests adding a FIB entry with to a next hop in a VLAN.
- *
- * We verify that the synchronizer records the correct state and that the
- * correct intent is submitted to the IntentService.
- *
- * @throws TestUtilsException
- */
- @Test
- public void testFibAddWithVlan() throws TestUtilsException {
- FibEntry fibEntry = new FibEntry(
- Ip4Prefix.valueOf("3.3.3.0/24"),
- Ip4Address.valueOf("192.168.40.1"),
- MacAddress.valueOf("00:00:00:00:00:04"));
-
- // Construct a MultiPointToSinglePointIntent intent
- TrafficSelector.Builder selectorBuilder =
- DefaultTrafficSelector.builder();
- selectorBuilder.matchEthType(Ethernet.TYPE_IPV4)
- .matchIPDst(fibEntry.prefix())
- .matchVlanId(VlanId.ANY);
-
- TrafficTreatment.Builder treatmentBuilder =
- DefaultTrafficTreatment.builder();
- treatmentBuilder.setEthDst(MacAddress.valueOf("00:00:00:00:00:04"))
- .setVlanId(VlanId.vlanId((short) 1));
-
- Set<ConnectPoint> ingressPoints = new HashSet<>();
- ingressPoints.add(SW1_ETH1);
- ingressPoints.add(SW2_ETH1);
- ingressPoints.add(SW3_ETH1);
-
- MultiPointToSinglePointIntent intent =
- MultiPointToSinglePointIntent.builder()
- .appId(APPID)
- .selector(selectorBuilder.build())
- .treatment(treatmentBuilder.build())
- .ingressPoints(ingressPoints)
- .egressPoint(SW4_ETH1)
- .constraints(IntentSynchronizer.CONSTRAINTS)
- .build();
-
- // Setup the expected intents
- intentService.submit(eqExceptId(intent));
-
- replay(intentService);
-
- // Run the test
- intentSynchronizer.leaderChanged(true);
- TestUtils.setField(intentSynchronizer, "isActivatedLeader", true);
- FibUpdate fibUpdate = new FibUpdate(FibUpdate.Type.UPDATE, fibEntry);
-
- intentSynchronizer.update(Collections.singleton(fibUpdate),
- Collections.emptyList());
-
- // Verify
- assertEquals(intentSynchronizer.getRouteIntents().size(), 1);
- Intent firstIntent =
- intentSynchronizer.getRouteIntents().iterator().next();
- IntentKey firstIntentKey = new IntentKey(firstIntent);
- IntentKey intentKey = new IntentKey(intent);
- assertTrue(firstIntentKey.equals(intentKey));
- verify(intentService);
- }
-
- /**
- * Tests updating a FIB entry.
- *
- * We verify that the synchronizer records the correct state and that the
- * correct intent is submitted to the IntentService.
- *
- * @throws TestUtilsException
- */
- @Test
- public void testFibUpdate() throws TestUtilsException {
- // Firstly add a route
- testFibAdd();
-
- Intent addedIntent =
- intentSynchronizer.getRouteIntents().iterator().next();
-
- // Start to construct a new route entry and new intent
- FibEntry fibEntryUpdate = new FibEntry(
- Ip4Prefix.valueOf("1.1.1.0/24"),
- Ip4Address.valueOf("192.168.20.1"),
- MacAddress.valueOf("00:00:00:00:00:02"));
-
- // Construct a new MultiPointToSinglePointIntent intent
- TrafficSelector.Builder selectorBuilderNew =
- DefaultTrafficSelector.builder();
- selectorBuilderNew.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(
- fibEntryUpdate.prefix());
-
- TrafficTreatment.Builder treatmentBuilderNew =
- DefaultTrafficTreatment.builder();
- treatmentBuilderNew.setEthDst(MacAddress.valueOf("00:00:00:00:00:02"));
-
-
- Set<ConnectPoint> ingressPointsNew = new HashSet<>();
- ingressPointsNew.add(SW1_ETH1);
- ingressPointsNew.add(SW3_ETH1);
- ingressPointsNew.add(SW4_ETH1);
-
- MultiPointToSinglePointIntent intentNew =
- MultiPointToSinglePointIntent.builder()
- .appId(APPID)
- .selector(selectorBuilderNew.build())
- .treatment(treatmentBuilderNew.build())
- .ingressPoints(ingressPointsNew)
- .egressPoint(SW2_ETH1)
- .constraints(IntentSynchronizer.CONSTRAINTS)
- .build();
-
- // Set up test expectation
- reset(intentService);
- // Setup the expected intents
- intentService.withdraw(eqExceptId(addedIntent));
- intentService.submit(eqExceptId(intentNew));
- replay(intentService);
-
- // Call the update() method in IntentSynchronizer class
- intentSynchronizer.leaderChanged(true);
- TestUtils.setField(intentSynchronizer, "isActivatedLeader", true);
- FibUpdate fibUpdate = new FibUpdate(FibUpdate.Type.UPDATE,
- fibEntryUpdate);
- intentSynchronizer.update(Collections.singletonList(fibUpdate),
- Collections.emptyList());
-
- // Verify
- assertEquals(intentSynchronizer.getRouteIntents().size(), 1);
- Intent firstIntent =
- intentSynchronizer.getRouteIntents().iterator().next();
- IntentKey firstIntentKey = new IntentKey(firstIntent);
- IntentKey intentNewKey = new IntentKey(intentNew);
- assertTrue(firstIntentKey.equals(intentNewKey));
- verify(intentService);
}
/**
- * Tests deleting a FIB entry.
- *
- * We verify that the synchronizer records the correct state and that the
- * correct intent is withdrawn from the IntentService.
- *
- * @throws TestUtilsException
- */
- @Test
- public void testFibDelete() throws TestUtilsException {
- // Firstly add a route
- testFibAdd();
-
- Intent addedIntent =
- intentSynchronizer.getRouteIntents().iterator().next();
-
- // Construct the existing route entry
- FibEntry fibEntry = new FibEntry(
- Ip4Prefix.valueOf("1.1.1.0/24"), null, null);
-
- // Set up expectation
- reset(intentService);
- // Setup the expected intents
- intentService.withdraw(eqExceptId(addedIntent));
- replay(intentService);
-
- // Call the update() method in IntentSynchronizer class
- intentSynchronizer.leaderChanged(true);
- TestUtils.setField(intentSynchronizer, "isActivatedLeader", true);
- FibUpdate fibUpdate = new FibUpdate(FibUpdate.Type.DELETE, fibEntry);
- intentSynchronizer.update(Collections.emptyList(),
- Collections.singletonList(fibUpdate));
-
- // Verify
- assertEquals(intentSynchronizer.getRouteIntents().size(), 0);
- verify(intentService);
- }
-
- /**
- * This method tests the behavior of intent Synchronizer.
+ * Tests the synchronization behavior of intent synchronizer. We set up
+ * a discrepancy between the intent service state and the intent
+ * synchronizer's state and ensure that this is reconciled correctly.
*
* @throws TestUtilsException
*/
@@ -529,27 +215,13 @@ public class IntentSyncTest extends AbstractIntentTest {
// Compose a intent, which is equal to intent5 but the id is different.
MultiPointToSinglePointIntent intent5New =
staticIntentBuilder(intent5, routeEntry5, "00:00:00:00:00:01");
- assertThat(IntentSynchronizer.IntentKey.equalIntents(
- intent5, intent5New),
- is(true));
+ assertThat(IntentUtils.equals(intent5, intent5New), is(true));
assertFalse(intent5.equals(intent5New));
MultiPointToSinglePointIntent intent6 = intentBuilder(
routeEntry6.prefix(), "00:00:00:00:00:01", SW1_ETH1);
- // Set up the routeIntents field in IntentSynchronizer class
- ConcurrentHashMap<IpPrefix, MultiPointToSinglePointIntent>
- routeIntents = new ConcurrentHashMap<>();
- routeIntents.put(routeEntry1.prefix(), intent1);
- routeIntents.put(routeEntry3.prefix(), intent3);
- routeIntents.put(routeEntry4Update.prefix(), intent4Update);
- routeIntents.put(routeEntry5.prefix(), intent5New);
- routeIntents.put(routeEntry6.prefix(), intent6);
- routeIntents.put(routeEntry7.prefix(), intent7);
- TestUtils.setField(intentSynchronizer, "routeIntents", routeIntents);
-
// Set up expectation
- reset(intentService);
Set<Intent> intents = new HashSet<>();
intents.add(intent1);
expect(intentService.getIntentState(intent1.key()))
@@ -568,9 +240,9 @@ public class IntentSyncTest extends AbstractIntentTest {
.andReturn(IntentState.WITHDRAWING).anyTimes();
expect(intentService.getIntents()).andReturn(intents).anyTimes();
+ // These are the operations that should be done to the intentService
+ // during synchronization
intentService.withdraw(intent2);
- intentService.withdraw(intent4);
-
intentService.submit(intent3);
intentService.submit(intent4Update);
intentService.submit(intent6);
@@ -578,16 +250,101 @@ public class IntentSyncTest extends AbstractIntentTest {
replay(intentService);
// Start the test
+
+ // Simulate some input from the clients. The intent synchronizer has not
+ // gained the global leadership yet, but it will remember this input for
+ // when it does.
+ intentSynchronizer.submit(intent1);
+ intentSynchronizer.submit(intent2);
+ intentSynchronizer.withdraw(intent2);
+ intentSynchronizer.submit(intent3);
+ intentSynchronizer.submit(intent4);
+ intentSynchronizer.submit(intent4Update);
+ intentSynchronizer.submit(intent5);
+ intentSynchronizer.submit(intent6);
+ intentSynchronizer.submit(intent7);
+
+ // Give the leadership to the intent synchronizer. It will now attempt
+ // to synchronize the intents in the store with the intents it has
+ // recorded based on the earlier user input.
+ intentSynchronizer.leaderChanged(true);
+
+ verify(intentService);
+ }
+
+ /**
+ * Tests the behavior of the submit API, both when the synchronizer has
+ * leadership and when it does not.
+ */
+ @Test
+ public void testSubmit() {
+ IpPrefix prefix = Ip4Prefix.valueOf("1.1.1.0/24");
+ Intent intent = intentBuilder(prefix, "00:00:00:00:00:01", SW1_ETH1);
+
+ // Set up expectations
+ intentService.submit(intent);
+ expect(intentService.getIntents()).andReturn(Collections.emptyList())
+ .anyTimes();
+ replay(intentService);
+
+ // Give the intent synchronizer leadership so it will submit intents
+ // to the intent service
+ intentSynchronizer.leaderChanged(true);
+
+ // Test the submit
+ intentSynchronizer.submit(intent);
+
+ verify(intentService);
+
+ // Now we'll remove leadership from the intent synchronizer and verify
+ // that it does not submit any intents to the intent service when we
+ // call the submit API
+ reset(intentService);
+ replay(intentService);
+
+ intentSynchronizer.leaderChanged(false);
+
+ intentSynchronizer.submit(intent);
+
+ verify(intentService);
+ }
+
+ /**
+ * Tests the behavior of the withdraw API, both when the synchronizer has
+ * leadership and when it does not.
+ */
+ @Test
+ public void testWithdraw() {
+ IpPrefix prefix = Ip4Prefix.valueOf("1.1.1.0/24");
+ Intent intent = intentBuilder(prefix, "00:00:00:00:00:01", SW1_ETH1);
+
+ // Submit an intent first so we can withdraw it later
+ intentService.submit(intent);
+ intentService.withdraw(intent);
+ expect(intentService.getIntents()).andReturn(Collections.emptyList())
+ .anyTimes();
+ replay(intentService);
+
+ // Give the intent synchronizer leadership so it will submit intents
+ // to the intent service
intentSynchronizer.leaderChanged(true);
- intentSynchronizer.synchronizeIntents();
- // Verify
- assertEquals(intentSynchronizer.getRouteIntents().size(), 6);
- assertTrue(intentSynchronizer.getRouteIntents().contains(intent1));
- assertTrue(intentSynchronizer.getRouteIntents().contains(intent3));
- assertTrue(intentSynchronizer.getRouteIntents().contains(intent4Update));
- assertTrue(intentSynchronizer.getRouteIntents().contains(intent5));
- assertTrue(intentSynchronizer.getRouteIntents().contains(intent6));
+ // Test the submit then withdraw
+ intentSynchronizer.submit(intent);
+ intentSynchronizer.withdraw(intent);
+
+ verify(intentService);
+
+ // Now we'll remove leadership from the intent synchronizer and verify
+ // that it does not withdraw any intents to the intent service when we
+ // call the withdraw API
+ reset(intentService);
+ replay(intentService);
+
+ intentSynchronizer.leaderChanged(false);
+
+ intentSynchronizer.submit(intent);
+ intentSynchronizer.withdraw(intent);
verify(intentService);
}
@@ -607,10 +364,10 @@ public class IntentSyncTest extends AbstractIntentTest {
TrafficSelector.Builder selectorBuilder =
DefaultTrafficSelector.builder();
if (ipPrefix.isIp4()) {
- selectorBuilder.matchEthType(Ethernet.TYPE_IPV4); // IPv4
+ selectorBuilder.matchEthType(Ethernet.TYPE_IPV4);
selectorBuilder.matchIPDst(ipPrefix);
} else {
- selectorBuilder.matchEthType(Ethernet.TYPE_IPV6); // IPv6
+ selectorBuilder.matchEthType(Ethernet.TYPE_IPV6);
selectorBuilder.matchIPv6Dst(ipPrefix);
}
@@ -628,11 +385,12 @@ public class IntentSyncTest extends AbstractIntentTest {
MultiPointToSinglePointIntent intent =
MultiPointToSinglePointIntent.builder()
.appId(APPID)
+ .key(Key.of(ipPrefix.toString(), APPID))
.selector(selectorBuilder.build())
.treatment(treatmentBuilder.build())
.ingressPoints(ingressPoints)
.egressPoint(egressPoint)
- .constraints(IntentSynchronizer.CONSTRAINTS)
+ .constraints(SdnIpFib.CONSTRAINTS)
.build();
return intent;
}
@@ -646,7 +404,7 @@ public class IntentSyncTest extends AbstractIntentTest {
* @return the newly constructed MultiPointToSinglePointIntent
* @throws TestUtilsException
*/
- private MultiPointToSinglePointIntent staticIntentBuilder(
+ private MultiPointToSinglePointIntent staticIntentBuilder(
MultiPointToSinglePointIntent intent, RouteEntry routeEntry,
String nextHopMacAddress) throws TestUtilsException {
diff --git a/framework/src/onos/apps/sdnip/src/test/java/org/onosproject/sdnip/PeerConnectivityManagerTest.java b/framework/src/onos/apps/sdnip/src/test/java/org/onosproject/sdnip/PeerConnectivityManagerTest.java
index d89c3c2b..c4b2daad 100644
--- a/framework/src/onos/apps/sdnip/src/test/java/org/onosproject/sdnip/PeerConnectivityManagerTest.java
+++ b/framework/src/onos/apps/sdnip/src/test/java/org/onosproject/sdnip/PeerConnectivityManagerTest.java
@@ -19,7 +19,6 @@ import com.google.common.collect.Sets;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
-import org.onlab.junit.TestUtils;
import org.onlab.junit.TestUtils.TestUtilsException;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IPv4;
@@ -28,13 +27,14 @@ import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.TpPort;
import org.onlab.packet.VlanId;
+import org.onosproject.TestApplicationId;
import org.onosproject.core.ApplicationId;
-import org.onosproject.net.config.NetworkConfigService;
import org.onosproject.incubator.net.intf.Interface;
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.NetworkConfigService;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.TrafficSelector;
@@ -42,8 +42,9 @@ import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.host.InterfaceIpAddress;
import org.onosproject.net.intent.AbstractIntentTest;
import org.onosproject.net.intent.Intent;
-import org.onosproject.net.intent.IntentService;
+import org.onosproject.net.intent.Key;
import org.onosproject.net.intent.PointToPointIntent;
+import org.onosproject.routing.IntentSynchronizationService;
import org.onosproject.routing.config.BgpConfig;
import org.onosproject.routing.config.BgpPeer;
import org.onosproject.routing.config.BgpSpeaker;
@@ -71,26 +72,15 @@ import static org.onosproject.sdnip.TestIntentServiceHelper.eqExceptId;
*/
public class PeerConnectivityManagerTest extends AbstractIntentTest {
- private static final ApplicationId APPID = new ApplicationId() {
- @Override
- public short id() {
- return 0;
- }
-
- @Override
- public String name() {
- return "foo";
- }
- };
+ private static final ApplicationId APPID = TestApplicationId.create("foo");
private static final ApplicationId CONFIG_APP_ID = APPID;
private PeerConnectivityManager peerConnectivityManager;
- private IntentSynchronizer intentSynchronizer;
+ private IntentSynchronizationService intentSynchronizer;
private RoutingConfigurationService routingConfig;
private InterfaceService interfaceService;
private NetworkConfigService networkConfigService;
- private IntentService intentService;
private Set<BgpConfig.BgpSpeakerConfig> bgpSpeakers;
private Map<String, Interface> interfaces;
@@ -98,8 +88,6 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest {
private BgpConfig bgpConfig;
- private Map<String, Interface> configuredInterfaces;
- private Map<IpAddress, BgpPeer> configuredPeers;
private List<PointToPointIntent> intentList;
private final String dpid1 = "00:00:00:00:00:00:00:01";
@@ -136,7 +124,7 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest {
// These will set expectations on routingConfig and interfaceService
bgpSpeakers = setUpBgpSpeakers();
interfaces = Collections.unmodifiableMap(setUpInterfaces());
- peers = Collections.unmodifiableMap(setUpPeers());
+ peers = setUpPeers();
initPeerConnectivity();
intentList = setUpIntentList();
@@ -169,11 +157,11 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest {
* Sets up logical interfaces, which emulate the configured interfaces
* in SDN-IP application.
*
- * @return configured interfaces as a MAP from Interface name to Interface
+ * @return configured interfaces as a map from interface name to Interface
*/
private Map<String, Interface> setUpInterfaces() {
- configuredInterfaces = new HashMap<>();
+ Map<String, Interface> configuredInterfaces = new HashMap<>();
String interfaceSw1Eth1 = "s1-eth1";
InterfaceIpAddress ia1 =
@@ -242,7 +230,7 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest {
*/
private Map<IpAddress, BgpPeer> setUpPeers() {
- configuredPeers = new HashMap<>();
+ Map<IpAddress, BgpPeer> configuredPeers = new HashMap<>();
String peerSw1Eth1 = "192.168.10.1";
configuredPeers.put(IpAddress.valueOf(peerSw1Eth1),
@@ -266,14 +254,12 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest {
* @return point to point intent list
*/
private List<PointToPointIntent> setUpIntentList() {
-
intentList = new ArrayList<>();
setUpBgpIntents();
setUpIcmpIntents();
return intentList;
-
}
/**
@@ -306,8 +292,12 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest {
builder.matchTcpDst(TpPort.tpPort(dstTcpPort));
}
+ Key key = Key.of(srcPrefix.split("/")[0] + "-" + dstPrefix.split("/")[0]
+ + "-" + ((srcTcpPort == null) ? "dst" : "src"), APPID);
+
PointToPointIntent intent = PointToPointIntent.builder()
.appId(APPID)
+ .key(key)
.selector(builder.build())
.treatment(noTreatment)
.ingressPoint(srcConnectPoint)
@@ -392,8 +382,12 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest {
.matchIPDst(IpPrefix.valueOf(dstPrefix))
.build();
+ Key key = Key.of(srcPrefix.split("/")[0] + "-" + dstPrefix.split("/")[0]
+ + "-" + "icmp", APPID);
+
PointToPointIntent intent = PointToPointIntent.builder()
.appId(APPID)
+ .key(key)
.selector(selector)
.treatment(noTreatment)
.ingressPoint(srcConnectPoint)
@@ -434,19 +428,14 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest {
expect(routingConfig.getBgpPeers()).andReturn(peers).anyTimes();
expect(bgpConfig.bgpSpeakers()).andReturn(bgpSpeakers).anyTimes();
replay(bgpConfig);
- expect(networkConfigService.getConfig(APPID, BgpConfig.class)).andReturn(bgpConfig).anyTimes();
+ expect(networkConfigService.getConfig(APPID, BgpConfig.class))
+ .andReturn(bgpConfig).anyTimes();
replay(networkConfigService);
replay(routingConfig);
replay(interfaceService);
- intentService = createMock(IntentService.class);
- replay(intentService);
-
- intentSynchronizer = new IntentSynchronizer(APPID, intentService,
- null, routingConfig,
- interfaceService);
- intentSynchronizer.leaderChanged(true);
- TestUtils.setField(intentSynchronizer, "isActivatedLeader", true);
+ intentSynchronizer = createMock(IntentSynchronizationService.class);
+ replay(intentSynchronizer);
peerConnectivityManager =
new PeerConnectivityManager(APPID, intentSynchronizer,
@@ -464,20 +453,18 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest {
*/
@Test
public void testConnectionSetup() {
-
- reset(intentService);
+ reset(intentSynchronizer);
// Setup the expected intents
for (Intent intent : intentList) {
- intentService.submit(eqExceptId(intent));
+ intentSynchronizer.submit(eqExceptId(intent));
}
- replay(intentService);
+ replay(intentSynchronizer);
// Running the interface to be tested.
peerConnectivityManager.start();
- verify(intentService);
-
+ verify(intentSynchronizer);
}
/**
@@ -488,7 +475,7 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest {
reset(interfaceService);
expect(interfaceService.getInterfaces()).andReturn(
- Sets.<Interface>newHashSet()).anyTimes();
+ Sets.newHashSet()).anyTimes();
expect(interfaceService.getInterfacesByPort(s2Eth1))
.andReturn(Collections.emptySet()).anyTimes();
expect(interfaceService.getInterfacesByPort(s1Eth1))
@@ -508,10 +495,10 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest {
replay(interfaceService);
- reset(intentService);
- replay(intentService);
+ reset(intentSynchronizer);
+ replay(intentSynchronizer);
peerConnectivityManager.start();
- verify(intentService);
+ verify(intentSynchronizer);
}
/**
@@ -527,10 +514,10 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest {
expect(routingConfig.getBgpPeers()).andReturn(peers).anyTimes();
replay(routingConfig);
- reset(intentService);
- replay(intentService);
+ reset(intentSynchronizer);
+ replay(intentSynchronizer);
peerConnectivityManager.start();
- verify(intentService);
+ verify(intentSynchronizer);
}
/**
@@ -540,7 +527,7 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest {
@Test
public void testNoPeerInterface() {
String peerSw100Eth1 = "192.168.200.1";
- configuredPeers.put(IpAddress.valueOf(peerSw100Eth1),
+ peers.put(IpAddress.valueOf(peerSw100Eth1),
new BgpPeer("00:00:00:00:00:00:01:00", 1, peerSw100Eth1));
testConnectionSetup();
}
diff --git a/framework/src/onos/apps/sdnip/src/test/java/org/onosproject/sdnip/SdnIpFibTest.java b/framework/src/onos/apps/sdnip/src/test/java/org/onosproject/sdnip/SdnIpFibTest.java
new file mode 100644
index 00000000..5466d520
--- /dev/null
+++ b/framework/src/onos/apps/sdnip/src/test/java/org/onosproject/sdnip/SdnIpFibTest.java
@@ -0,0 +1,417 @@
+/*
+ * 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.sdnip;
+
+import com.google.common.collect.Sets;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.Ip4Prefix;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
+import org.onosproject.TestApplicationId;
+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.DeviceId;
+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.host.InterfaceIpAddress;
+import org.onosproject.net.intent.AbstractIntentTest;
+import org.onosproject.net.intent.Key;
+import org.onosproject.net.intent.MultiPointToSinglePointIntent;
+import org.onosproject.routing.FibEntry;
+import org.onosproject.routing.FibUpdate;
+import org.onosproject.routing.IntentSynchronizationService;
+import org.onosproject.routing.config.BgpPeer;
+import org.onosproject.routing.config.RoutingConfigurationService;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.reset;
+import static org.easymock.EasyMock.verify;
+import static org.onosproject.sdnip.TestIntentServiceHelper.eqExceptId;
+
+/**
+ * Unit tests for SdnIpFib.
+ */
+public class SdnIpFibTest extends AbstractIntentTest {
+
+ private RoutingConfigurationService routingConfig;
+ private InterfaceService interfaceService;
+
+ private static final ConnectPoint SW1_ETH1 = new ConnectPoint(
+ DeviceId.deviceId("of:0000000000000001"),
+ PortNumber.portNumber(1));
+
+ private static final ConnectPoint SW2_ETH1 = new ConnectPoint(
+ DeviceId.deviceId("of:0000000000000002"),
+ PortNumber.portNumber(1));
+
+ private static final ConnectPoint SW3_ETH1 = new ConnectPoint(
+ DeviceId.deviceId("of:0000000000000003"),
+ PortNumber.portNumber(1));
+
+ private static final ConnectPoint SW4_ETH1 = new ConnectPoint(
+ DeviceId.deviceId("of:0000000000000004"),
+ PortNumber.portNumber(1));
+
+ private SdnIpFib sdnipFib;
+ private IntentSynchronizationService intentSynchronizer;
+ private final Set<Interface> interfaces = Sets.newHashSet();
+
+ private static final ApplicationId APPID = TestApplicationId.create("SDNIP");
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+
+ routingConfig = createMock(RoutingConfigurationService.class);
+ interfaceService = createMock(InterfaceService.class);
+
+ // These will set expectations on routingConfig and interfaceService
+ setUpInterfaceService();
+ setUpBgpPeers();
+
+ replay(routingConfig);
+ replay(interfaceService);
+
+ intentSynchronizer = createMock(IntentSynchronizationService.class);
+
+ sdnipFib = new SdnIpFib(APPID, interfaceService, intentSynchronizer);
+ }
+
+ /**
+ * Sets up BGP peers in external networks.
+ */
+ private void setUpBgpPeers() {
+
+ Map<IpAddress, BgpPeer> peers = new HashMap<>();
+
+ String peerSw1Eth1 = "192.168.10.1";
+ peers.put(IpAddress.valueOf(peerSw1Eth1),
+ new BgpPeer("00:00:00:00:00:00:00:01", 1, peerSw1Eth1));
+
+ // Two BGP peers are connected to switch 2 port 1.
+ String peer1Sw2Eth1 = "192.168.20.1";
+ peers.put(IpAddress.valueOf(peer1Sw2Eth1),
+ new BgpPeer("00:00:00:00:00:00:00:02", 1, peer1Sw2Eth1));
+
+ String peer2Sw2Eth1 = "192.168.20.2";
+ peers.put(IpAddress.valueOf(peer2Sw2Eth1),
+ new BgpPeer("00:00:00:00:00:00:00:02", 1, peer2Sw2Eth1));
+
+ String peer1Sw4Eth1 = "192.168.40.1";
+ peers.put(IpAddress.valueOf(peer1Sw4Eth1),
+ new BgpPeer("00:00:00:00:00:00:00:04", 1, peer1Sw4Eth1));
+
+ expect(routingConfig.getBgpPeers()).andReturn(peers).anyTimes();
+ }
+
+ /**
+ * Sets up InterfaceService.
+ */
+ private void setUpInterfaceService() {
+ Set<InterfaceIpAddress> interfaceIpAddresses1 = Sets.newHashSet();
+ interfaceIpAddresses1.add(new InterfaceIpAddress(
+ IpAddress.valueOf("192.168.10.101"),
+ IpPrefix.valueOf("192.168.10.0/24")));
+ Interface sw1Eth1 = new Interface(SW1_ETH1,
+ interfaceIpAddresses1, MacAddress.valueOf("00:00:00:00:00:01"),
+ VlanId.NONE);
+ interfaces.add(sw1Eth1);
+
+ Set<InterfaceIpAddress> interfaceIpAddresses2 = Sets.newHashSet();
+ interfaceIpAddresses2.add(
+ new InterfaceIpAddress(IpAddress.valueOf("192.168.20.101"),
+ IpPrefix.valueOf("192.168.20.0/24")));
+ Interface sw2Eth1 = new Interface(SW2_ETH1,
+ interfaceIpAddresses2, MacAddress.valueOf("00:00:00:00:00:02"),
+ VlanId.NONE);
+ interfaces.add(sw2Eth1);
+
+ Set<InterfaceIpAddress> interfaceIpAddresses3 = Sets.newHashSet();
+ interfaceIpAddresses3.add(
+ new InterfaceIpAddress(IpAddress.valueOf("192.168.30.101"),
+ IpPrefix.valueOf("192.168.30.0/24")));
+ Interface sw3Eth1 = new Interface(SW3_ETH1,
+ interfaceIpAddresses3, MacAddress.valueOf("00:00:00:00:00:03"),
+ VlanId.NONE);
+ interfaces.add(sw3Eth1);
+
+ InterfaceIpAddress interfaceIpAddress4 =
+ new InterfaceIpAddress(IpAddress.valueOf("192.168.40.101"),
+ IpPrefix.valueOf("192.168.40.0/24"));
+ Interface sw4Eth1 = new Interface(SW4_ETH1,
+ Sets.newHashSet(interfaceIpAddress4),
+ MacAddress.valueOf("00:00:00:00:00:04"),
+ VlanId.vlanId((short) 1));
+
+ expect(interfaceService.getInterfacesByPort(SW4_ETH1)).andReturn(
+ Collections.singleton(sw4Eth1)).anyTimes();
+ expect(interfaceService.getMatchingInterface(Ip4Address.valueOf("192.168.40.1")))
+ .andReturn(sw4Eth1).anyTimes();
+
+ interfaces.add(sw4Eth1);
+
+ expect(interfaceService.getInterfacesByPort(SW1_ETH1)).andReturn(
+ Collections.singleton(sw1Eth1)).anyTimes();
+ expect(interfaceService.getMatchingInterface(Ip4Address.valueOf("192.168.10.1")))
+ .andReturn(sw1Eth1).anyTimes();
+ expect(interfaceService.getInterfacesByPort(SW2_ETH1)).andReturn(
+ Collections.singleton(sw2Eth1)).anyTimes();
+ expect(interfaceService.getMatchingInterface(Ip4Address.valueOf("192.168.20.1")))
+ .andReturn(sw2Eth1).anyTimes();
+ expect(interfaceService.getInterfacesByPort(SW3_ETH1)).andReturn(
+ Collections.singleton(sw3Eth1)).anyTimes();
+ expect(interfaceService.getMatchingInterface(Ip4Address.valueOf("192.168.30.1")))
+ .andReturn(sw3Eth1).anyTimes();
+ expect(interfaceService.getInterfaces()).andReturn(interfaces).anyTimes();
+ }
+
+ /**
+ * Tests adding a FIB entry to the IntentSynchronizer.
+ *
+ * We verify that the synchronizer records the correct state and that the
+ * correct intent is submitted to the IntentService.
+ */
+ @Test
+ public void testFibAdd() {
+ IpPrefix prefix = Ip4Prefix.valueOf("1.1.1.0/24");
+ FibEntry fibEntry = new FibEntry(prefix,
+ Ip4Address.valueOf("192.168.10.1"),
+ MacAddress.valueOf("00:00:00:00:00:01"));
+
+ // Construct a MultiPointToSinglePointIntent intent
+ TrafficSelector.Builder selectorBuilder =
+ DefaultTrafficSelector.builder();
+ selectorBuilder.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(
+ fibEntry.prefix());
+
+ TrafficTreatment.Builder treatmentBuilder =
+ DefaultTrafficTreatment.builder();
+ treatmentBuilder.setEthDst(MacAddress.valueOf("00:00:00:00:00:01"));
+
+ Set<ConnectPoint> ingressPoints = new HashSet<>();
+ ingressPoints.add(SW2_ETH1);
+ ingressPoints.add(SW3_ETH1);
+ ingressPoints.add(SW4_ETH1);
+
+ MultiPointToSinglePointIntent intent =
+ MultiPointToSinglePointIntent.builder()
+ .appId(APPID)
+ .key(Key.of(prefix.toString(), APPID))
+ .selector(selectorBuilder.build())
+ .treatment(treatmentBuilder.build())
+ .ingressPoints(ingressPoints)
+ .egressPoint(SW1_ETH1)
+ .constraints(SdnIpFib.CONSTRAINTS)
+ .build();
+
+ // Setup the expected intents
+ intentSynchronizer.submit(eqExceptId(intent));
+ replay(intentSynchronizer);
+
+ // Send in the UPDATE FibUpdate
+ FibUpdate fibUpdate = new FibUpdate(FibUpdate.Type.UPDATE, fibEntry);
+ sdnipFib.update(Collections.singleton(fibUpdate), Collections.emptyList());
+
+ verify(intentSynchronizer);
+ }
+
+ /**
+ * Tests adding a FIB entry with to a next hop in a VLAN.
+ *
+ * We verify that the synchronizer records the correct state and that the
+ * correct intent is submitted to the IntentService.
+ */
+ @Test
+ public void testFibAddWithVlan() {
+ IpPrefix prefix = Ip4Prefix.valueOf("3.3.3.0/24");
+ FibEntry fibEntry = new FibEntry(prefix,
+ Ip4Address.valueOf("192.168.40.1"),
+ MacAddress.valueOf("00:00:00:00:00:04"));
+
+ // Construct a MultiPointToSinglePointIntent intent
+ TrafficSelector.Builder selectorBuilder =
+ DefaultTrafficSelector.builder();
+ selectorBuilder.matchEthType(Ethernet.TYPE_IPV4)
+ .matchIPDst(fibEntry.prefix())
+ .matchVlanId(VlanId.ANY);
+
+ TrafficTreatment.Builder treatmentBuilder =
+ DefaultTrafficTreatment.builder();
+ treatmentBuilder.setEthDst(MacAddress.valueOf("00:00:00:00:00:04"))
+ .setVlanId(VlanId.vlanId((short) 1));
+
+ Set<ConnectPoint> ingressPoints = new HashSet<>();
+ ingressPoints.add(SW1_ETH1);
+ ingressPoints.add(SW2_ETH1);
+ ingressPoints.add(SW3_ETH1);
+
+ MultiPointToSinglePointIntent intent =
+ MultiPointToSinglePointIntent.builder()
+ .appId(APPID)
+ .key(Key.of(prefix.toString(), APPID))
+ .selector(selectorBuilder.build())
+ .treatment(treatmentBuilder.build())
+ .ingressPoints(ingressPoints)
+ .egressPoint(SW4_ETH1)
+ .constraints(SdnIpFib.CONSTRAINTS)
+ .build();
+
+ // Setup the expected intents
+ intentSynchronizer.submit(eqExceptId(intent));
+
+ replay(intentSynchronizer);
+
+ // Send in the UPDATE FibUpdate
+ FibUpdate fibUpdate = new FibUpdate(FibUpdate.Type.UPDATE, fibEntry);
+ sdnipFib.update(Collections.singleton(fibUpdate), Collections.emptyList());
+
+ verify(intentSynchronizer);
+ }
+
+ /**
+ * Tests updating a FIB entry.
+ *
+ * We verify that the synchronizer records the correct state and that the
+ * correct intent is submitted to the IntentService.
+ */
+ @Test
+ public void testFibUpdate() {
+ // Firstly add a route
+ testFibAdd();
+
+ IpPrefix prefix = Ip4Prefix.valueOf("1.1.1.0/24");
+
+ // Start to construct a new route entry and new intent
+ FibEntry fibEntryUpdate = new FibEntry(prefix,
+ Ip4Address.valueOf("192.168.20.1"),
+ MacAddress.valueOf("00:00:00:00:00:02"));
+
+ // Construct a new MultiPointToSinglePointIntent intent
+ TrafficSelector.Builder selectorBuilderNew =
+ DefaultTrafficSelector.builder();
+ selectorBuilderNew.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(
+ fibEntryUpdate.prefix());
+
+ TrafficTreatment.Builder treatmentBuilderNew =
+ DefaultTrafficTreatment.builder();
+ treatmentBuilderNew.setEthDst(MacAddress.valueOf("00:00:00:00:00:02"));
+
+ Set<ConnectPoint> ingressPointsNew = new HashSet<>();
+ ingressPointsNew.add(SW1_ETH1);
+ ingressPointsNew.add(SW3_ETH1);
+ ingressPointsNew.add(SW4_ETH1);
+
+ MultiPointToSinglePointIntent intentNew =
+ MultiPointToSinglePointIntent.builder()
+ .appId(APPID)
+ .key(Key.of(prefix.toString(), APPID))
+ .selector(selectorBuilderNew.build())
+ .treatment(treatmentBuilderNew.build())
+ .ingressPoints(ingressPointsNew)
+ .egressPoint(SW2_ETH1)
+ .constraints(SdnIpFib.CONSTRAINTS)
+ .build();
+
+ // Set up test expectation
+ reset(intentSynchronizer);
+
+ // Setup the expected intents
+ intentSynchronizer.submit(eqExceptId(intentNew));
+ replay(intentSynchronizer);
+
+ // Send in the UPDATE FibUpdate
+ FibUpdate fibUpdate = new FibUpdate(FibUpdate.Type.UPDATE,
+ fibEntryUpdate);
+ sdnipFib.update(Collections.singletonList(fibUpdate),
+ Collections.emptyList());
+
+ verify(intentSynchronizer);
+ }
+
+ /**
+ * Tests deleting a FIB entry.
+ *
+ * We verify that the synchronizer records the correct state and that the
+ * correct intent is withdrawn from the IntentService.
+ */
+ @Test
+ public void testFibDelete() {
+ // Firstly add a route
+ testFibAdd();
+
+ IpPrefix prefix = Ip4Prefix.valueOf("1.1.1.0/24");
+
+ // Construct the existing route entry
+ FibEntry fibEntry = new FibEntry(prefix, null, null);
+
+ // Construct the existing MultiPointToSinglePoint intent
+ TrafficSelector.Builder selectorBuilder =
+ DefaultTrafficSelector.builder();
+ selectorBuilder.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(
+ fibEntry.prefix());
+
+ TrafficTreatment.Builder treatmentBuilder =
+ DefaultTrafficTreatment.builder();
+ treatmentBuilder.setEthDst(MacAddress.valueOf("00:00:00:00:00:01"));
+
+ Set<ConnectPoint> ingressPoints = new HashSet<>();
+ ingressPoints.add(SW2_ETH1);
+ ingressPoints.add(SW3_ETH1);
+ ingressPoints.add(SW4_ETH1);
+
+ MultiPointToSinglePointIntent addedIntent =
+ MultiPointToSinglePointIntent.builder()
+ .appId(APPID)
+ .key(Key.of(prefix.toString(), APPID))
+ .selector(selectorBuilder.build())
+ .treatment(treatmentBuilder.build())
+ .ingressPoints(ingressPoints)
+ .egressPoint(SW1_ETH1)
+ .constraints(SdnIpFib.CONSTRAINTS)
+ .build();
+
+ // Set up expectation
+ reset(intentSynchronizer);
+ // Setup the expected intents
+ intentSynchronizer.withdraw(eqExceptId(addedIntent));
+ replay(intentSynchronizer);
+
+ // Send in the DELETE FibUpdate
+ FibUpdate fibUpdate = new FibUpdate(FibUpdate.Type.DELETE, fibEntry);
+ sdnipFib.update(Collections.emptyList(), Collections.singletonList(fibUpdate));
+
+ verify(intentSynchronizer);
+ }
+}
diff --git a/framework/src/onos/apps/sdnip/src/test/java/org/onosproject/sdnip/TestIntentServiceHelper.java b/framework/src/onos/apps/sdnip/src/test/java/org/onosproject/sdnip/TestIntentServiceHelper.java
index 69b18aa9..7f825e81 100644
--- a/framework/src/onos/apps/sdnip/src/test/java/org/onosproject/sdnip/TestIntentServiceHelper.java
+++ b/framework/src/onos/apps/sdnip/src/test/java/org/onosproject/sdnip/TestIntentServiceHelper.java
@@ -17,7 +17,6 @@ package org.onosproject.sdnip;
import org.easymock.IArgumentMatcher;
import org.onosproject.net.intent.Intent;
-import org.onosproject.sdnip.IntentSynchronizer.IntentKey;
import static org.easymock.EasyMock.reportMatcher;
@@ -53,8 +52,6 @@ public final class TestIntentServiceHelper {
* the solution is to use an EasyMock matcher that verifies that all the
* value properties of the provided intent match the expected values, but
* ignores the intent ID when testing equality.
- *
- * FIXME this currently does not take key into account
*/
private static final class IdAgnosticIntentMatcher implements
IArgumentMatcher {
@@ -86,9 +83,7 @@ public final class TestIntentServiceHelper {
Intent providedIntent = (Intent) object;
providedString = providedIntent.toString();
- IntentKey thisIntentKey = new IntentKey(intent);
- IntentKey providedIntentKey = new IntentKey(providedIntent);
- return thisIntentKey.equals(providedIntentKey);
+ return IntentUtils.equals(intent, providedIntent);
}
}
diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java
index ef9d444a..8fdf81a2 100644
--- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java
+++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 Open Networking Laboratory
+ * 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.
@@ -18,24 +18,26 @@ package org.onosproject.segmentrouting;
import com.google.common.collect.Lists;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
-import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
+import org.onosproject.incubator.net.config.basics.ConfigException;
+import org.onosproject.incubator.net.config.basics.InterfaceConfig;
+import org.onosproject.incubator.net.intf.Interface;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.config.NetworkConfigRegistry;
+import org.onosproject.net.host.InterfaceIpAddress;
+import org.onosproject.segmentrouting.config.SegmentRoutingConfig;
+import org.onosproject.segmentrouting.config.SegmentRoutingConfig.AdjacencySid;
import org.onosproject.segmentrouting.grouphandler.DeviceProperties;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
-import org.onosproject.segmentrouting.config.NetworkConfig.SwitchConfig;
-import org.onosproject.segmentrouting.config.NetworkConfigManager;
-import org.onosproject.segmentrouting.config.SegmentRouterConfig;
-import org.onosproject.segmentrouting.config.SegmentRouterConfig.Subnet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import static com.google.common.base.Preconditions.checkNotNull;
-
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* Segment Routing configuration component that reads the
@@ -50,7 +52,6 @@ public class DeviceConfiguration implements DeviceProperties {
.getLogger(DeviceConfiguration.class);
private final List<Integer> allSegmentIds = new ArrayList<>();
private final HashMap<DeviceId, SegmentRouterInfo> deviceConfigMap = new HashMap<>();
- private final NetworkConfigManager configService;
private class SegmentRouterInfo {
int nodeSid;
@@ -60,48 +61,60 @@ public class DeviceConfiguration implements DeviceProperties {
boolean isEdge;
HashMap<PortNumber, Ip4Address> gatewayIps;
HashMap<PortNumber, Ip4Prefix> subnets;
- List<SegmentRouterConfig.AdjacencySid> adjacencySids;
+ List<AdjacencySid> adjacencySids;
}
/**
* Constructor. Reads all the configuration for all devices of type
* Segment Router and organizes into various maps for easier access.
- *
- * @param configService handle to network configuration manager
- * component from where the relevant configuration is retrieved.
*/
- public DeviceConfiguration(NetworkConfigManager configService) {
- this.configService = checkNotNull(configService);
- List<SwitchConfig> allSwitchCfg =
- this.configService.getConfiguredAllowedSwitches();
- for (SwitchConfig cfg : allSwitchCfg) {
- if (!(cfg instanceof SegmentRouterConfig)) {
- continue;
- }
+ public DeviceConfiguration(NetworkConfigRegistry cfgService) {
+ // Read config from device subject, excluding gatewayIps and subnets.
+ Set<DeviceId> deviceSubjects =
+ cfgService.getSubjects(DeviceId.class, SegmentRoutingConfig.class);
+ deviceSubjects.forEach(subject -> {
+ SegmentRoutingConfig config =
+ cfgService.getConfig(subject, SegmentRoutingConfig.class);
SegmentRouterInfo info = new SegmentRouterInfo();
- info.nodeSid = ((SegmentRouterConfig) cfg).getNodeSid();
- info.deviceId = ((SegmentRouterConfig) cfg).getDpid();
- info.mac = MacAddress.valueOf(((
- SegmentRouterConfig) cfg).getRouterMac());
- String routerIp = ((SegmentRouterConfig) cfg).getRouterIp();
- Ip4Prefix prefix = checkNotNull(IpPrefix.valueOf(routerIp).getIp4Prefix());
- info.ip = prefix.address();
- info.isEdge = ((SegmentRouterConfig) cfg).isEdgeRouter();
- info.subnets = new HashMap<>();
+ info.deviceId = subject;
+ info.nodeSid = config.getSid();
+ info.ip = config.getIp();
+ info.mac = config.getMac();
+ info.isEdge = config.isEdgeRouter();
+ info.adjacencySids = config.getAdjacencySids();
info.gatewayIps = new HashMap<>();
- for (Subnet s: ((SegmentRouterConfig) cfg).getSubnets()) {
- info.subnets.put(PortNumber.portNumber(s.getPortNo()),
- Ip4Prefix.valueOf(s.getSubnetIp()));
- String gatewayIp = s.getSubnetIp().
- substring(0, s.getSubnetIp().indexOf('/'));
- info.gatewayIps.put(PortNumber.portNumber(s.getPortNo()),
- Ip4Address.valueOf(gatewayIp));
- }
- info.adjacencySids = ((SegmentRouterConfig) cfg).getAdjacencySids();
+ info.subnets = new HashMap<>();
+
this.deviceConfigMap.put(info.deviceId, info);
this.allSegmentIds.add(info.nodeSid);
-
- }
+ });
+
+ // Read gatewayIps and subnets from port subject.
+ Set<ConnectPoint> portSubjects =
+ cfgService.getSubjects(ConnectPoint.class, InterfaceConfig.class);
+ portSubjects.forEach(subject -> {
+ InterfaceConfig config =
+ cfgService.getConfig(subject, InterfaceConfig.class);
+ Set<Interface> networkInterfaces;
+ try {
+ networkInterfaces = config.getInterfaces();
+ } catch (ConfigException e) {
+ log.error("Error loading port configuration");
+ return;
+ }
+ networkInterfaces.forEach(networkInterface -> {
+ DeviceId dpid = networkInterface.connectPoint().deviceId();
+ PortNumber port = networkInterface.connectPoint().port();
+ SegmentRouterInfo info = this.deviceConfigMap.get(dpid);
+
+ Set<InterfaceIpAddress> interfaceAddresses = networkInterface.ipAddresses();
+ interfaceAddresses.forEach(interfaceAddress -> {
+ info.gatewayIps.put(port, interfaceAddress.ipAddress().getIp4Address());
+ info.subnets.put(port, interfaceAddress.subnetAddress().getIp4Prefix());
+ });
+ });
+
+ });
}
/**
@@ -379,8 +392,8 @@ public class DeviceConfiguration implements DeviceProperties {
*/
public List<Integer> getPortsForAdjacencySid(DeviceId deviceId, int sid) {
if (deviceConfigMap.get(deviceId) != null) {
- for (SegmentRouterConfig.AdjacencySid asid : deviceConfigMap.get(deviceId).adjacencySids) {
- if (asid.getAdjSid() == sid) {
+ for (AdjacencySid asid : deviceConfigMap.get(deviceId).adjacencySids) {
+ if (asid.getAsid() == sid) {
return asid.getPorts();
}
}
@@ -402,9 +415,9 @@ public class DeviceConfiguration implements DeviceProperties {
if (deviceConfigMap.get(deviceId).adjacencySids.isEmpty()) {
return false;
} else {
- for (SegmentRouterConfig.AdjacencySid asid:
+ for (AdjacencySid asid:
deviceConfigMap.get(deviceId).adjacencySids) {
- if (asid.getAdjSid() == sid) {
+ if (asid.getAsid() == sid) {
return true;
}
}
@@ -414,4 +427,4 @@ public class DeviceConfiguration implements DeviceProperties {
return false;
}
-}
+} \ No newline at end of file
diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java
index 0f8fa59d..f65f03e0 100644
--- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java
+++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java
@@ -111,10 +111,10 @@ public class IcmpHandler {
icmpReplyIpv4.setChecksum((short) 0);
ICMP icmpReply = new ICMP();
+ icmpReply.setPayload(((ICMP) icmpRequestIpv4.getPayload()).getPayload());
icmpReply.setIcmpType(ICMP.TYPE_ECHO_REPLY);
icmpReply.setIcmpCode(ICMP.SUBTYPE_ECHO_REPLY);
icmpReply.setChecksum((short) 0);
-
icmpReplyIpv4.setPayload(icmpReply);
icmpReplyEth.setPayload(icmpReplyIpv4);
diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
index 874faabf..05663129 100644
--- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
+++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
@@ -27,6 +27,12 @@ import org.onlab.util.KryoNamespace;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.event.Event;
+import org.onosproject.net.config.ConfigFactory;
+import org.onosproject.net.config.NetworkConfigEvent;
+import org.onosproject.net.config.NetworkConfigRegistry;
+import org.onosproject.net.config.NetworkConfigListener;
+import org.onosproject.net.config.basics.SubjectFactories;
+import org.onosproject.segmentrouting.config.SegmentRoutingConfig;
import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
import org.onosproject.segmentrouting.grouphandler.NeighborSet;
import org.onosproject.segmentrouting.grouphandler.NeighborSetNextObjectiveStoreKey;
@@ -50,7 +56,6 @@ 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.config.NetworkConfigManager;
import org.onosproject.store.service.EventuallyConsistentMap;
import org.onosproject.store.service.EventuallyConsistentMapBuilder;
import org.onosproject.store.service.StorageService;
@@ -133,7 +138,21 @@ public class SegmentRoutingManager implements SegmentRoutingService {
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected StorageService storageService;
- private NetworkConfigManager networkConfigService = new NetworkConfigManager();;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected NetworkConfigRegistry cfgService;
+
+ private final InternalConfigListener cfgListener =
+ new InternalConfigListener(this);
+
+ private final ConfigFactory cfgFactory =
+ new ConfigFactory(SubjectFactories.DEVICE_SUBJECT_FACTORY,
+ SegmentRoutingConfig.class,
+ "segmentrouting") {
+ @Override
+ public SegmentRoutingConfig createConfig() {
+ return new SegmentRoutingConfig();
+ }
+ };
private Object threadSchedulerLock = new Object();
private static int numOfEventsQueued = 0;
@@ -192,44 +211,17 @@ public class SegmentRoutingManager implements SegmentRoutingService {
.withTimestampProvider((k, v) -> new WallClockTimestamp())
.build();
- networkConfigService.init();
- deviceConfiguration = new DeviceConfiguration(networkConfigService);
- arpHandler = new ArpHandler(this);
- icmpHandler = new IcmpHandler(this);
- ipHandler = new IpHandler(this);
- routingRulePopulator = new RoutingRulePopulator(this);
- defaultRoutingHandler = new DefaultRoutingHandler(this);
- tunnelHandler = new TunnelHandler(linkService, deviceConfiguration,
- groupHandlerMap, tunnelStore);
- policyHandler = new PolicyHandler(appId, deviceConfiguration,
- flowObjectiveService, tunnelHandler, policyStore);
-
- packetService.addProcessor(processor, PacketProcessor.director(2));
- linkService.addListener(new InternalLinkListener());
- deviceService.addListener(new InternalDeviceListener());
-
- 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
- DefaultGroupHandler groupHandler = DefaultGroupHandler
- .createGroupHandler(device.id(), appId,
- deviceConfiguration, linkService,
- flowObjectiveService,
- nsNextObjStore);
- groupHandlerMap.put(device.id(), groupHandler);
- defaultRoutingHandler.populateTtpRules(device.id());
- }
+ cfgService.addListener(cfgListener);
+ cfgService.registerConfigFactory(cfgFactory);
- defaultRoutingHandler.startPopulationProcess();
log.info("Started");
-
}
@Deactivate
protected void deactivate() {
+ cfgService.removeListener(cfgListener);
+ cfgService.unregisterConfigFactory(cfgFactory);
+
packetService.removeProcessor(processor);
processor = null;
log.info("Stopped");
@@ -512,6 +504,59 @@ public class SegmentRoutingManager implements SegmentRoutingService {
}
}
+ private class InternalConfigListener implements NetworkConfigListener {
+ SegmentRoutingManager segmentRoutingManager;
+
+ public InternalConfigListener(SegmentRoutingManager srMgr) {
+ this.segmentRoutingManager = srMgr;
+ }
+ public void configureNetwork() {
+ deviceConfiguration = new DeviceConfiguration(segmentRoutingManager.cfgService);
+
+ arpHandler = new ArpHandler(segmentRoutingManager);
+ icmpHandler = new IcmpHandler(segmentRoutingManager);
+ ipHandler = new IpHandler(segmentRoutingManager);
+ routingRulePopulator = new RoutingRulePopulator(segmentRoutingManager);
+ defaultRoutingHandler = new DefaultRoutingHandler(segmentRoutingManager);
+
+ tunnelHandler = new TunnelHandler(linkService, deviceConfiguration,
+ groupHandlerMap, tunnelStore);
+ policyHandler = new PolicyHandler(appId, deviceConfiguration,
+ flowObjectiveService,
+ tunnelHandler, policyStore);
+
+ packetService.addProcessor(processor, PacketProcessor.director(2));
+ linkService.addListener(new InternalLinkListener());
+ deviceService.addListener(new InternalDeviceListener());
+
+ 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
+ DefaultGroupHandler groupHandler = DefaultGroupHandler
+ .createGroupHandler(device.id(), appId,
+ deviceConfiguration, linkService,
+ flowObjectiveService,
+ nsNextObjStore);
+ groupHandlerMap.put(device.id(), groupHandler);
+ defaultRoutingHandler.populateTtpRules(device.id());
+ }
+ defaultRoutingHandler.startPopulationProcess();
+ }
+
+ @Override
+ public void event(NetworkConfigEvent event) {
+ if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
+ event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
+ event.configClass().equals(SegmentRoutingConfig.class)) {
+ log.info("Network configuration change detected. (Re)Configuring...");
+ configureNetwork();
+ return;
+ }
+ }
+ }
}
diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/SegmentRoutingConfig.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/SegmentRoutingConfig.java
new file mode 100644
index 00000000..6dc3f0db
--- /dev/null
+++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/SegmentRoutingConfig.java
@@ -0,0 +1,128 @@
+/*
+ * 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.config;
+
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.MacAddress;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.config.Config;
+import org.onosproject.net.config.basics.BasicElementConfig;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * Configuration object for Segment Routing Application.
+ */
+public class SegmentRoutingConfig extends Config<DeviceId> {
+ private static final String NAME = "name";
+ private static final String IP = "routerIp";
+ private static final String MAC = "routerMac";
+ private static final String SID = "nodeSid";
+ private static final String EDGE = "isEdgeRouter";
+ private static final String ADJSID = "adjacencySids";
+
+ public Optional<String> getName() {
+ String name = get(NAME, null);
+ return name != null ? Optional.of(name) : Optional.empty();
+ }
+
+ public BasicElementConfig setName(String name) {
+ return (BasicElementConfig) setOrClear(NAME, name);
+ }
+
+ public Ip4Address getIp() {
+ String ip = get(IP, null);
+ return ip != null ? Ip4Address.valueOf(ip) : null;
+ }
+
+ public BasicElementConfig setIp(String ip) {
+ return (BasicElementConfig) setOrClear(IP, ip);
+ }
+
+ public MacAddress getMac() {
+ String mac = get(MAC, null);
+ return mac != null ? MacAddress.valueOf(mac) : null;
+ }
+
+ public BasicElementConfig setMac(String mac) {
+ return (BasicElementConfig) setOrClear(MAC, mac);
+ }
+
+ public int getSid() {
+ return get(SID, -1);
+ }
+
+ public BasicElementConfig setSid(int sid) {
+ return (BasicElementConfig) setOrClear(SID, sid);
+ }
+
+ public boolean isEdgeRouter() {
+ return get(EDGE, false);
+ }
+
+ public BasicElementConfig setEdgeRouter(boolean isEdgeRouter) {
+ return (BasicElementConfig) setOrClear(EDGE, isEdgeRouter);
+ }
+
+ public List<AdjacencySid> getAdjacencySids() {
+ ArrayList<AdjacencySid> adjacencySids = new ArrayList<>();
+
+ if (!object.has(ADJSID)) {
+ return adjacencySids;
+ }
+
+ ArrayNode adjacencySidNodes = (ArrayNode) object.path(ADJSID);
+ adjacencySidNodes.forEach(adjacencySidNode -> {
+ int asid = adjacencySidNode.path(AdjacencySid.ASID).asInt();
+
+ ArrayList<Integer> ports = new ArrayList<Integer>();
+ ArrayNode portsNodes = (ArrayNode) adjacencySidNode.path(AdjacencySid.PORTS);
+ portsNodes.forEach(portNode -> {
+ ports.add(portNode.asInt());
+ });
+
+ AdjacencySid adjacencySid = new AdjacencySid(asid, ports);
+ adjacencySids.add(adjacencySid);
+ });
+
+ return adjacencySids;
+ }
+
+ public class AdjacencySid {
+ private static final String ASID = "adjSid";
+ private static final String PORTS = "ports";
+
+ int asid;
+ List<Integer> ports;
+
+ public AdjacencySid(int asid, List<Integer> ports) {
+ this.asid = asid;
+ this.ports = ports;
+ }
+
+ public int getAsid() {
+ return asid;
+ }
+
+ public List<Integer> getPorts() {
+ return ports;
+ }
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/package-info.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/package-info.java
index fdae9c9e..95f7e244 100644
--- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/package-info.java
+++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/package-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 Open Networking Laboratory
+ * 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.
diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DeviceProperties.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DeviceProperties.java
index 816ca7bc..497f5256 100644
--- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DeviceProperties.java
+++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DeviceProperties.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 Open Networking Laboratory
+ * 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.
diff --git a/framework/src/onos/apps/test/distributed-primitives/src/main/java/org/onosproject/distributedprimitives/cli/CounterTestIncrementCommand.java b/framework/src/onos/apps/test/distributed-primitives/src/main/java/org/onosproject/distributedprimitives/cli/CounterTestIncrementCommand.java
index 12c8140a..d93ad78f 100644
--- a/framework/src/onos/apps/test/distributed-primitives/src/main/java/org/onosproject/distributedprimitives/cli/CounterTestIncrementCommand.java
+++ b/framework/src/onos/apps/test/distributed-primitives/src/main/java/org/onosproject/distributedprimitives/cli/CounterTestIncrementCommand.java
@@ -92,7 +92,8 @@ public class CounterTestIncrementCommand extends AbstractShellCommand {
} catch (InterruptedException e) {
return;
} catch (ExecutionException | TimeoutException e) {
- e.printStackTrace();
+ print("Error executing command");
+ log.error("Error executing command counter-test-increment", e);
}
}
}
diff --git a/framework/src/onos/apps/test/intent-perf/src/main/java/org/onosproject/intentperf/IntentPerfInstaller.java b/framework/src/onos/apps/test/intent-perf/src/main/java/org/onosproject/intentperf/IntentPerfInstaller.java
index de9e9f21..ad3236e5 100644
--- a/framework/src/onos/apps/test/intent-perf/src/main/java/org/onosproject/intentperf/IntentPerfInstaller.java
+++ b/framework/src/onos/apps/test/intent-perf/src/main/java/org/onosproject/intentperf/IntentPerfInstaller.java
@@ -179,8 +179,8 @@ public class IntentPerfInstaller {
workers = Executors.newFixedThreadPool(DEFAULT_NUM_WORKERS, groupedThreads("onos/intent-perf", "worker-%d"));
// disable flow backups for testing
- configService.setProperty("org.onosproject.store.flow.impl.DistributedFlowRuleStore",
- "backupEnabled", "false");
+ configService.setProperty("org.onosproject.store.flow.impl.NewDistributedFlowRuleStore",
+ "backupEnabled", "true");
// TODO: replace with shared executor
messageHandlingExecutor = Executors.newSingleThreadExecutor(
diff --git a/framework/src/onos/apps/vtn/app/app.xml b/framework/src/onos/apps/vtn/app/app.xml
new file mode 100644
index 00000000..a0efd7f4
--- /dev/null
+++ b/framework/src/onos/apps/vtn/app/app.xml
@@ -0,0 +1,25 @@
+<?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.vtn" 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}/onos-app-vtn-mgr/${project.version}</artifact>
+ <artifact>mvn:${project.groupId}/onos-app-vtn-web/${project.version}</artifact>
+ <artifact>mvn:${project.groupId}/onos-app-vtn-rsc/${project.version}</artifact>
+</app>
diff --git a/framework/src/onos/apps/vtn/app/features.xml b/framework/src/onos/apps/vtn/app/features.xml
new file mode 100644
index 00000000..c82b41d5
--- /dev/null
+++ b/framework/src/onos/apps/vtn/app/features.xml
@@ -0,0 +1,27 @@
+<?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>
+ <feature>onos-drivers</feature>
+ <bundle>mvn:${project.groupId}/onos-app-vtn-mgr/${project.version}</bundle>
+ <bundle>mvn:${project.groupId}/onos-app-vtn-web/${project.version}</bundle>
+ <bundle>mvn:${project.groupId}/onos-app-vtn-rsc/${project.version}</bundle>
+ </feature>
+</features>
diff --git a/framework/src/onos/apps/vtn/app/pom.xml b/framework/src/onos/apps/vtn/app/pom.xml
new file mode 100644
index 00000000..4ed66172
--- /dev/null
+++ b/framework/src/onos/apps/vtn/app/pom.xml
@@ -0,0 +1,44 @@
+<?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/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-app-vtn</artifactId>
+ <version>1.4.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>onos-app-vtn-onosfw</artifactId>
+ <packaging>pom</packaging>
+
+ <description>ONOS framework applications</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-app-vtn-rsc</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-app-vtn-web</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-app-vtn-mgr</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
+</project>
diff --git a/framework/src/onos/apps/vtn/pom.xml b/framework/src/onos/apps/vtn/pom.xml
index fb8fcb13..c2cfe2be 100644
--- a/framework/src/onos/apps/vtn/pom.xml
+++ b/framework/src/onos/apps/vtn/pom.xml
@@ -1,6 +1,6 @@
-<?xml version="1.0"?>
+<?xml version="1.0" encoding="UTF-8"?>
<!--
- ~ Copyright 2015 Open Networking Laboratory
+ ~ 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.
@@ -14,11 +14,11 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<project
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
- xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+<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>
@@ -27,32 +27,14 @@
</parent>
<artifactId>onos-app-vtn</artifactId>
- <packaging>bundle</packaging>
+ <packaging>pom</packaging>
+ <description>ONOS framework applications</description>
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <onos.app.name>org.onosproject.vtn</onos.app.name>
- </properties>
- <dependencies>
- <dependency>
- <groupId>javax.ws.rs</groupId>
- <artifactId>jsr311-api</artifactId>
- <version>1.1.1</version>
- </dependency>
- <dependency>
- <groupId>org.onosproject</groupId>
- <artifactId>onos-incubator-api</artifactId>
- </dependency>
- <dependency>
- <groupId>org.onosproject</groupId>
- <artifactId>onos-core-serializers</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.onosproject</groupId>
- <artifactId>onos-app-vtnrsc</artifactId>
- <version>${project.version}</version>
- </dependency>
- </dependencies>
+ <modules>
+ <module>vtnrsc</module>
+ <module>vtnmgr</module>
+ <module>vtnweb</module>
+ <module>app</module>
+ </modules>
</project>
diff --git a/framework/src/onos/apps/vtn/vtnmgr/pom.xml b/framework/src/onos/apps/vtn/vtnmgr/pom.xml
new file mode 100644
index 00000000..03e66708
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnmgr/pom.xml
@@ -0,0 +1,53 @@
+<?xml version="1.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.
+ -->
+<project
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+ xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-app-vtn</artifactId>
+ <version>1.4.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>onos-app-vtn-mgr</artifactId>
+ <packaging>bundle</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>javax.ws.rs</groupId>
+ <artifactId>jsr311-api</artifactId>
+ <version>1.1.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-incubator-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-core-serializers</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-app-vtn-rsc</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/framework/src/onos/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/VTNService.java b/framework/src/onos/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/VTNService.java
new file mode 100644
index 00000000..a20f852b
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/VTNService.java
@@ -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.vtn;
+
+import org.onosproject.net.Device;
+import org.onosproject.net.Host;
+
+/**
+ * VTN application that applies configuration and flows to the device.
+ */
+public interface VTNService {
+
+ /**
+ * Creates a vxlan tunnel and creates the ovs when a ovs controller node is detected.
+ *
+ * @param device controller-type device
+ */
+ void onServerDetected(Device device);
+
+ /**
+ * Drops a vxlan tunnel and drops the ovs when a ovs controller node is vanished.
+ *
+ * @param device controller-type device
+ */
+ void onServerVanished(Device device);
+
+ /**
+ * Applies default forwarding flows when a ovs is detected.
+ *
+ * @param device switch-type device
+ */
+ void onOvsDetected(Device device);
+
+ /**
+ * Remove default forwarding flows when a ovs is vanished.
+ *
+ * @param device switch-type device
+ */
+ void onOvsVanished(Device device);
+
+ /**
+ * Applies multicast flows and tunnel flows when a VM is detected.
+ *
+ * @param host a VM
+ */
+ void onHostDetected(Host host);
+
+ /**
+ * Remove multicast flows and tunnel flows when a VM is vanished.
+ *
+ * @param host a VM
+ */
+ void onHostVanished(Host host);
+
+}
diff --git a/framework/src/onos/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/impl/VTNManager.java b/framework/src/onos/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/impl/VTNManager.java
new file mode 100644
index 00000000..090ef0f1
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/impl/VTNManager.java
@@ -0,0 +1,672 @@
+/*
+ * 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.vtn.impl;
+
+import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
+import static org.onlab.util.Tools.groupedThreads;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.stream.Collectors;
+
+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.osgi.DefaultServiceDirectory;
+import org.onlab.osgi.ServiceDirectory;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onlab.util.KryoNamespace;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Host;
+import org.onosproject.net.HostId;
+import org.onosproject.net.Port;
+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.DefaultTunnelDescription;
+import org.onosproject.net.behaviour.IpTunnelEndPoint;
+import org.onosproject.net.behaviour.Pipeliner;
+import org.onosproject.net.behaviour.PipelinerContext;
+import org.onosproject.net.behaviour.TunnelConfig;
+import org.onosproject.net.behaviour.TunnelDescription;
+import org.onosproject.net.behaviour.TunnelEndPoint;
+import org.onosproject.net.device.DeviceEvent;
+import org.onosproject.net.device.DeviceListener;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.driver.DefaultDriverData;
+import org.onosproject.net.driver.Driver;
+import org.onosproject.net.driver.DriverHandler;
+import org.onosproject.net.driver.DriverService;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowRuleService;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.criteria.Criteria;
+import org.onosproject.net.flow.instructions.Instructions;
+import org.onosproject.net.flowobjective.DefaultForwardingObjective;
+import org.onosproject.net.flowobjective.FlowObjectiveService;
+import org.onosproject.net.flowobjective.FlowObjectiveStore;
+import org.onosproject.net.flowobjective.ForwardingObjective;
+import org.onosproject.net.flowobjective.ForwardingObjective.Flag;
+import org.onosproject.net.flowobjective.Objective;
+import org.onosproject.net.host.HostEvent;
+import org.onosproject.net.host.HostListener;
+import org.onosproject.net.host.HostService;
+import org.onosproject.store.serializers.KryoNamespaces;
+import org.onosproject.store.service.EventuallyConsistentMap;
+import org.onosproject.store.service.StorageService;
+import org.onosproject.store.service.WallClockTimestamp;
+import org.onosproject.vtn.VTNService;
+import org.onosproject.vtnrsc.SegmentationId;
+import org.onosproject.vtnrsc.TenantNetwork;
+import org.onosproject.vtnrsc.VirtualPort;
+import org.onosproject.vtnrsc.VirtualPortId;
+import org.onosproject.vtnrsc.tenantnetwork.TenantNetworkService;
+import org.onosproject.vtnrsc.virtualport.VirtualPortService;
+import org.slf4j.Logger;
+
+import com.google.common.collect.Sets;
+
+/**
+ * Provides implementation of VTNService.
+ */
+@Component(immediate = true)
+@Service
+public class VTNManager implements VTNService {
+ private final Logger log = getLogger(getClass());
+
+ private static final String APP_ID = "org.onosproject.app.vtn";
+ private ScheduledExecutorService backgroundService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected DeviceService deviceService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected HostService hostService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected FlowRuleService flowRuleService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CoreService coreService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected StorageService storageService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected TenantNetworkService tenantNetworkService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected VirtualPortService virtualPortService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected DriverService driverService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected FlowObjectiveService flowObjectiveService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected FlowObjectiveStore flowObjectiveStore;
+ protected ServiceDirectory serviceDirectory = new DefaultServiceDirectory();
+ private EventuallyConsistentMap<HostId, SegmentationId> binding;
+ private ApplicationId appId;
+ private HostListener hostListener = new InnerHostListener();
+ private DeviceListener deviceListener = new InnerDeviceListener();
+ private static final String IFACEID = "ifaceid";
+ private static final String PORT_HEAD = "vxlan";
+ private static final String DEFAULT_BRIDGE_NAME = "br-int";
+ private static final String CONTROLLER_IP_KEY = "ipaddress";
+ private static final int DEFAULT_MAC_PRIORITY = 0x0000;
+ private static final int MAC_PRIORITY = 0xffff;
+ private static final int DEFAULT_PORT_PRIORITY = 0x0000;
+ private static final int PORT_PRIORITY = 0xffff;
+ private static final String SWITCH_CHANNEL_ID = "channelId";
+ private static final String DRIVER_NAME = "onosfw";
+
+ @Activate
+ public void activate() {
+ KryoNamespace.Builder serializer = KryoNamespace.newBuilder()
+ .register(KryoNamespaces.API);
+ appId = coreService.registerApplication(APP_ID);
+ deviceService.addListener(deviceListener);
+ hostService.addListener(hostListener);
+ backgroundService = newSingleThreadScheduledExecutor(groupedThreads("onos-apps/vtn",
+ "manager-background"));
+ binding = storageService
+ .<HostId, SegmentationId>eventuallyConsistentMapBuilder()
+ .withName("all_tunnel").withSerializer(serializer)
+ .withTimestampProvider((k, v) -> new WallClockTimestamp())
+ .build();
+ log.info("Started");
+ }
+
+ @Deactivate
+ public void deactivate() {
+ backgroundService.shutdown();
+ binding.destroy();
+ log.info("Stopped");
+ }
+
+ @Override
+ public void onServerDetected(Device device) {
+ Iterable<Device> devices = deviceService.getAvailableDevices();
+ DriverHandler handler = driverService.createHandler(device.id());
+ BridgeConfig bridgeConfig = handler.behaviour(BridgeConfig.class);
+ bridgeConfig.addBridge(BridgeName.bridgeName(DEFAULT_BRIDGE_NAME));
+ String ipAddress = device.annotations().value(CONTROLLER_IP_KEY);
+ IpAddress ip = IpAddress.valueOf(ipAddress);
+ Sets.newHashSet(devices).stream()
+ .filter(d -> Device.Type.CONTROLLER == d.type())
+ .filter(d -> !device.id().equals(d.id())).forEach(d -> {
+ String ipAddress1 = d.annotations()
+ .value(CONTROLLER_IP_KEY);
+ IpAddress ip1 = IpAddress.valueOf(ipAddress1);
+ applyTunnelConfig(ip, ip1, handler);
+ DriverHandler handler1 = driverService
+ .createHandler(d.id());
+ applyTunnelConfig(ip1, ip, handler1);
+
+ });
+ }
+
+ @Override
+ public void onServerVanished(Device device) {
+ Iterable<Device> devices = deviceService.getAvailableDevices();
+ String ipAddress = device.annotations().value(CONTROLLER_IP_KEY);
+ IpAddress dst = IpAddress.valueOf(ipAddress);
+ Sets.newHashSet(devices).stream()
+ .filter(d -> d.type() == Device.Type.CONTROLLER)
+ .filter(d -> !device.id().equals(d.id())).forEach(d -> {
+ String ipAddress1 = d.annotations()
+ .value(CONTROLLER_IP_KEY);
+ DriverHandler handler = driverService.createHandler(d.id());
+ IpAddress src = IpAddress.valueOf(ipAddress1);
+ removeTunnelConfig(src, dst, handler);
+ });
+ }
+
+ private void applyTunnelConfig(IpAddress src, IpAddress dst,
+ DriverHandler handler) {
+ TunnelEndPoint tunnelAsSrc = IpTunnelEndPoint.ipTunnelPoint(src);
+ TunnelEndPoint tunnelAsDst = IpTunnelEndPoint.ipTunnelPoint(dst);
+ TunnelDescription tunnel = new DefaultTunnelDescription(
+ tunnelAsSrc,
+ tunnelAsDst,
+ TunnelDescription.Type.VXLAN,
+ null);
+ TunnelConfig config = handler.behaviour(TunnelConfig.class);
+ config.createTunnel(tunnel);
+ }
+
+ private void removeTunnelConfig(IpAddress src, IpAddress dst,
+ DriverHandler handler) {
+ TunnelEndPoint tunnelAsSrc = IpTunnelEndPoint.ipTunnelPoint(src);
+ TunnelEndPoint tunnelAsDst = IpTunnelEndPoint.ipTunnelPoint(dst);
+ TunnelDescription tunnel = new DefaultTunnelDescription(
+ tunnelAsSrc,
+ tunnelAsDst,
+ TunnelDescription.Type.VXLAN,
+ null);
+ TunnelConfig config = handler.behaviour(TunnelConfig.class);
+ config.removeTunnel(tunnel);
+ }
+
+ @Override
+ public void onOvsDetected(Device device) {
+ programMacDefaultRules(device.id(), appId, Objective.Operation.ADD);
+ programPortDefaultRules(device.id(), appId, Objective.Operation.ADD);
+ }
+
+ @Override
+ public void onOvsVanished(Device device) {
+ programMacDefaultRules(device.id(), appId, Objective.Operation.REMOVE);
+ programPortDefaultRules(device.id(), appId, Objective.Operation.REMOVE);
+ }
+
+ @Override
+ public void onHostDetected(Host host) {
+ String ifaceId = host.annotations().value(IFACEID);
+ DeviceId deviceId = host.location().deviceId();
+ String currentControllerIp = getControllerIpOfSwitch(deviceId);
+ Iterable<Device> devices = deviceService.getAvailableDevices();
+ VirtualPortId portId = VirtualPortId.portId(ifaceId);
+ VirtualPort port = virtualPortService.getPort(portId);
+ TenantNetwork network = tenantNetworkService
+ .getNetwork(port.networkId());
+ String tunnelName = "vxlan-" + currentControllerIp;
+ binding.put(host.id(), network.segmentationId());
+ List<Port> allPorts = deviceService.getPorts(deviceId);
+ PortNumber inPort = host.location().port();
+ List<PortNumber> localVmPorts = getLocalPorts(deviceId, ifaceId);
+ List<PortNumber> localTunnelPorts = new ArrayList<>();
+ Sets.newHashSet(allPorts.iterator()).stream()
+ .filter(p -> !p.number().equals(PortNumber.LOCAL)).forEach(p -> {
+ if (p.annotations().value("portName").startsWith(PORT_HEAD)) {
+ localTunnelPorts.add(p.number());
+ }
+ });
+
+ localVmPorts.forEach(lp -> programLocalBcastRules(deviceId, network.segmentationId(), lp, localVmPorts,
+ localTunnelPorts, appId, Objective.Operation.ADD));
+ programLocalOut(deviceId, network.segmentationId(), inPort, host.mac(),
+ appId, Objective.Operation.ADD);
+ localTunnelPorts
+ .forEach(tp -> programTunnelFloodOut(deviceId,
+ network.segmentationId(),
+ tp, localVmPorts,
+ appId,
+ Objective.Operation.ADD));
+ Sets.newHashSet(devices).stream()
+ .filter(d -> d.type() == Device.Type.CONTROLLER).forEach(d -> {
+ DriverHandler handler = driverService.createHandler(d.id());
+ BridgeConfig bridgeConfig = handler
+ .behaviour(BridgeConfig.class);
+ Collection<BridgeDescription> bridgeDescriptions = bridgeConfig
+ .getBridges();
+
+ Iterator<BridgeDescription> it = bridgeDescriptions
+ .iterator();
+ if (it.hasNext()) {
+ BridgeDescription sw = it.next();
+ Set<PortNumber> ports = bridgeConfig.getPortNumbers();
+ ports.stream()
+ .filter(p -> p.name()
+ .equalsIgnoreCase(tunnelName))
+ .forEach(p -> programTunnelOut(sw.deviceId(),
+ network.segmentationId(), p,
+ host.mac(), appId,
+ Objective.Operation.ADD));
+ }
+ });
+ programLocalIn(deviceId, network.segmentationId(), inPort, host.mac(),
+ appId, Objective.Operation.ADD);
+ localTunnelPorts
+ .forEach(tp -> programTunnelIn(deviceId,
+ network.segmentationId(),
+ tp, inPort, host.mac(),
+ appId, Objective.Operation.ADD));
+
+ }
+
+ @Override
+ public void onHostVanished(Host host) {
+ String ifaceId = host.annotations().value(IFACEID);
+ SegmentationId segId = binding.remove(host.id());
+ DeviceId deviceId = host.location().deviceId();
+ String currentControllerIp = getControllerIpOfSwitch(deviceId);
+ Iterable<Device> devices = deviceService.getAvailableDevices();
+
+ String tunnelName = "vxlan-" + currentControllerIp;
+ List<Port> allPorts = deviceService.getPorts(deviceId);
+ PortNumber inPort = host.location().port();
+
+ List<PortNumber> localTunnelPorts = new ArrayList<>();
+ Sets.newHashSet(allPorts.iterator()).stream()
+ .filter(p -> !p.number().equals(PortNumber.LOCAL)).forEach(p -> {
+ if (p.annotations().value("portName").startsWith(PORT_HEAD)) {
+ localTunnelPorts.add(p.number());
+ }
+ });
+
+ List<PortNumber> localVmPorts = getLocalPorts(deviceId, ifaceId);
+ localVmPorts.add(inPort);
+ localVmPorts.forEach(lp -> programLocalBcastRules(deviceId, segId, lp, localVmPorts,
+ localTunnelPorts, appId, Objective.Operation.REMOVE));
+ programLocalOut(deviceId, segId, inPort, host.mac(),
+ appId, Objective.Operation.REMOVE);
+ localTunnelPorts
+ .forEach(tp -> programTunnelFloodOut(deviceId,
+ segId,
+ tp, localVmPorts,
+ appId,
+ Objective.Operation.REMOVE));
+ Sets.newHashSet(devices).stream()
+ .filter(d -> d.type() == Device.Type.CONTROLLER).forEach(d -> {
+ DriverHandler handler = driverService.createHandler(d.id());
+ BridgeConfig bridgeConfig = handler
+ .behaviour(BridgeConfig.class);
+ Collection<BridgeDescription> bridgeDescriptions = bridgeConfig
+ .getBridges();
+
+ Iterator<BridgeDescription> it = bridgeDescriptions
+ .iterator();
+ if (it.hasNext()) {
+ BridgeDescription sw = it.next();
+ Set<PortNumber> ports = bridgeConfig.getPortNumbers();
+ ports.stream()
+ .filter(p -> p.name()
+ .equalsIgnoreCase(tunnelName))
+ .forEach(p -> programTunnelOut(sw.deviceId(),
+ segId, p,
+ host.mac(), appId,
+ Objective.Operation.REMOVE));
+ }
+ });
+ programLocalIn(deviceId, segId, inPort, host.mac(),
+ appId, Objective.Operation.REMOVE);
+ localTunnelPorts
+ .forEach(tp -> programTunnelIn(deviceId,
+ segId,
+ tp, inPort, host.mac(),
+ appId, Objective.Operation.REMOVE));
+ }
+
+ private class InnerDeviceListener implements DeviceListener {
+
+ @Override
+ public void event(DeviceEvent event) {
+ Device device = event.subject();
+ if (Device.Type.CONTROLLER == device.type()
+ && DeviceEvent.Type.DEVICE_ADDED == event.type()) {
+ backgroundService.execute(() -> onServerDetected(device));
+ } else if (Device.Type.CONTROLLER == device.type()
+ && DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED == event
+ .type()) {
+ backgroundService.execute(() -> onServerVanished(device));
+ } else if (Device.Type.SWITCH == device.type()
+ && DeviceEvent.Type.DEVICE_ADDED == event.type()) {
+ backgroundService.execute(() -> onOvsDetected(device));
+ } else if (Device.Type.SWITCH == device.type()
+ && DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED == event
+ .type()) {
+ backgroundService.execute(() -> onOvsVanished(device));
+ } else {
+ log.info("Do nothing for this device type");
+ }
+ }
+
+ }
+
+ private class InnerHostListener implements HostListener {
+
+ @Override
+ public void event(HostEvent event) {
+ Host host = event.subject();
+ if (HostEvent.Type.HOST_ADDED == event.type()) {
+ backgroundService.execute(() -> onHostDetected(host));
+ } else if (HostEvent.Type.HOST_REMOVED == event.type()) {
+ backgroundService.execute(() -> onHostVanished(host));
+ } else if (HostEvent.Type.HOST_UPDATED == event.type()) {
+ backgroundService.execute(() -> {
+ onHostVanished(host);
+ onHostDetected(host);
+ });
+ }
+ }
+
+ }
+
+ // Used to forward the flows to the local VM.
+ private void programLocalOut(DeviceId dpid, SegmentationId segmentationId,
+ PortNumber outPort, MacAddress sourceMac,
+ ApplicationId appid,
+ Objective.Operation type) {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchTunnelId(Long.parseLong(segmentationId.toString()))
+ .matchEthDst(sourceMac).build();
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setOutput(outPort).build();
+ ForwardingObjective.Builder objective = DefaultForwardingObjective
+ .builder().withTreatment(treatment).withSelector(selector)
+ .fromApp(appId).withFlag(Flag.SPECIFIC)
+ .withPriority(MAC_PRIORITY);
+ if (type.equals(Objective.Operation.ADD)) {
+ flowServiceForward(dpid, objective.add());
+ } else {
+ flowServiceForward(dpid, objective.remove());
+ }
+
+ }
+
+ // Used to forward the flows into the VXLAN tunnel.
+ private void programTunnelOut(DeviceId dpid, SegmentationId segmentationId,
+ PortNumber tunnelOutPort, MacAddress dstMac,
+ ApplicationId appid,
+ Objective.Operation type) {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchEthDst(dstMac).add(Criteria.matchTunnelId(Long
+ .parseLong(segmentationId.toString())))
+ .build();
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+
+ .setOutput(tunnelOutPort).build();
+ ForwardingObjective.Builder objective = DefaultForwardingObjective
+ .builder().withTreatment(treatment).withSelector(selector)
+ .fromApp(appId).withFlag(Flag.SPECIFIC)
+ .withPriority(MAC_PRIORITY);
+ if (type.equals(Objective.Operation.ADD)) {
+ flowServiceForward(dpid, objective.add());
+ } else {
+ flowServiceForward(dpid, objective.remove());
+ }
+
+ }
+
+ // Used to forward multicast flows to remote VMs of the same tenant via
+ // VXLAN tunnel.
+ private void programTunnelFloodOut(DeviceId deviceId,
+ SegmentationId segmentationId,
+ PortNumber ofPortOut,
+ List<PortNumber> localVmPorts,
+ ApplicationId appid,
+ Objective.Operation type) {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchInPort(ofPortOut)
+
+ .add(Criteria.matchTunnelId(Long.parseLong(segmentationId
+ .toString()))).matchEthDst(MacAddress.BROADCAST)
+ .build();
+ TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+
+ for (PortNumber outPort : localVmPorts) {
+ treatment.setOutput(outPort);
+ }
+
+ ForwardingObjective.Builder objective = DefaultForwardingObjective
+ .builder().withTreatment(treatment.build())
+ .withSelector(selector).fromApp(appId).makePermanent()
+ .withFlag(Flag.SPECIFIC).withPriority(MAC_PRIORITY);
+ if (type.equals(Objective.Operation.ADD)) {
+ flowServiceForward(deviceId, objective.add());
+ } else {
+ flowServiceForward(deviceId, objective.remove());
+ }
+ }
+
+ // Applies default flows to mac table.
+ private void programMacDefaultRules(DeviceId dpid, ApplicationId appid,
+ Objective.Operation type) {
+ TrafficSelector selector = DefaultTrafficSelector.builder().build();
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder().drop()
+ .build();
+ ForwardingObjective.Builder objective = DefaultForwardingObjective
+ .builder().withTreatment(treatment).withSelector(selector)
+ .fromApp(appId).makePermanent().withFlag(Flag.SPECIFIC)
+ .withPriority(DEFAULT_MAC_PRIORITY);
+ if (type.equals(Objective.Operation.ADD)) {
+ flowServiceForward(dpid, objective.add());
+ } else {
+ flowServiceForward(dpid, objective.remove());
+ }
+ }
+
+ // Used to forward the flows to the local VMs with the same tenant.
+ private void programLocalBcastRules(DeviceId deviceId,
+ SegmentationId segmentationId,
+ PortNumber inPort,
+ List<PortNumber> localVmPorts,
+ List<PortNumber> localTunnelPorts,
+ ApplicationId appid,
+ Objective.Operation type) {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchInPort(inPort).matchEthDst(MacAddress.BROADCAST)
+ .add(Criteria.matchTunnelId(Long
+ .parseLong(segmentationId.toString())))
+ .build();
+ TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+ for (PortNumber outPort : localVmPorts) {
+ if (inPort != outPort) {
+ treatment.setOutput(outPort);
+ }
+ }
+ for (PortNumber outport : localTunnelPorts) {
+ treatment.setOutput(outport);
+ }
+ ForwardingObjective.Builder objective = DefaultForwardingObjective
+ .builder().withTreatment(treatment.build())
+ .withSelector(selector).fromApp(appId).makePermanent()
+ .withFlag(Flag.SPECIFIC).withPriority(MAC_PRIORITY);
+ if (type.equals(Objective.Operation.ADD)) {
+ flowServiceForward(deviceId, objective.add());
+ } else {
+ flowServiceForward(deviceId, objective.remove());
+ }
+ }
+
+ // Used to apply local entry flow.
+ private void programLocalIn(DeviceId dpid, SegmentationId segmentationId,
+ PortNumber inPort, MacAddress srcMac,
+ ApplicationId appid, Objective.Operation type) {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchInPort(inPort).matchEthSrc(srcMac).build();
+ TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+ treatment.add(Instructions.modTunnelId(Long.parseLong(segmentationId
+ .toString())));
+ ForwardingObjective.Builder objective = DefaultForwardingObjective
+ .builder().withTreatment(treatment.build())
+ .withSelector(selector).fromApp(appId).makePermanent()
+ .withFlag(Flag.SPECIFIC).withPriority(PORT_PRIORITY);
+ if (type.equals(Objective.Operation.ADD)) {
+ flowServiceForward(dpid, objective.add());
+ } else {
+ flowServiceForward(dpid, objective.remove());
+ }
+ }
+
+ // Used to forward the flows from the egress tunnel to the VM.
+ private void programTunnelIn(DeviceId dpid, SegmentationId segmentationId,
+ PortNumber tunnelInPort, PortNumber outPort,
+ MacAddress sourceMac, ApplicationId appid,
+ Objective.Operation type) {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchInPort(tunnelInPort).add(Criteria.matchTunnelId(Long
+ .parseLong(segmentationId.toString())))
+ .build();
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
+
+ ForwardingObjective.Builder objective = DefaultForwardingObjective
+ .builder().withTreatment(treatment).withSelector(selector)
+ .fromApp(appId).makePermanent().withFlag(Flag.SPECIFIC)
+ .withPriority(PORT_PRIORITY);
+ if (type.equals(Objective.Operation.ADD)) {
+ flowServiceForward(dpid, objective.add());
+ } else {
+ flowServiceForward(dpid, objective.remove());
+ }
+ }
+
+ // Applies the default flows to port table.
+ private void programPortDefaultRules(DeviceId dpid, ApplicationId appid,
+ Objective.Operation type) {
+ TrafficSelector selector = DefaultTrafficSelector.builder().build();
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
+ ForwardingObjective.Builder objective = DefaultForwardingObjective
+ .builder().withTreatment(treatment).withSelector(selector)
+ .fromApp(appId).makePermanent().withFlag(Flag.SPECIFIC)
+ .withPriority(DEFAULT_PORT_PRIORITY);
+ if (type.equals(Objective.Operation.ADD)) {
+ flowServiceForward(dpid, objective.add());
+ } else {
+ flowServiceForward(dpid, objective.remove());
+ }
+ }
+
+ // Used to get channelId from the device annotations.
+ private String getControllerIpOfSwitch(DeviceId deviceId) {
+ Device device = deviceService.getDevice(deviceId);
+ String url = device.annotations().value(SWITCH_CHANNEL_ID);
+ return url.substring(0, url.lastIndexOf(":"));
+ }
+
+ private Iterable<String> getIfaceIds(String ifaceId) {
+ VirtualPortId portId = VirtualPortId.portId(ifaceId);
+ VirtualPort port = virtualPortService.getPort(portId);
+ if (port == null) {
+ return Collections.emptyList();
+ }
+
+ TenantNetwork network = tenantNetworkService
+ .getNetwork(port.networkId());
+ if (network == null) {
+ return Collections.emptyList();
+ }
+
+ Collection<VirtualPort> ports = virtualPortService
+ .getPorts(network.id());
+ return ports.stream().map(p -> p.portId().portId())
+ .collect(Collectors.toSet());
+ }
+
+ private List<PortNumber> getLocalPorts(DeviceId deviceId, String ifaceId) {
+ DriverHandler handler = driverService
+ .createHandler(getController(deviceId));
+ BridgeConfig bridgeConfig = handler.behaviour(BridgeConfig.class);
+ Iterable<String> ifaceIds = getIfaceIds(ifaceId);
+ return bridgeConfig.getLocalPorts(ifaceIds);
+ }
+
+ private DeviceId getController(DeviceId deviceId) {
+ Iterable<Device> devices = deviceService.getAvailableDevices();
+ for (Device device : devices) {
+ if (device.type() == Device.Type.CONTROLLER && device.id()
+ .toString().contains(getControllerIpOfSwitch(deviceId))) {
+ return device.id();
+ }
+ }
+ log.info("Can not find controller for device : {}", deviceId);
+ return null;
+ }
+
+ //Used to apply flowRule
+ private void flowServiceForward(DeviceId deviceId, ForwardingObjective forwardingObjective) {
+ Driver driver = driverService.getDriver(DRIVER_NAME);
+ Pipeliner pipeLiner = driver.createBehaviour(new DefaultDriverData(driver, deviceId), Pipeliner.class);
+ if (pipeLiner != null) {
+ final PipelinerContext context = new InnerPipelineContext();
+ pipeLiner.init(deviceId, context);
+ pipeLiner.forward(forwardingObjective);
+ }
+ }
+
+ // Processing context for initializing pipeline driver behaviours.
+ private class InnerPipelineContext implements PipelinerContext {
+ @Override
+ public ServiceDirectory directory() {
+ return serviceDirectory;
+ }
+
+ @Override
+ public FlowObjectiveStore store() {
+ return flowObjectiveStore;
+ }
+ }
+
+}
diff --git a/framework/src/onos/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/impl/package-info.java b/framework/src/onos/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/impl/package-info.java
new file mode 100644
index 00000000..f18dbf8a
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/impl/package-info.java
@@ -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.
+ */
+
+/**
+ * VTN application that applies configuration and flows to the device.
+ */
+package org.onosproject.vtn.impl;
diff --git a/framework/src/onos/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/package-info.java b/framework/src/onos/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/package-info.java
new file mode 100644
index 00000000..371466c3
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/package-info.java
@@ -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.
+ */
+
+/**
+ * VTN application that applies configuration and flows to the device.
+ */
+package org.onosproject.vtn;
diff --git a/framework/src/onos/apps/vtn/vtnrsc/pom.xml b/framework/src/onos/apps/vtn/vtnrsc/pom.xml
new file mode 100644
index 00000000..8696295c
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/pom.xml
@@ -0,0 +1,56 @@
+<?xml version="1.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.
+ -->
+<project
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+ xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-app-vtn</artifactId>
+ <version>1.4.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+
+ <artifactId>onos-app-vtn-rsc</artifactId>
+ <packaging>bundle</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-cli</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.scr.annotations</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.karaf.shell</groupId>
+ <artifactId>org.apache.karaf.shell.console</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-core-serializers</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/AllocationPool.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/AllocationPool.java
new file mode 100644
index 00000000..3d6ba8e8
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/AllocationPool.java
@@ -0,0 +1,38 @@
+/*
+ * 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.IpAddress;
+
+/**
+ * The continuous IP address range between the start address and the end address for the allocation pools.
+ */
+public interface AllocationPool {
+
+ /**
+ * The start address for the allocation pool.
+ *
+ * @return startIp
+ */
+ IpAddress startIp();
+
+ /**
+ * The end address for the allocation pool.
+ *
+ * @return endIp
+ */
+ IpAddress endIp();
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/AllowedAddressPair.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/AllowedAddressPair.java
new file mode 100644
index 00000000..4e1028d8
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/AllowedAddressPair.java
@@ -0,0 +1,94 @@
+/*
+ * 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;
+
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+
+/**
+ * Immutable representation of a allowed address pair.
+ */
+public final class AllowedAddressPair {
+ private final IpAddress ip;
+ private final MacAddress mac;
+ // Public construction is prohibited
+ private AllowedAddressPair(IpAddress ip, MacAddress mac) {
+ checkNotNull(ip, "IpAddress cannot be null");
+ checkNotNull(mac, "MacAddress cannot be null");
+ this.ip = ip;
+ this.mac = mac;
+ }
+ /**
+ * Returns the AllowedAddressPair ip address.
+ *
+ * @return ip address
+ */
+ public IpAddress ip() {
+ return ip;
+ }
+
+ /**
+ * Returns the AllowedAddressPair MAC address.
+ *
+ * @return MAC address
+ */
+ public MacAddress mac() {
+ return mac;
+ }
+
+
+ /**
+ * Creates a allowedAddressPair using the supplied ipAddress &amp;
+ * macAddress.
+ *
+ * @param ip IP address
+ * @param mac MAC address
+ * @return AllowedAddressPair
+ */
+ public static AllowedAddressPair allowedAddressPair(IpAddress ip,
+ MacAddress mac) {
+ return new AllowedAddressPair(ip, mac);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(ip, mac);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof AllowedAddressPair) {
+ final AllowedAddressPair that = (AllowedAddressPair) obj;
+ return Objects.equals(this.ip, that.ip)
+ && Objects.equals(this.mac, that.mac);
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(this).add("ip", ip).add("mac", mac).toString();
+ }
+
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/BindingHostId.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/BindingHostId.java
new file mode 100644
index 00000000..c715d08a
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/BindingHostId.java
@@ -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;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Objects;
+
+public final class BindingHostId {
+ private final String bindingHostId;
+
+ // Public construction is prohibited
+ private BindingHostId(String bindingHostId) {
+ checkNotNull(bindingHostId, "BindingHosttId cannot be null");
+ this.bindingHostId = bindingHostId;
+ }
+
+ /**
+ * Creates a BindingHostId identifier.
+ *
+ * @param bindingHostId the bindingHostId identifier
+ * @return the bindingHostId identifier
+ */
+ public static BindingHostId bindingHostId(String bindingHostId) {
+ return new BindingHostId(bindingHostId);
+ }
+
+ /**
+ * Returns the bindingHostId identifier.
+ *
+ * @return the bindingHostId identifier
+ */
+ public String bindingHostId() {
+ return bindingHostId;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(bindingHostId);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof BindingHostId) {
+ final BindingHostId that = (BindingHostId) obj;
+ return this.getClass() == that.getClass()
+ && Objects.equals(this.bindingHostId, that.bindingHostId);
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return bindingHostId;
+ }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultAllocationPool.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultAllocationPool.java
new file mode 100644
index 00000000..8a480194
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultAllocationPool.java
@@ -0,0 +1,81 @@
+/*
+ * 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;
+
+import org.onlab.packet.IpAddress;
+
+/**
+ * The continuous IP address range between the start address and the end address
+ * for the allocation pools.
+ */
+public final class DefaultAllocationPool implements AllocationPool {
+
+ private final IpAddress startIp;
+ private final IpAddress endIp;
+
+ /**
+ * Creates an AllocationPool by using the start IP address and the end IP
+ * address.
+ *
+ * @param startIp the start IP address of the allocation pool
+ * @param endIp the end IP address of the allocation pool
+ */
+ public DefaultAllocationPool(IpAddress startIp, IpAddress endIp) {
+ checkNotNull(startIp, "StartIp cannot be null");
+ checkNotNull(endIp, "EndIp cannot be null");
+ this.startIp = startIp;
+ this.endIp = endIp;
+ }
+
+ @Override
+ public IpAddress startIp() {
+ return startIp;
+ }
+
+ @Override
+ public IpAddress endIp() {
+ return endIp;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(startIp, endIp);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof DefaultAllocationPool) {
+ final DefaultAllocationPool other = (DefaultAllocationPool) obj;
+ return Objects.equals(this.startIp, other.startIp)
+ && Objects.equals(this.endIp, other.endIp);
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(this).add("startIp", startIp).add("endIp", endIp)
+ .toString();
+ }
+}
+
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultHostRoute.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultHostRoute.java
new file mode 100644
index 00000000..8679100d
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultHostRoute.java
@@ -0,0 +1,79 @@
+/*
+ * 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 java.util.Objects;
+
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+
+/**
+ * Host route dictionaries for the subnet.
+ */
+public final class DefaultHostRoute implements HostRoute {
+
+ private final IpAddress nexthop;
+ private final IpPrefix destination;
+
+ /**
+ *
+ * Creates a DefaultHostRoute by using the next hop and the destination.
+ *
+ * @param nexthop of the DefaultHostRoute
+ * @param destination of the DefaultHostRoute
+ */
+ public DefaultHostRoute(IpAddress nexthop, IpPrefix destination) {
+ this.nexthop = nexthop;
+ this.destination = destination;
+ }
+
+ @Override
+ public IpAddress nexthop() {
+ return nexthop;
+ }
+
+ @Override
+ public IpPrefix destination() {
+ return destination;
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(this).add("nexthop", nexthop)
+ .add("destination", destination).toString();
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(nexthop, destination);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof DefaultHostRoute) {
+ final DefaultHostRoute other = (DefaultHostRoute) obj;
+ return Objects.equals(this.nexthop, other.nexthop)
+ && Objects.equals(this.destination, other.destination);
+ }
+ return false;
+ }
+
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultSubnet.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultSubnet.java
new file mode 100644
index 00000000..6049b558
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultSubnet.java
@@ -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 java.util.Objects;
+import java.util.Set;
+
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpAddress.Version;
+import org.onlab.packet.IpPrefix;
+
+/**
+ * Default implementation of Subnet interface .
+ */
+public final class DefaultSubnet implements Subnet {
+ private final SubnetId id;
+ private final String subnetName;
+ private final TenantNetworkId networkId;
+ private final TenantId tenantId;
+ private final Version ipVersion;
+ private final IpPrefix cidr;
+ private final IpAddress gatewayIp;
+ private final boolean dhcpEnabled;
+ private final boolean shared;
+ private final Mode ipV6AddressMode;
+ private final Mode ipV6RaMode;
+ private final Set<HostRoute> hostRoutes;
+ private final Set<AllocationPool> allocationPools;
+
+ /**
+ * Creates a subnet object.
+ *
+ * @param id subnet identifier
+ * @param subnetName the name of subnet
+ * @param networkId network identifier
+ * @param tenantId tenant identifier
+ * @param ipVersion Version of ipv4 or ipv6
+ * @param cidr the cidr
+ * @param gatewayIp gateway ip
+ * @param dhcpEnabled dhcp enabled or not
+ * @param shared indicates whether this network is shared across all
+ * tenants, By default, only administrative user can change this
+ * value
+ * @param hostRoutes a collection of host routes
+ * @param ipV6AddressMode ipV6AddressMode
+ * @param ipV6RaMode ipV6RaMode
+ * @param allocationPoolsIt a collection of allocationPools
+ */
+ public DefaultSubnet(SubnetId id, String subnetName,
+ TenantNetworkId networkId, TenantId tenantId,
+ Version ipVersion, IpPrefix cidr, IpAddress gatewayIp,
+ boolean dhcpEnabled, boolean shared,
+ Set<HostRoute> hostRoutes, Mode ipV6AddressMode,
+ Mode ipV6RaMode,
+ Set<AllocationPool> allocationPoolsIt) {
+ this.id = id;
+ this.subnetName = subnetName;
+ this.networkId = networkId;
+ this.tenantId = tenantId;
+ this.ipVersion = ipVersion;
+ this.cidr = cidr;
+ this.gatewayIp = gatewayIp;
+ this.dhcpEnabled = dhcpEnabled;
+ this.shared = shared;
+ this.ipV6AddressMode = ipV6AddressMode;
+ this.ipV6RaMode = ipV6RaMode;
+ this.hostRoutes = hostRoutes;
+ this.allocationPools = allocationPoolsIt;
+ }
+
+ @Override
+ public SubnetId id() {
+ return id;
+ }
+
+ @Override
+ public String subnetName() {
+ return subnetName;
+ }
+
+ @Override
+ public TenantNetworkId networkId() {
+ return networkId;
+ }
+
+ @Override
+ public TenantId tenantId() {
+ return tenantId;
+ }
+
+ @Override
+ public Version ipVersion() {
+ return ipVersion;
+ }
+
+ @Override
+ public IpPrefix cidr() {
+ return cidr;
+ }
+
+ @Override
+ public IpAddress gatewayIp() {
+ return gatewayIp;
+ }
+
+ @Override
+ public boolean dhcpEnabled() {
+ return dhcpEnabled;
+ }
+
+ @Override
+ public boolean shared() {
+ return shared;
+ }
+
+ @Override
+ public Iterable<HostRoute> hostRoutes() {
+ return hostRoutes;
+ }
+
+ @Override
+ public Mode ipV6AddressMode() {
+ return ipV6AddressMode;
+ }
+
+ @Override
+ public Mode ipV6RaMode() {
+ return ipV6RaMode;
+ }
+
+ @Override
+ public Iterable<AllocationPool> allocationPools() {
+ return allocationPools;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, subnetName, ipVersion, cidr, gatewayIp,
+ dhcpEnabled, shared, tenantId);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof DefaultSubnet) {
+ final DefaultSubnet that = (DefaultSubnet) obj;
+ return Objects.equals(this.id, that.id)
+ && Objects.equals(this.subnetName, that.subnetName)
+ && Objects.equals(this.ipVersion, that.ipVersion)
+ && Objects.equals(this.cidr, that.cidr)
+ && Objects.equals(this.shared, that.shared)
+ && Objects.equals(this.gatewayIp, that.gatewayIp)
+ && Objects.equals(this.dhcpEnabled, that.dhcpEnabled);
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(this).add("id", id).add("subnetName", subnetName)
+ .add("ipVersion", ipVersion).add("cidr", cidr)
+ .add("shared", shared).add("gatewayIp", gatewayIp)
+ .add("dhcpEnabled", dhcpEnabled).toString();
+ }
+
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultTenantNetwork.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultTenantNetwork.java
new file mode 100644
index 00000000..8c941ea2
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultTenantNetwork.java
@@ -0,0 +1,160 @@
+/*
+ * 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 java.util.Objects;
+
+/**
+ * Default implementation of TenantNetwork interface.
+ */
+public final class DefaultTenantNetwork implements TenantNetwork {
+ private final TenantNetworkId id;
+ private final String name;
+ private final boolean adminStateUp;
+ private final State state;
+ private final boolean shared;
+ private final Type type;
+ private final TenantId tenantId;
+ private final boolean routerExternal;
+ private final PhysicalNetwork physicalNetwork;
+ private final SegmentationId segmentationId;
+
+ /**
+ * Creates a neutronNetwork element attributed to the specified provider.
+ *
+ * @param id network identifier
+ * @param name the network name
+ * @param adminStateUp administrative state of the network
+ * @param state the network state
+ * @param shared indicates whether this network is shared across all
+ * tenants, By default, only administrative user can change this
+ * value
+ * @param tenantId tenant identifier
+ * @param routerExternal network routerExternal
+ * @param type the network type
+ * @param physicalNetwork physicalNetwork identifier
+ * @param segmentationId segmentation identifier
+ */
+ public DefaultTenantNetwork(TenantNetworkId id, String name,
+ boolean adminStateUp, State state,
+ boolean shared, TenantId tenantId,
+ boolean routerExternal, Type type,
+ PhysicalNetwork physicalNetwork,
+ SegmentationId segmentationId) {
+ this.id = id;
+ this.name = name;
+ this.adminStateUp = adminStateUp;
+ this.state = state;
+ this.shared = shared;
+ this.type = type;
+ this.tenantId = tenantId;
+ this.routerExternal = routerExternal;
+ this.physicalNetwork = physicalNetwork;
+ this.segmentationId = segmentationId;
+ }
+
+ @Override
+ public TenantNetworkId id() {
+ return id;
+ }
+
+ @Override
+ public String name() {
+ return name;
+ }
+
+ @Override
+ public boolean adminStateUp() {
+ return adminStateUp;
+ }
+
+ @Override
+ public State state() {
+ return state;
+ }
+
+ @Override
+ public boolean shared() {
+ return shared;
+ }
+
+ @Override
+ public TenantId tenantId() {
+ return tenantId;
+ }
+
+ @Override
+ public boolean routerExternal() {
+ return routerExternal;
+ }
+
+ @Override
+ public Type type() {
+ return type;
+ }
+
+ @Override
+ public PhysicalNetwork physicalNetwork() {
+ return physicalNetwork;
+ }
+
+ @Override
+ public SegmentationId segmentationId() {
+ return segmentationId;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, name, adminStateUp, state, shared, tenantId,
+ routerExternal, type, physicalNetwork,
+ segmentationId);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof DefaultTenantNetwork) {
+ final DefaultTenantNetwork that = (DefaultTenantNetwork) obj;
+ return Objects.equals(this.id, that.id)
+ && Objects.equals(this.name, that.name)
+ && Objects.equals(this.adminStateUp, that.adminStateUp)
+ && Objects.equals(this.state, that.state)
+ && Objects.equals(this.shared, that.shared)
+ && Objects.equals(this.tenantId, that.tenantId)
+ && Objects.equals(this.routerExternal, that.routerExternal)
+ && Objects.equals(this.type, that.type)
+ && Objects.equals(this.physicalNetwork,
+ that.physicalNetwork)
+ && Objects.equals(this.segmentationId, that.segmentationId);
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(this).add("id", id).add("name", name)
+ .add("adminStateUp", adminStateUp).add("state", state)
+ .add("shared", shared).add("tenantId", tenantId)
+ .add("routeExternal", routerExternal).add("type", type)
+ .add("physicalNetwork", physicalNetwork)
+ .add("segmentationId", segmentationId).toString();
+ }
+
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultVirtualPort.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultVirtualPort.java
new file mode 100644
index 00000000..9ee85da7
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultVirtualPort.java
@@ -0,0 +1,229 @@
+/*
+ * 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 java.util.Collection;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+import org.onlab.packet.MacAddress;
+import org.onosproject.net.DeviceId;
+
+/**
+ * Default implementation of VirtualPort interface .
+ */
+public final class DefaultVirtualPort implements VirtualPort {
+ private final VirtualPortId id;
+ private final TenantNetworkId networkId;
+ private final Boolean adminStateUp;
+ private final String name;
+ private final State state;
+ private final MacAddress macAddress;
+ private final TenantId tenantId;
+ private final String deviceOwner;
+ private final DeviceId deviceId;
+ private final Set<FixedIp> fixedIps;
+ private final BindingHostId bindingHostId;
+ private final String bindingVnicType;
+ private final String bindingVifType;
+ private final String bindingVifDetails;
+ private final Set<AllowedAddressPair> allowedAddressPairs;
+ private final Set<SecurityGroup> securityGroups;
+
+ /**
+ * Creates a VirtualPort object.
+ *
+ * @param id the virtual port identifier
+ * @param networkId the network identifier
+ * @param adminStateUp adminStateup true or false
+ * @param strMap the map of properties of virtual port
+ * @param state virtual port state
+ * @param macAddress the MAC address
+ * @param tenantId the tenant identifier
+ * @param deviceId the device identifier
+ * @param fixedIps set of fixed IP
+ * @param bindingHostId the binding host identifier
+ * @param allowedAddressPairs the collection of allowdeAddressPairs
+ * @param securityGroups the collection of securityGroups
+ */
+ public DefaultVirtualPort(VirtualPortId id,
+ TenantNetworkId networkId,
+ Boolean adminStateUp,
+ Map<String, String> strMap,
+ State state,
+ MacAddress macAddress,
+ TenantId tenantId,
+ DeviceId deviceId,
+ Set<FixedIp> fixedIps,
+ BindingHostId bindingHostId,
+ Set<AllowedAddressPair> allowedAddressPairs,
+ Set<SecurityGroup> securityGroups) {
+ this.id = id;
+ this.networkId = networkId;
+ this.adminStateUp = adminStateUp;
+ this.name = strMap.get("name");
+ this.state = state;
+ this.macAddress = macAddress;
+ this.tenantId = tenantId;
+ this.deviceOwner = strMap.get("deviceOwner");
+ this.deviceId = deviceId;
+ this.fixedIps = fixedIps;
+ this.bindingHostId = bindingHostId;
+ this.bindingVnicType = strMap.get("bindingVnicType");
+ this.bindingVifType = strMap.get("bindingVifType");
+ this.bindingVifDetails = strMap.get("bindingVifDetails");
+ this.allowedAddressPairs = allowedAddressPairs;
+ this.securityGroups = securityGroups;
+ }
+
+ @Override
+ public VirtualPortId portId() {
+ return id;
+ }
+
+ @Override
+ public TenantNetworkId networkId() {
+ return networkId;
+ }
+
+ @Override
+ public String name() {
+ return name;
+ }
+
+ @Override
+ public boolean adminStateUp() {
+ return adminStateUp;
+ }
+
+ @Override
+ public State state() {
+ return state;
+ }
+
+ @Override
+ public MacAddress macAddress() {
+ return macAddress;
+ }
+
+ @Override
+ public TenantId tenantId() {
+ return tenantId;
+ }
+
+ @Override
+ public DeviceId deviceId() {
+ return deviceId;
+ }
+
+ @Override
+ public String deviceOwner() {
+ return deviceOwner;
+ }
+
+ @Override
+ public Collection<AllowedAddressPair> allowedAddressPairs() {
+ return allowedAddressPairs;
+ }
+
+ @Override
+ public Set<FixedIp> fixedIps() {
+ return fixedIps;
+ }
+
+ @Override
+ public BindingHostId bindingHostId() {
+ return bindingHostId;
+ }
+
+ @Override
+ public String bindingVnicType() {
+ return bindingVifType;
+ }
+
+ @Override
+ public String bindingVifType() {
+ return bindingVifType;
+ }
+
+ @Override
+ public String bindingVifDetails() {
+ return bindingVifDetails;
+ }
+
+ @Override
+ public Collection<SecurityGroup> securityGroups() {
+ return securityGroups;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, networkId, adminStateUp, name, state,
+ macAddress, tenantId, deviceId, deviceOwner,
+ allowedAddressPairs, fixedIps, bindingHostId,
+ bindingVnicType, bindingVifType, bindingVifDetails,
+ securityGroups);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof DefaultVirtualPort) {
+ final DefaultVirtualPort that = (DefaultVirtualPort) obj;
+ return Objects.equals(this.id, that.id)
+ && Objects.equals(this.networkId, that.networkId)
+ && Objects.equals(this.adminStateUp, that.adminStateUp)
+ && Objects.equals(this.state, that.state)
+ && Objects.equals(this.name, that.name)
+ && Objects.equals(this.tenantId, that.tenantId)
+ && Objects.equals(this.macAddress, that.macAddress)
+ && Objects.equals(this.deviceId, that.deviceId)
+ && Objects.equals(this.deviceOwner, that.deviceOwner)
+ && Objects.equals(this.allowedAddressPairs,
+ that.allowedAddressPairs)
+ && Objects.equals(this.fixedIps, that.fixedIps)
+ && Objects.equals(this.bindingHostId, that.bindingHostId)
+ && Objects.equals(this.bindingVifDetails,
+ that.bindingVifDetails)
+ && Objects.equals(this.bindingVifType, that.bindingVifType)
+ && Objects.equals(this.bindingVnicType,
+ that.bindingVnicType)
+ && Objects.equals(this.securityGroups, that.securityGroups);
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(this).add("id", id).add("network_id", networkId)
+ .add("adminStateUp", adminStateUp).add("state", state)
+ .add("name", name).add("state", state)
+ .add("macAddress", macAddress).add("tenantId", tenantId)
+ .add("deviced", deviceId).add("deviceOwner", deviceOwner)
+ .add("allowedAddressPairs", allowedAddressPairs)
+ .add("fixedIp", fixedIps).add("bindingHostId", bindingHostId)
+ .add("bindingVnicType", bindingVnicType)
+ .add("bindingVifDetails", bindingVifDetails)
+ .add("bindingVifType", bindingVifType)
+ .add("securityGroups", securityGroups).toString();
+ }
+
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/FixedIp.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/FixedIp.java
new file mode 100644
index 00000000..c6569a7b
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/FixedIp.java
@@ -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.vtnrsc;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Objects;
+
+import org.onlab.packet.IpAddress;
+
+/**
+ * Immutable representation of a IP address for the port, Include the IP address
+ * and subnet identity.
+ */
+public final class FixedIp {
+ private final SubnetId subnetId;
+ private final IpAddress ip;
+ // Public construction is prohibited
+ private FixedIp(SubnetId subnetId, IpAddress ip) {
+ checkNotNull(subnetId, "SubnetId cannot be null");
+ checkNotNull(ip, "IpAddress cannot be null");
+ this.subnetId = subnetId;
+ this.ip = ip;
+ }
+
+ /**
+ * Returns the FixedIp subnet identifier.
+ *
+ * @return subnet identifier
+ */
+ public SubnetId subnetId() {
+ return subnetId;
+ }
+
+ /**
+ * Returns the FixedIp IP address.
+ *
+ * @return IP address
+ */
+ public IpAddress ip() {
+ return ip;
+ }
+
+ /**
+ * Creates a fixed ip using the supplied fixedIp.
+ *
+ * @param subnetId subnet identity
+ * @param ip IP address
+ * @return FixedIp
+ */
+ public static FixedIp fixedIp(SubnetId subnetId, IpAddress ip) {
+ return new FixedIp(subnetId, ip);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(subnetId, ip);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof FixedIp) {
+ final FixedIp that = (FixedIp) obj;
+ return Objects.equals(this.subnetId, that.subnetId)
+ && Objects.equals(this.ip, that.ip);
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(this).add("subnetId", subnetId).add("ip", ip)
+ .toString();
+ }
+
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/HostRoute.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/HostRoute.java
new file mode 100644
index 00000000..b18cb950
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/HostRoute.java
@@ -0,0 +1,39 @@
+/*
+ * 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.IpAddress;
+import org.onlab.packet.IpPrefix;
+
+/**
+ * Host route dictionaries for the subnet.
+ */
+public interface HostRoute {
+
+ /**
+ * Returns the next hop address.
+ *
+ * @return next hop address
+ */
+ IpAddress nexthop();
+
+ /**
+ * Returns the destination address.
+ *
+ * @return destination address
+ */
+ IpPrefix destination();
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PhysicalNetwork.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PhysicalNetwork.java
new file mode 100644
index 00000000..e96e666a
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PhysicalNetwork.java
@@ -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.vtnrsc;
+
+import java.util.Objects;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Immutable representation of a physical network identity.
+ */
+public final class PhysicalNetwork {
+
+ private final String physicalNetwork;
+
+ // Public construction is prohibited
+ private PhysicalNetwork(String physicalNetwork) {
+ checkNotNull(physicalNetwork, "PhysicalNetwork cannot be null");
+ this.physicalNetwork = physicalNetwork;
+ }
+
+ /**
+ * Creates a PhysicalNetwork object.
+ *
+ * @param physicalNetwork physical network
+ * @return physical network
+ */
+ public static PhysicalNetwork physicalNetwork(String physicalNetwork) {
+ return new PhysicalNetwork(physicalNetwork);
+ }
+
+ /**
+ * Returns a physicalNetwork.
+ *
+ * @return physical network
+ */
+ public String physicalNetwork() {
+ return physicalNetwork;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(physicalNetwork);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof PhysicalNetwork) {
+ final PhysicalNetwork that = (PhysicalNetwork) obj;
+ return this.getClass() == that.getClass()
+ && Objects.equals(this.physicalNetwork,
+ that.physicalNetwork);
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return physicalNetwork;
+ }
+
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/SecurityGroup.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/SecurityGroup.java
new file mode 100644
index 00000000..9ec1dc63
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/SecurityGroup.java
@@ -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.vtnrsc;
+
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Immutable representation of a security group.
+ */
+public final class SecurityGroup {
+ private final String securityGroup;
+
+ /**
+ * Returns the securityGroup.
+ *
+ * @return securityGroup
+ */
+ public String securityGroup() {
+ return securityGroup;
+ }
+ // Public construction is prohibited
+ private SecurityGroup(String securityGroup) {
+ checkNotNull(securityGroup, "SecurityGroup cannot be null");
+ this.securityGroup = securityGroup;
+ }
+
+ /**
+ * Creates a securityGroup using the supplied securityGroup.
+ *
+ * @param securityGroup security group
+ * @return securityGroup
+ */
+ public static SecurityGroup securityGroup(String securityGroup) {
+ return new SecurityGroup(securityGroup);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(securityGroup);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof SecurityGroup) {
+ final SecurityGroup that = (SecurityGroup) obj;
+ return this.getClass() == that.getClass()
+ && Objects.equals(this.securityGroup, that.securityGroup);
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(this).add("securityGroup", securityGroup)
+ .toString();
+ }
+
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/SegmentationId.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/SegmentationId.java
new file mode 100644
index 00000000..a076265f
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/SegmentationId.java
@@ -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.vtnrsc;
+
+import java.util.Objects;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Immutable representation of a Segmentation identifier.
+ */
+public final class SegmentationId {
+
+ private final String segmentationId;
+
+ // Public construction is prohibited
+ private SegmentationId(String segmentationId) {
+ checkNotNull(segmentationId, "SegmentationId cannot be null");
+ this.segmentationId = segmentationId;
+ }
+
+ /**
+ * Creates a SegmentationId object.
+ *
+ * @param segmentationId segmentation identifier
+ * @return SegmentationId
+ */
+ public static SegmentationId segmentationId(String segmentationId) {
+ return new SegmentationId(segmentationId);
+ }
+
+ /**
+ * Returns the segmentation identifier.
+ *
+ * @return segmentationId
+ */
+ public String segmentationId() {
+ return segmentationId;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(segmentationId);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof SegmentationId) {
+ final SegmentationId that = (SegmentationId) obj;
+ return this.getClass() == that.getClass()
+ && Objects.equals(this.segmentationId, that.segmentationId);
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return segmentationId;
+ }
+
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/Subnet.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/Subnet.java
new file mode 100644
index 00000000..f563a78f
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/Subnet.java
@@ -0,0 +1,129 @@
+/*
+ * 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.IpAddress;
+import org.onlab.packet.IpAddress.Version;
+import org.onlab.packet.IpPrefix;
+
+/**
+ * Representation of a subnet.
+ */
+public interface Subnet {
+
+ /**
+ * Coarse classification of the type of the ipV6Mode.
+ */
+ enum Mode {
+ DHCPV6_STATEFUL, DHCPV6_STATELESS, SLAAC
+ }
+
+ /**
+ * Returns the subnet identifier.
+ *
+ * @return identifier
+ */
+ SubnetId id();
+
+ /**
+ * Returns the name of the subnet.
+ *
+ * @return subnetName
+ */
+ String subnetName();
+
+ /**
+ * Returns the network identifier.
+ *
+ * @return the network identifier
+ */
+ TenantNetworkId networkId();
+
+ /**
+ * Returns tenant identifier.
+ *
+ * @return the tenant identifier
+ */
+ TenantId tenantId();
+
+ /**
+ * Returns the IP version, which is 4 or 6.
+ *
+ * @return ipVersion
+ */
+ Version ipVersion();
+
+ /**
+ * Returns the cidr.
+ *
+ * @return cidr
+ */
+ IpPrefix cidr();
+
+ /**
+ * Returns the gateway IP address.
+ *
+ * @return gatewayIp
+ */
+ IpAddress gatewayIp();
+
+ /**
+ * Returns true if DHCP is enabled and return false if DHCP is disabled.
+ *
+ * @return true or false
+ */
+ boolean dhcpEnabled();
+
+ /**
+ * Indicates whether this tenantNetwork is shared across all tenants. By
+ * default, only administrative user can change this value.
+ *
+ * @return true or false
+ */
+ boolean shared();
+
+ /**
+ * Returns a collection of hostRoutes.
+ *
+ * @return a collection of hostRoutes
+ */
+ Iterable<HostRoute> hostRoutes();
+
+ /**
+ * Returns the ipV6AddressMode. A valid value is dhcpv6-stateful,
+ * dhcpv6-stateless, or slaac.
+ *
+ * @return ipV6AddressMode whose value is dhcpv6-stateful, dhcpv6-stateless
+ * or slaac
+ */
+ Mode ipV6AddressMode();
+
+ /**
+ * Returns the ipV6RaMode.A valid value is dhcpv6-stateful,
+ * dhcpv6-stateless, or slaac.
+ *
+ * @return ipV6RaMode whose value is dhcpv6-stateful, dhcpv6-stateless or
+ * slaac
+ */
+ Mode ipV6RaMode();
+
+ /**
+ * Returns a collection of allocation_pools.
+ *
+ * @return a collection of allocationPools
+ */
+ Iterable<AllocationPool> allocationPools();
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/SubnetId.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/SubnetId.java
new file mode 100644
index 00000000..4bcc3329
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/SubnetId.java
@@ -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;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Objects;
+
+/**
+ * Immutable representation of a subnet identifier.
+ */
+public final class SubnetId {
+
+ private final String subnetId;
+
+ // Public construction is prohibited
+ private SubnetId(String subnetId) {
+ checkNotNull(subnetId, "SubnetId cannot be null");
+ this.subnetId = subnetId;
+ }
+
+ /**
+ * Creates a Subnet identifier.
+ *
+ * @param subnetId the subnet identifier
+ * @return the subnet identifier
+ */
+ public static SubnetId subnetId(String subnetId) {
+ return new SubnetId(subnetId);
+ }
+
+ /**
+ * Returns the subnet identifier.
+ *
+ * @return the subnet identifier
+ */
+ public String subnetId() {
+ return subnetId;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(subnetId);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof SubnetId) {
+ final SubnetId that = (SubnetId) obj;
+ return this.getClass() == that.getClass()
+ && Objects.equals(this.subnetId, that.subnetId);
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return subnetId;
+ }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/TenantId.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/TenantId.java
new file mode 100644
index 00000000..c4d99e49
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/TenantId.java
@@ -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.vtnrsc;
+
+import java.util.Objects;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Immutable representation of a tenant identifier.
+ */
+public final class TenantId {
+
+ private final String tenantId;
+
+ // Public construction is prohibited
+ private TenantId(String tenantId) {
+ this.tenantId = tenantId;
+ }
+
+ /**
+ * Creates a network id using the tenantid.
+ *
+ * @param tenantid network String
+ * @return TenantId
+ */
+ public static TenantId tenantId(String tenantid) {
+ checkNotNull(tenantid, "Tenantid can not be null");
+ return new TenantId(tenantid);
+ }
+
+ /**
+ * Returns the tenant identifier.
+ *
+ * @return the tenant identifier
+ */
+ public String tenantId() {
+ return tenantId;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(tenantId);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof TenantId) {
+ final TenantId that = (TenantId) obj;
+ return this.getClass() == that.getClass()
+ && Objects.equals(this.tenantId, that.tenantId);
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return tenantId;
+ }
+
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/TenantNetwork.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/TenantNetwork.java
new file mode 100644
index 00000000..256352f4
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/TenantNetwork.java
@@ -0,0 +1,130 @@
+/*
+ * 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;
+
+/**
+ * Representation of the tenantNetwork.
+ */
+public interface TenantNetwork {
+
+ /**
+ * Coarse classification of the state of the tenantNetwork.
+ */
+ enum State {
+ /**
+ * Signifies that a tenantNetwork is currently active.This state means
+ * that this network is available.
+ */
+ ACTIVE,
+ /**
+ * Signifies that a tenantNetwork is currently built.
+ */
+ BUILD,
+ /**
+ * Signifies that a tenantNetwork is currently unavailable.
+ */
+ DOWN,
+ /**
+ * Signifies that a tenantNetwork is currently error.
+ */
+ ERROR
+ }
+
+ /**
+ * Coarse classification of the type of the tenantNetwork.
+ */
+ enum Type {
+ /**
+ * Signifies that a tenantNetwork is local.
+ */
+ LOCAL
+ }
+
+ /**
+ * Returns the tenantNetwork identifier.
+ *
+ * @return tenantNetwork identifier
+ */
+ TenantNetworkId id();
+
+ /**
+ * Returns the tenantNetwork name.
+ *
+ * @return tenantNetwork name
+ */
+ String name();
+
+ /**
+ * Returns the administrative state of the tenantNetwork,which is up(true)
+ * or down(false).
+ *
+ * @return true or false
+ */
+ boolean adminStateUp();
+
+ /**
+ * Returns the tenantNetwork state.
+ *
+ * @return tenant network state
+ */
+ State state();
+
+ /**
+ * Indicates whether this tenantNetwork is shared across all tenants. By
+ * default,only administrative user can change this value.
+ *
+ * @return true or false
+ */
+ boolean shared();
+
+ /**
+ * Returns the UUID of the tenant that will own the tenantNetwork. This
+ * tenant can be different from the tenant that makes the create
+ * tenantNetwork request.
+ *
+ * @return the tenant identifier
+ */
+ TenantId tenantId();
+
+ /**
+ * Returns the routerExternal.Indicates whether this network is externally
+ * accessible.
+ *
+ * @return true or false
+ */
+ boolean routerExternal();
+
+ /**
+ * Returns the tenantNetwork Type.
+ *
+ * @return tenantNetwork Type
+ */
+ Type type();
+
+ /**
+ * Returns the tenantNetwork physical network.
+ *
+ * @return tenantNetwork physical network
+ */
+ PhysicalNetwork physicalNetwork();
+
+ /**
+ * Returns the tenantNetwork segmentation id.
+ *
+ * @return tenantNetwork segmentation id
+ */
+ SegmentationId segmentationId();
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/TenantNetworkId.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/TenantNetworkId.java
new file mode 100644
index 00000000..fbb9e480
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/TenantNetworkId.java
@@ -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;
+
+import java.util.Objects;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Immutable representation of a tenantNetwork identity.
+ */
+public final class TenantNetworkId {
+
+ private final String networkId;
+
+ // Public construction is prohibited
+ private TenantNetworkId(String networkId) {
+ this.networkId = networkId;
+ }
+
+ /**
+ * Creates a TenantNetwork identifier.
+ *
+ * @param networkId tenantNetwork identify string
+ * @return the attached tenantNetwork identifier
+ */
+ public static TenantNetworkId networkId(String networkId) {
+ checkNotNull(networkId, "Networkid cannot be null");
+ return new TenantNetworkId(networkId);
+ }
+
+ /**
+ * Returns tenantNetwork identifier.
+ *
+ * @return the tenantNetwork identifier
+ */
+ public String networkId() {
+ return networkId;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(networkId);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof TenantNetworkId) {
+ final TenantNetworkId that = (TenantNetworkId) obj;
+ return this.getClass() == that.getClass()
+ && Objects.equals(this.networkId, that.networkId);
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return networkId;
+ }
+
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/VirtualPort.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/VirtualPort.java
new file mode 100644
index 00000000..d2d7c146
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/VirtualPort.java
@@ -0,0 +1,156 @@
+/*
+ * 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.Collection;
+import java.util.Set;
+
+import org.onlab.packet.MacAddress;
+import org.onosproject.net.DeviceId;
+
+/**
+ * Representation of the VirtualPort.
+ */
+public interface VirtualPort {
+ /**
+ * Coarse classification of the type of the virtual port.
+ */
+ enum State {
+ /**
+ * Signifies that a virtualPort is currently active,This state mean that
+ * this virtualPort is available.
+ */
+ ACTIVE,
+ /**
+ * Signifies that a virtualPort is currently unavailable.
+ */
+ DOWN;
+ }
+
+ /**
+ * Returns the virtualPort identifier.
+ *
+ * @return virtualPort identifier
+ */
+ VirtualPortId portId();
+
+ /**
+ * Returns the network identifier.
+ *
+ * @return tenantNetwork identifier
+ */
+ TenantNetworkId networkId();
+
+ /**
+ * Returns the symbolic name for the virtualPort.
+ *
+ * @return virtualPort name
+ */
+ String name();
+
+ /**
+ * Returns the administrative status of the port,which is up(true) or
+ * down(false).
+ *
+ * @return true if the administrative status of the port is up
+ */
+ boolean adminStateUp();
+
+ /**
+ * Returns the state.
+ *
+ * @return state
+ */
+ State state();
+
+ /**
+ * Returns the MAC address.
+ *
+ * @return MAC Address
+ */
+ MacAddress macAddress();
+
+ /**
+ * Returns the port tenantId.
+ *
+ * @return port tenantId
+ */
+ TenantId tenantId();
+
+ /**
+ * Returns the device identifier.
+ *
+ * @return deviceId
+ */
+ DeviceId deviceId();
+
+ /**
+ * Returns the identifier of the entity that uses this port.
+ *
+ * @return deviceOwner
+ */
+ String deviceOwner();
+
+ /**
+ * Returns the virtualPort allowedAddressPairs.
+ *
+ * @return virtualPort allowedAddressPairs
+ */
+ Collection<AllowedAddressPair> allowedAddressPairs();
+
+ /**
+ * Returns set of IP addresses for the port, include the IP addresses and subnet
+ * identity.
+ *
+ * @return FixedIps Set of fixedIp
+ */
+ Set<FixedIp> fixedIps();
+
+ /**
+ * Returns the virtualPort bindinghostId.
+ *
+ * @return virtualPort bindinghostId
+ */
+ BindingHostId bindingHostId();
+
+ /**
+ * Returns the virtualPort bindingVnicType.
+ *
+ * @return virtualPort bindingVnicType
+ */
+ String bindingVnicType();
+
+ /**
+ * Returns the virtualPort bindingVifType.
+ *
+ * @return virtualPort bindingVifType
+ */
+ String bindingVifType();
+
+ /**
+ * Returns the virtualPort bindingvifDetail.
+ *
+ * @return virtualPort bindingvifDetail
+ */
+ String bindingVifDetails();
+
+ /**
+ * Returns the security groups.
+ *
+ * @return port security groups
+ */
+ Iterable<SecurityGroup> securityGroups();
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/VirtualPortId.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/VirtualPortId.java
new file mode 100644
index 00000000..3038bdff
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/VirtualPortId.java
@@ -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.
+ */
+package org.onosproject.vtnrsc;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Objects;
+
+/**
+ * Immutable representation of a virtual port identifier.
+ */
+public final class VirtualPortId {
+ private final String portId;
+ // Public construction is prohibited
+ private VirtualPortId(String virtualPortId) {
+ checkNotNull(virtualPortId, "VirtualPortId cannot be null");
+ this.portId = virtualPortId;
+ }
+
+ public String portId() {
+ return portId;
+ }
+
+ /**
+ * Creates a virtualPort id using the supplied portId.
+ *
+ * @param portId virtualport identifier
+ * @return VirtualPortId
+ */
+ public static VirtualPortId portId(String portId) {
+ return new VirtualPortId(portId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(portId);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof VirtualPortId) {
+ final VirtualPortId that = (VirtualPortId) obj;
+ return this.getClass() == that.getClass()
+ && Objects.equals(this.portId, that.portId);
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return portId;
+ }
+
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/network/TenantNetworkCreateCommand.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/network/TenantNetworkCreateCommand.java
new file mode 100644
index 00000000..bcfdacfa
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/network/TenantNetworkCreateCommand.java
@@ -0,0 +1,97 @@
+/*
+ * 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.cli.network;
+
+import java.util.Set;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.shell.commands.Option;
+import org.onosproject.cli.AbstractShellCommand;
+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 org.onosproject.vtnrsc.tenantnetwork.TenantNetworkService;
+
+import com.google.common.collect.Sets;
+
+/**
+ * Supports for creating a TenantNetwork.
+ */
+@Command(scope = "onos", name = "tenantnetwork-create",
+ description = "Supports for creating a TenantNetwork")
+public class TenantNetworkCreateCommand extends AbstractShellCommand {
+
+ @Argument(index = 0, name = "id", description = "TenantNetwork network id", required = true,
+ multiValued = false)
+ String id = null;
+
+ @Argument(index = 1, name = "tenantID", description = "The tenant id of TenantNetwork",
+ required = true, multiValued = false)
+ String tenantID = null;
+
+ @Argument(index = 2, name = "type", description = "The type of TenantNetwork", required = true,
+ multiValued = false)
+ String type = null;
+
+ @Argument(index = 3, name = "segmentationID", description = "The segmentation id of TenantNetwork",
+ required = true, multiValued = false)
+ String segmentationID = "";
+
+ @Option(name = "-n", aliases = "--name", description = "TenantNetwork name", required = false,
+ multiValued = false)
+ String name = null;
+
+ @Option(name = "-a", aliases = "--adminStateUp", description = "TenantNetwork adminStateUp is true or false",
+ required = false, multiValued = false)
+ boolean adminStateUp = false;
+
+ @Option(name = "-s", aliases = "--state", description = "The state of TenantNetwork",
+ required = false, multiValued = false)
+ String state = null;
+
+ @Option(name = "-d", aliases = "--shared", description = "TenantNetwork is shared or not",
+ required = false, multiValued = false)
+ boolean shared = false;
+
+ @Option(name = "-r", aliases = "--routerExternal",
+ description = "TenantNetwork is routerExternal or not", required = false,
+ multiValued = false)
+ boolean routerExternal = false;
+
+ @Option(name = "-p", aliases = "--physicalNetwork", description = "The physical network of Tenant",
+ required = false, multiValued = false)
+ String physicalNetwork = "";
+
+ @Override
+ protected void execute() {
+ TenantNetworkService service = get(TenantNetworkService.class);
+ TenantNetwork network = new DefaultTenantNetwork(TenantNetworkId.networkId(id), name,
+ adminStateUp,
+ TenantNetwork.State.valueOf(state),
+ shared, TenantId.tenantId(tenantID),
+ routerExternal,
+ TenantNetwork.Type.valueOf(type),
+ PhysicalNetwork.physicalNetwork(physicalNetwork),
+ SegmentationId.segmentationId(segmentationID));
+
+ Set<TenantNetwork> networksSet = Sets.newHashSet(network);
+ service.createNetworks(networksSet);
+ }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/network/TenantNetworkQueryCommand.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/network/TenantNetworkQueryCommand.java
new file mode 100644
index 00000000..47ea83c2
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/network/TenantNetworkQueryCommand.java
@@ -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.vtnrsc.cli.network;
+
+import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.shell.commands.Option;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.vtnrsc.TenantNetwork;
+import org.onosproject.vtnrsc.TenantNetworkId;
+import org.onosproject.vtnrsc.tenantnetwork.TenantNetworkService;
+
+/**
+ * Supports for querying TenantNetworks by network id.
+ */
+@Command(scope = "onos", name = "tenantnetworks", description = "Supports for querying"
+ + "tenantNetworks by networkid")
+public class TenantNetworkQueryCommand extends AbstractShellCommand {
+
+ @Option(name = "-i", aliases = "--id", description = "TenantNetwork id", required = false,
+ multiValued = false)
+ String id = null;
+
+ private static final String FMT = "networkId=%s, networkName=%s, segmentationId=%s,"
+ + "tenantId=%s, type=%s, adminStateUp=%s";
+
+ @Override
+ protected void execute() {
+ TenantNetworkService service = get(TenantNetworkService.class);
+ if (id != null) {
+ TenantNetwork network = service.getNetwork(TenantNetworkId.networkId(id));
+ printNetwork(network);
+ } else {
+ Iterable<TenantNetwork> networks = service.getNetworks();
+ for (TenantNetwork network : networks) {
+ printNetwork(network);
+ }
+ }
+ }
+
+ private void printNetwork(TenantNetwork network) {
+ if (network == null) {
+ return;
+ }
+ print(FMT, network.id(), network.name(), network.segmentationId(),
+ network.tenantId(), network.type(), network.adminStateUp());
+ }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/network/TenantNetworkRemoveCommand.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/network/TenantNetworkRemoveCommand.java
new file mode 100644
index 00000000..0ea22853
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/network/TenantNetworkRemoveCommand.java
@@ -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.vtnrsc.cli.network;
+
+import java.util.Set;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.vtnrsc.TenantNetworkId;
+import org.onosproject.vtnrsc.tenantnetwork.TenantNetworkService;
+
+import com.google.common.collect.Sets;
+
+/**
+ * Supports for removing a TenantNetwork by network id.
+ */
+@Command(scope = "onos", name = "tenantnetwork-remove", description = "Supports for removing"
+ + " a tenantNetwork by tenantNetworkid")
+public class TenantNetworkRemoveCommand extends AbstractShellCommand {
+
+ @Argument(index = 0, name = "id", description = "TenantNetwork neutronNetwork Id",
+ required = true, multiValued = false)
+ String id = null;
+
+ @Override
+ protected void execute() {
+ TenantNetworkService service = get(TenantNetworkService.class);
+ Set<TenantNetworkId> networkIds = Sets.newHashSet(TenantNetworkId.networkId(id));
+ service.removeNetworks(networkIds);
+ }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/network/TenantNetworkUpdateCommand.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/network/TenantNetworkUpdateCommand.java
new file mode 100644
index 00000000..2a738f72
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/network/TenantNetworkUpdateCommand.java
@@ -0,0 +1,99 @@
+/*
+ * 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.cli.network;
+
+import java.util.Set;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.shell.commands.Option;
+import org.onosproject.cli.AbstractShellCommand;
+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 org.onosproject.vtnrsc.tenantnetwork.TenantNetworkService;
+
+import com.google.common.collect.Sets;
+
+/**
+ * Supports for updating a TenantNetwork.
+ */
+@Command(scope = "onos", name = "tenantnetwork-update",
+ description = "Supports for updating a TenantNetwork")
+public class TenantNetworkUpdateCommand extends AbstractShellCommand {
+
+ @Argument(index = 0, name = "id", description = "TenantNetwork network id", required = true,
+ multiValued = false)
+ String id = null;
+
+ @Argument(index = 1, name = "tenantID", description = "The tenant id of TenantNetwork",
+ required = true, multiValued = false)
+ String tenantID = null;
+
+ @Argument(index = 2, name = "type", description = "The type of TenantNetwork", required = true,
+ multiValued = false)
+ String type = null;
+
+ @Argument(index = 3, name = "segmentationID", description = "The segmentation id of TenantNetwork",
+ required = true, multiValued = false)
+ String segmentationID = "";
+
+ @Option(name = "-n", aliases = "--name", description = "TenantNetwork name", required = false,
+ multiValued = false)
+ String name = null;
+
+ @Option(name = "-a", aliases = "--adminStateUp", description = "TenantNetwork adminStateUp is true or false",
+ required = false, multiValued = false)
+ boolean adminStateUp = false;
+
+ @Option(name = "-s", aliases = "--state", description = "The state of TenantNetwork",
+ required = false, multiValued = false)
+ String state = null;
+
+ @Option(name = "-d", aliases = "--shared", description = "TenantNetwork is shared or not",
+ required = false, multiValued = false)
+ boolean shared = false;
+
+ @Option(name = "-r", aliases = "--routerExternal",
+ description = "TenantNetwork is routerExternal or not", required = false,
+ multiValued = false)
+ boolean routerExternal = false;
+
+ @Option(name = "-p", aliases = "--physicalNetwork", description = "The physical network of Tenant",
+ required = false, multiValued = false)
+ String physicalNetwork = "";
+
+ @Override
+ protected void execute() {
+ TenantNetworkService service = get(TenantNetworkService.class);
+ TenantNetwork network = new DefaultTenantNetwork(TenantNetworkId.networkId(id), name,
+ adminStateUp,
+ TenantNetwork.State.valueOf(state),
+ shared, TenantId.tenantId(tenantID),
+ routerExternal,
+ TenantNetwork.Type.valueOf(type),
+ PhysicalNetwork.physicalNetwork(physicalNetwork),
+ SegmentationId.segmentationId(segmentationID));
+
+ Set<TenantNetwork> networksSet = Sets.newHashSet();
+ networksSet.add(network);
+ service.updateNetworks(networksSet);
+ }
+
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/network/package-info.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/network/package-info.java
new file mode 100644
index 00000000..1622c800
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/network/package-info.java
@@ -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.
+ */
+
+/**
+ * Command line interface for tenant networks.
+ */
+package org.onosproject.vtnrsc.cli.network;
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/subnet/SubnetCreateCommand.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/subnet/SubnetCreateCommand.java
new file mode 100644
index 00000000..56236408
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/subnet/SubnetCreateCommand.java
@@ -0,0 +1,118 @@
+/*
+ * 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.cli.subnet;
+
+import java.util.Set;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.shell.commands.Option;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpAddress.Version;
+import org.onlab.packet.IpPrefix;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.vtnrsc.AllocationPool;
+import org.onosproject.vtnrsc.DefaultSubnet;
+import org.onosproject.vtnrsc.HostRoute;
+import org.onosproject.vtnrsc.Subnet;
+import org.onosproject.vtnrsc.Subnet.Mode;
+import org.onosproject.vtnrsc.SubnetId;
+import org.onosproject.vtnrsc.TenantId;
+import org.onosproject.vtnrsc.TenantNetworkId;
+import org.onosproject.vtnrsc.subnet.SubnetService;
+
+import com.google.common.collect.Sets;
+
+/**
+ * Supports for creating a subnet.
+ */
+@Command(scope = "onos", name = "subnet-create", description = "Supports for creating a subnet")
+public class SubnetCreateCommand extends AbstractShellCommand {
+
+ @Argument(index = 0, name = "id", description = "Subnet Id", required = true,
+ multiValued = false)
+ String id = null;
+
+ @Argument(index = 1, name = "subnetName", description = "Subnet String name", required = true,
+ multiValued = false)
+ String subnetName = null;
+
+ @Argument(index = 2, name = "networkId", description = "Subnet Network Id", required = true,
+ multiValued = false)
+ String networkId = null;
+
+ @Argument(index = 3, name = "tenantId", description = "Subnet Tenant Id", required = true,
+ multiValued = false)
+ String tenantId = null;
+
+ @Option(name = "-i", aliases = "--ipVersion", description = "Subnet Version ipVersion",
+ required = false, multiValued = false)
+ Version ipVersion = null;
+
+ @Option(name = "-c", aliases = "--cidr", description = "Subnet IpPrefix cidr",
+ required = false, multiValued = false)
+ String cidr = "0.0.0.0/0";
+
+ @Option(name = "-g", aliases = "--gatewayIp", description = "Subnet IpAddress gatewayIp",
+ required = false, multiValued = false)
+ String gatewayIp = "0.0.0.0";
+
+ @Option(name = "-d", aliases = "--dhcpEnabled", description = "Subnet boolean dhcpEnabled",
+ required = false, multiValued = false)
+ boolean dhcpEnabled = false;
+
+ @Option(name = "-s", aliases = "--shared", description = "Subnet boolean shared",
+ required = false, multiValued = false)
+ boolean shared = false;
+
+ @Option(name = "-m", aliases = "--ipV6AddressMode",
+ description = "Subnet Mode ipV6AddressMode", required = false, multiValued = false)
+ String ipV6AddressMode = null;
+
+ @Option(name = "-r", aliases = "--ipV6RaMode", description = "Subnet Mode ipV6RaMode",
+ required = false, multiValued = false)
+ String ipV6RaMode = null;
+
+ @Option(name = "-h", aliases = "--hostRoutes", description = "Subnet jsonnode hostRoutes",
+ required = false, multiValued = false)
+ Set<HostRoute> hostRoutes = Sets.newHashSet();
+
+ @Option(name = "-a", aliases = "--allocationPools",
+ description = "Subnet jsonnode allocationPools", required = false, multiValued = false)
+ Set<AllocationPool> allocationPools = Sets.newHashSet();
+
+ @Override
+ protected void execute() {
+ SubnetService service = get(SubnetService.class);
+ if (id == null || networkId == null || tenantId == null) {
+ print(null, "id,networkId,tenantId can not be null");
+ return;
+ }
+ Subnet subnet = new DefaultSubnet(SubnetId.subnetId(id), subnetName,
+ TenantNetworkId.networkId(networkId),
+ TenantId.tenantId(tenantId), ipVersion,
+ cidr == null ? null : IpPrefix.valueOf(cidr),
+ gatewayIp == null ? null : IpAddress.valueOf(gatewayIp),
+ dhcpEnabled, shared, hostRoutes,
+ ipV6AddressMode == null ? null : Mode.valueOf(ipV6AddressMode),
+ ipV6RaMode == null ? null : Mode.valueOf(ipV6RaMode),
+ allocationPools);
+
+ Set<Subnet> subnetsSet = Sets.newHashSet(subnet);
+ service.createSubnets(subnetsSet);
+ }
+
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/subnet/SubnetQueryCommand.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/subnet/SubnetQueryCommand.java
new file mode 100644
index 00000000..f5a94f0f
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/subnet/SubnetQueryCommand.java
@@ -0,0 +1,61 @@
+/*
+ * 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.cli.subnet;
+
+import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.shell.commands.Option;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.vtnrsc.Subnet;
+import org.onosproject.vtnrsc.SubnetId;
+import org.onosproject.vtnrsc.subnet.SubnetService;
+
+/**
+ * Supports for querying a subnet.
+ */
+@Command(scope = "onos", name = "subnets", description = "Supports for querying a subnet")
+public class SubnetQueryCommand extends AbstractShellCommand {
+
+ @Option(name = "-i", aliases = "--id", description = "Subnet id", required = false,
+ multiValued = false)
+ String id = null;
+
+ private static final String FMT = "subnetId=%s, networkId=%s, subnetName=%s,"
+ + "tenantId=%s, cidr=%s, dhcpEnabled=%s, gatewayIp=%s," + "ipVersion=%s";
+
+ @Override
+ protected void execute() {
+ SubnetService service = get(SubnetService.class);
+ if (id != null) {
+ Subnet subnet = service.getSubnet(SubnetId.subnetId(id));
+ printSubnet(subnet);
+ } else {
+ Iterable<Subnet> subnets = service.getSubnets();
+ if (subnets == null) {
+ return;
+ }
+ for (Subnet subnet : subnets) {
+ printSubnet(subnet);
+ }
+ }
+ }
+
+ private void printSubnet(Subnet subnet) {
+ print(FMT, subnet.id(), subnet.networkId(), subnet.subnetName(),
+ subnet.tenantId(), subnet.cidr(), subnet.dhcpEnabled(), subnet
+ .gatewayIp(), subnet.ipVersion());
+
+ }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/subnet/SubnetRemoveCommand.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/subnet/SubnetRemoveCommand.java
new file mode 100644
index 00000000..241af87e
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/subnet/SubnetRemoveCommand.java
@@ -0,0 +1,46 @@
+/*
+ * 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.cli.subnet;
+
+import java.util.Set;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.vtnrsc.SubnetId;
+import org.onosproject.vtnrsc.subnet.SubnetService;
+
+import com.google.common.collect.Sets;
+
+/**
+ * Supports for removing a subnet.
+ */
+@Command(scope = "onos", name = "subnet-remove", description = "Supports for removing a subnet")
+public class SubnetRemoveCommand extends AbstractShellCommand {
+
+ @Argument(index = 0, name = "id", description = "Subnet SubnetId Id", required = true,
+ multiValued = false)
+ String id = null;
+
+ @Override
+ protected void execute() {
+ SubnetService service = get(SubnetService.class);
+ Set<SubnetId> subnetsSet = Sets.newHashSet();
+ subnetsSet.add(SubnetId.subnetId(id));
+ service.removeSubnets(subnetsSet);
+ }
+
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/subnet/SubnetUpdateCommand.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/subnet/SubnetUpdateCommand.java
new file mode 100644
index 00000000..b0578a1e
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/subnet/SubnetUpdateCommand.java
@@ -0,0 +1,118 @@
+/*
+ * 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.cli.subnet;
+
+import java.util.Set;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.shell.commands.Option;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpAddress.Version;
+import org.onlab.packet.IpPrefix;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.vtnrsc.AllocationPool;
+import org.onosproject.vtnrsc.DefaultSubnet;
+import org.onosproject.vtnrsc.HostRoute;
+import org.onosproject.vtnrsc.Subnet;
+import org.onosproject.vtnrsc.Subnet.Mode;
+import org.onosproject.vtnrsc.SubnetId;
+import org.onosproject.vtnrsc.TenantId;
+import org.onosproject.vtnrsc.TenantNetworkId;
+import org.onosproject.vtnrsc.subnet.SubnetService;
+
+import com.google.common.collect.Sets;
+
+/**
+ * Supports for updating a subnet.
+ */
+@Command(scope = "onos", name = "subnet-update", description = "Supports for updating a subnet")
+public class SubnetUpdateCommand extends AbstractShellCommand {
+
+ @Argument(index = 0, name = "id", description = "Subnet Id", required = true,
+ multiValued = false)
+ String id = null;
+
+ @Argument(index = 1, name = "subnetName", description = "Subnet String name", required = true,
+ multiValued = false)
+ String subnetName = null;
+
+ @Argument(index = 2, name = "networkId", description = "Subnet Network Id", required = true,
+ multiValued = false)
+ String networkId = null;
+
+ @Argument(index = 3, name = "tenantId", description = "Subnet Tenant Id", required = true,
+ multiValued = false)
+ String tenantId = null;
+
+ @Option(name = "-i", aliases = "--ipVersion", description = "Subnet Version ipVersion",
+ required = false, multiValued = false)
+ Version ipVersion = null;
+
+ @Option(name = "-c", aliases = "--cidr", description = "Subnet IpPrefix cidr", required = false,
+ multiValued = false)
+ String cidr = "0.0.0.0/0";
+
+ @Option(name = "-g", aliases = "--gatewayIp", description = "Subnet IpAddress gatewayIp",
+ required = false, multiValued = false)
+ String gatewayIp = "0.0.0.0";
+
+ @Option(name = "-d", aliases = "--dhcpEnabled", description = "Subnet boolean dhcpEnabled",
+ required = false, multiValued = false)
+ boolean dhcpEnabled = false;
+
+ @Option(name = "-s", aliases = "--shared", description = "Subnet boolean shared", required = false,
+ multiValued = false)
+ boolean shared = false;
+
+ @Option(name = "-m", aliases = "--ipV6AddressMode", description = "Subnet Mode ipV6AddressMode",
+ required = false, multiValued = false)
+ String ipV6AddressMode = null;
+
+ @Option(name = "-r", aliases = "--ipV6RaMode", description = "Subnet Mode ipV6RaMode",
+ required = false, multiValued = false)
+ String ipV6RaMode = null;
+
+ @Option(name = "-h", aliases = "--hostRoutes", description = "Subnet jsonnode hostRoutes",
+ required = false, multiValued = false)
+ Set<HostRoute> hostRoutes = Sets.newHashSet();
+
+ @Option(name = "-a", aliases = "--allocationPools",
+ description = "Subnet jsonnode allocationPools", required = false, multiValued = false)
+ Set<AllocationPool> allocationPools = Sets.newHashSet();
+
+ @Override
+ protected void execute() {
+ SubnetService service = get(SubnetService.class);
+ if (id == null || networkId == null || tenantId == null) {
+ print(null, "id,networkId,tenantId can not be null");
+ return;
+ }
+ Subnet subnet = new DefaultSubnet(SubnetId.subnetId(id), subnetName,
+ TenantNetworkId.networkId(networkId),
+ TenantId.tenantId(tenantId), ipVersion,
+ cidr == null ? null : IpPrefix.valueOf(cidr),
+ gatewayIp == null ? null : IpAddress.valueOf(gatewayIp),
+ dhcpEnabled, shared, hostRoutes,
+ ipV6AddressMode == null ? null : Mode.valueOf(ipV6AddressMode),
+ ipV6RaMode == null ? null : Mode.valueOf(ipV6RaMode),
+ allocationPools);
+ Set<Subnet> subnetsSet = Sets.newHashSet();
+ subnetsSet.add(subnet);
+ service.updateSubnets(subnetsSet);
+ }
+
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/subnet/package-info.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/subnet/package-info.java
new file mode 100644
index 00000000..b3a2ff51
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/subnet/package-info.java
@@ -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.
+ */
+
+/**
+ * Command line interface for subnets.
+ */
+package org.onosproject.vtnrsc.cli.subnet;
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/virtualport/VirtualPortCreateCommand.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/virtualport/VirtualPortCreateCommand.java
new file mode 100644
index 00000000..4c555e33
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/virtualport/VirtualPortCreateCommand.java
@@ -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.cli.virtualport;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.shell.commands.Option;
+import org.onlab.packet.MacAddress;
+import org.onosproject.cli.AbstractShellCommand;
+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.TenantId;
+import org.onosproject.vtnrsc.TenantNetworkId;
+import org.onosproject.vtnrsc.VirtualPort;
+import org.onosproject.vtnrsc.VirtualPortId;
+import org.onosproject.vtnrsc.virtualport.VirtualPortService;
+
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+/**
+ * Supports for creating a virtualPort.
+ */
+@Command(scope = "onos", name = "virtualport-create",
+ description = "Supports for creating a virtualPort.")
+public class VirtualPortCreateCommand extends AbstractShellCommand {
+
+ @Argument(index = 0, name = "id", description = "virtualPort id.", required = true,
+ multiValued = false)
+ String id = null;
+
+ @Argument(index = 1, name = "networkId", description = "network id.", required = true,
+ multiValued = false)
+ String networkId = null;
+
+ @Argument(index = 2, name = "name", description = "virtualPort name.", required = true,
+ multiValued = false)
+ String name = null;
+
+ @Argument(index = 3, name = "tenantId", description = "tenant id.", required = true,
+ multiValued = false)
+ String tenantId = null;
+
+ @Argument(index = 4, name = "deviceId", description = "device id.", required = true,
+ multiValued = false)
+ String deviceId = null;
+
+ @Option(name = "-a", aliases = "--adminStateUp",
+ description = "administrative status of the virtualPort which is true or false.",
+ required = false, multiValued = false)
+ Boolean adminStateUp = false;
+
+ @Option(name = "-s", aliases = "--state", description = "virtualPort state.", required = false,
+ multiValued = false)
+ String state = null;
+
+ @Option(name = "-m", aliases = "--macAddress", description = "MAC address.", required = false,
+ multiValued = false)
+ String macAddress = "";
+
+ @Option(name = "-d", aliases = "--deviceOwner", description = "ID of the entity that uses this "
+ + "virtualPort.", required = false, multiValued = false)
+ String deviceOwner = null;
+
+ @Option(name = "-f", aliases = "--fixedIp",
+ description = "The IP address for the port,include the IP address "
+ + "and subnet identity.", required = false, multiValued = false)
+ FixedIp fixedIp = null;
+
+ @Option(name = "-i", aliases = "--bindingHostId", description = "virtualPort bindingHostId.",
+ required = false, multiValued = false)
+ String bindingHostId = null;
+
+ @Option(name = "-t", aliases = "--bindingvnicType", description = "virtualPort bindingvnicType.",
+ required = false, multiValued = false)
+ String bindingvnicType = null;
+
+ @Option(name = "-v", aliases = "--bindingvifType", description = "virtualPort bindingvifType.",
+ required = false, multiValued = false)
+ String bindingvifType = null;
+
+ @Option(name = "-b", aliases = "--bindingvnicDetails",
+ description = "virtualPort bindingvnicDetails.", required = false, multiValued = false)
+ String bindingvnicDetails = null;
+
+ @Option(name = "-l", aliases = "--allowedAddress", description = "virtual allowedAddressPair.",
+ required = false, multiValued = false)
+ Set<AllowedAddressPair> allowedAddressPairs = Sets.newHashSet();
+
+ @Option(name = "-e", aliases = "--securityGroups", description = "virtualPort securityGroups.",
+ required = false, multiValued = false)
+ Set<SecurityGroup> securityGroups = Sets.newHashSet();
+
+ @Override
+ protected void execute() {
+ Map<String, String> strMap = Maps.newHashMap();
+ strMap.putIfAbsent("name", name);
+ strMap.putIfAbsent("deviceOwner", deviceOwner);
+ strMap.putIfAbsent("bindingvnicType", bindingvnicType);
+ strMap.putIfAbsent("bindingvifType", bindingvifType);
+ strMap.putIfAbsent("bindingvnicDetails", bindingvnicDetails);
+ VirtualPortService service = get(VirtualPortService.class);
+ VirtualPort virtualPort = new DefaultVirtualPort(VirtualPortId.portId(id),
+ TenantNetworkId.networkId(networkId),
+ false, strMap, VirtualPort.State.ACTIVE,
+ MacAddress.valueOf(macAddress),
+ TenantId.tenantId(tenantId),
+ DeviceId.deviceId(deviceId), Sets.newHashSet(fixedIp),
+ BindingHostId.bindingHostId(bindingHostId),
+ allowedAddressPairs, securityGroups);
+ Set<VirtualPort> virtualPorts = Sets.newHashSet(virtualPort);
+ service.createPorts(virtualPorts);
+ }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/virtualport/VirtualPortQueryCommand.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/virtualport/VirtualPortQueryCommand.java
new file mode 100644
index 00000000..47126d1b
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/virtualport/VirtualPortQueryCommand.java
@@ -0,0 +1,94 @@
+/*
+ * 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.cli.virtualport;
+
+import java.util.Collection;
+
+import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.shell.commands.Option;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.DeviceId;
+import org.onosproject.vtnrsc.TenantNetworkId;
+import org.onosproject.vtnrsc.VirtualPort;
+import org.onosproject.vtnrsc.VirtualPortId;
+import org.onosproject.vtnrsc.virtualport.VirtualPortService;
+
+/**
+ * Supports for querying virtualPorts.
+ */
+@Command(scope = "onos", name = "virtualports", description = "Supports for querying virtualPorts.")
+public class VirtualPortQueryCommand extends AbstractShellCommand {
+
+ @Option(name = "-v", aliases = "--vPortId", description = "virtualPort ID.", required = false,
+ multiValued = false)
+ String vPortId;
+
+ @Option(name = "-n", aliases = "--networkId", description = "network ID.", required = false,
+ multiValued = false)
+ String networkId;
+
+ @Option(name = "-d", aliases = "--deviceId", description = "device ID.", required = false,
+ multiValued = false)
+ String deviceId;
+
+ @Option(name = "-t", aliases = "--tenantId", description = "tenant ID.", required = false,
+ multiValued = false)
+ String tenantId;
+
+ private static final String FMT = "virtualPortId=%s, networkId=%s, name=%s,"
+ + " tenantId=%s, deviceId=%s, adminStateUp=%s, state=%s,"
+ + " macAddress=%s, deviceOwner=%s, fixedIp=%s, bindingHostId=%s,"
+ + " bindingvnicType=%s, bindingvifType=%s, bindingvnicDetails=%s,"
+ + " allowedAddress=%s, securityGroups=%s";
+
+ @Override
+ protected void execute() {
+ VirtualPortService service = get(VirtualPortService.class);
+ if (vPortId != null && networkId == null && deviceId == null && tenantId == null) {
+ VirtualPort port = service.getPort(VirtualPortId.portId(vPortId));
+ printPort(port);
+ } else if (vPortId == null && networkId != null && deviceId == null && tenantId == null) {
+ Collection<VirtualPort> ports = service.getPorts(TenantNetworkId.networkId(networkId));
+ printPorts(ports);
+ } else if (vPortId == null && networkId == null && deviceId != null && tenantId == null) {
+ Collection<VirtualPort> ports = service.getPorts(DeviceId.deviceId(deviceId));
+ printPorts(ports);
+ } else if (vPortId == null && networkId == null && deviceId == null && tenantId != null) {
+ Collection<VirtualPort> ports = service.getPorts(DeviceId.deviceId(tenantId));
+ printPorts(ports);
+ } else if (vPortId == null && networkId == null && deviceId == null && tenantId == null) {
+ Collection<VirtualPort> ports = service.getPorts();
+ printPorts(ports);
+ } else {
+ print("cannot input more than one parameter");
+ }
+
+ }
+
+ private void printPorts(Collection<VirtualPort> ports) {
+ for (VirtualPort port : ports) {
+ printPort(port);
+ }
+ }
+
+ private void printPort(VirtualPort port) {
+ print(FMT, port.portId(), port.networkId(), port.name(), port.tenantId(), port.deviceId(),
+ port.adminStateUp(), port.state(), port.macAddress(), port.deviceOwner(), port
+ .fixedIps(), port.bindingHostId(), port.bindingVnicType(),
+ port.bindingVifType(), port.bindingVifDetails(), port.allowedAddressPairs(),
+ port.securityGroups());
+ }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/virtualport/VirtualPortRemoveCommand.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/virtualport/VirtualPortRemoveCommand.java
new file mode 100644
index 00000000..1a3cb4f0
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/virtualport/VirtualPortRemoveCommand.java
@@ -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.vtnrsc.cli.virtualport;
+
+import java.util.Set;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.vtnrsc.VirtualPortId;
+import org.onosproject.vtnrsc.virtualport.VirtualPortService;
+
+import com.google.common.collect.Sets;
+
+/**
+ * Supports for removing a virtualPort.
+ */
+@Command(scope = "onos", name = "virtualport-remove",
+ description = "Supports for removing a virtualPort.")
+public class VirtualPortRemoveCommand extends AbstractShellCommand {
+
+ @Argument(index = 0, name = "id", description = "virtualPort id.", required = true,
+ multiValued = false)
+ String id = null;
+
+ @Override
+ protected void execute() {
+ VirtualPortService service = get(VirtualPortService.class);
+ Set<VirtualPortId> virtualPorts = Sets.newHashSet(VirtualPortId.portId(id));
+ service.removePorts(virtualPorts);
+ }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/virtualport/VirtualPortUpdateCommand.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/virtualport/VirtualPortUpdateCommand.java
new file mode 100644
index 00000000..6df4b23c
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/virtualport/VirtualPortUpdateCommand.java
@@ -0,0 +1,135 @@
+/*
+ * 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.cli.virtualport;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.shell.commands.Option;
+import org.onlab.packet.MacAddress;
+import org.onosproject.cli.AbstractShellCommand;
+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.TenantId;
+import org.onosproject.vtnrsc.TenantNetworkId;
+import org.onosproject.vtnrsc.VirtualPort;
+import org.onosproject.vtnrsc.VirtualPortId;
+import org.onosproject.vtnrsc.virtualport.VirtualPortService;
+
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+/**
+ * Supports for updating a virtualPort.
+ */
+@Command(scope = "onos", name = "virtualport-update",
+ description = "Supports for updating a virtualPort.")
+public class VirtualPortUpdateCommand extends AbstractShellCommand {
+
+ @Argument(index = 0, name = "id", description = "virtualPort id.", required = true,
+ multiValued = false)
+ String id = null;
+
+ @Argument(index = 1, name = "networkId", description = "network id.", required = true,
+ multiValued = false)
+ String networkId = null;
+
+ @Argument(index = 2, name = "name", description = "virtualPort name.", required = true,
+ multiValued = false)
+ String name = null;
+
+ @Argument(index = 3, name = "tenantId", description = "tenant id.", required = true,
+ multiValued = false)
+ String tenantId = null;
+
+ @Argument(index = 4, name = "deviceId", description = "device id.", required = true,
+ multiValued = false)
+ String deviceId = null;
+
+ @Option(name = "-a", aliases = "--adminStateUp",
+ description = "administrative status of the virtualPort which is true or false.",
+ required = false, multiValued = false)
+ Boolean adminStateUp = false;
+
+ @Option(name = "-s", aliases = "--state", description = "virtualPort state.", required = false,
+ multiValued = false)
+ String state = null;
+
+ @Option(name = "-m", aliases = "--macAddress", description = "MAC address.", required = false,
+ multiValued = false)
+ String macAddress = "";
+
+ @Option(name = "-d", aliases = "--deviceOwner",
+ description = "ID of the entity that uses this " + "virtualPort.", required = false,
+ multiValued = false)
+ String deviceOwner = null;
+
+ @Option(name = "-f", aliases = "--fixedIp",
+ description = "The IP address for the port,include the IP address "
+ + "and subnet identity.", required = false, multiValued = false)
+ FixedIp fixedIp = null;
+
+ @Option(name = "-i", aliases = "--bindingHostId", description = "virtualPort bindingHostId.",
+ required = false, multiValued = false)
+ String bindingHostId = "";
+
+ @Option(name = "-t", aliases = "--bindingvnicType",
+ description = "virtualPort bindingvnicType.", required = false, multiValued = false)
+ String bindingvnicType = null;
+
+ @Option(name = "-v", aliases = "--bindingvifType", description = "virtualPort bindingvifType.",
+ required = false, multiValued = false)
+ String bindingvifType = null;
+
+ @Option(name = "-b", aliases = "--bindingvnicDetails",
+ description = "virtualPort bindingvnicDetails.", required = false, multiValued = false)
+ String bindingvnicDetails = null;
+
+ @Option(name = "-l", aliases = "--allowedAddress", description = "virtual allowedAddressPair.",
+ required = false, multiValued = false)
+ Set<AllowedAddressPair> allowedAddressPairs = Sets.newHashSet();
+
+ @Option(name = "-e", aliases = "--securityGroups", description = "virtualPort securityGroups.",
+ required = false, multiValued = false)
+ Set<SecurityGroup> securityGroups = Sets.newHashSet();
+
+ @Override
+ protected void execute() {
+ VirtualPortService service = get(VirtualPortService.class);
+ Map<String, String> strMap = Maps.newHashMap();
+ strMap.putIfAbsent("name", name);
+ strMap.putIfAbsent("deviceOwner", deviceOwner);
+ strMap.putIfAbsent("bindingvnicType", bindingvnicType);
+ strMap.putIfAbsent("bindingvifType", bindingvifType);
+ strMap.putIfAbsent("bindingvnicDetails", bindingvnicDetails);
+ VirtualPort virtualPort = new DefaultVirtualPort(VirtualPortId.portId(id),
+ TenantNetworkId.networkId(networkId),
+ false, strMap, VirtualPort.State.ACTIVE,
+ MacAddress.valueOf(macAddress),
+ TenantId.tenantId(tenantId),
+ DeviceId.deviceId(deviceId), Sets.newHashSet(fixedIp),
+ BindingHostId.bindingHostId(bindingHostId),
+ allowedAddressPairs, securityGroups);
+ Set<VirtualPort> virtualPorts = Sets.newHashSet(virtualPort);
+ service.updatePorts(virtualPorts);
+ }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/virtualport/package-info.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/virtualport/package-info.java
new file mode 100644
index 00000000..fac214a1
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/cli/virtualport/package-info.java
@@ -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.
+ */
+
+/**
+ * Command line interface for virtual ports.
+ */
+package org.onosproject.vtnrsc.cli.virtualport;
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/package-info.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/package-info.java
new file mode 100644
index 00000000..b245fb14
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/package-info.java
@@ -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.
+ */
+
+/**
+ * VTN resources that used by virtual tenant network.
+ */
+package org.onosproject.vtnrsc;
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/subnet/SubnetService.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/subnet/SubnetService.java
new file mode 100644
index 00000000..82eb9611
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/subnet/SubnetService.java
@@ -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.subnet;
+
+import org.onosproject.vtnrsc.Subnet;
+import org.onosproject.vtnrsc.SubnetId;
+
+
+/**
+ * Service for interacting with the inventory of subnets.
+ */
+public interface SubnetService {
+ /**
+ * 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);
+
+
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/subnet/impl/SubnetManager.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/subnet/impl/SubnetManager.java
new file mode 100644
index 00000000..890beb29
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/subnet/impl/SubnetManager.java
@@ -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.subnet.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.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+import org.onlab.packet.IpAddress;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.store.serializers.KryoNamespaces;
+import org.onosproject.store.service.Serializer;
+import org.onosproject.store.service.StorageService;
+import org.onosproject.vtnrsc.AllocationPool;
+import org.onosproject.vtnrsc.DefaultAllocationPool;
+import org.onosproject.vtnrsc.DefaultHostRoute;
+import org.onosproject.vtnrsc.DefaultSubnet;
+import org.onosproject.vtnrsc.HostRoute;
+import org.onosproject.vtnrsc.Subnet;
+import org.onosproject.vtnrsc.SubnetId;
+import org.onosproject.vtnrsc.TenantId;
+import org.onosproject.vtnrsc.TenantNetworkId;
+import org.onosproject.vtnrsc.subnet.SubnetService;
+import org.onosproject.vtnrsc.tenantnetwork.TenantNetworkService;
+import org.slf4j.Logger;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Map;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Provides implementation of the Subnet service.
+ */
+@Component(immediate = true)
+@Service
+public class SubnetManager implements SubnetService {
+
+ private static final String SUBNET_ID_NULL = "Subnet ID cannot be null";
+ private static final String SUBNET_NOT_NULL = "Subnet cannot be null";
+ private static final String SUBNET = "vtn-subnet-store";
+ private static final String VTNRSC_APP = "org.onosproject.vtnrsc";
+
+
+ private final Logger log = getLogger(getClass());
+
+ protected Map<SubnetId, Subnet> subnetStore;
+ protected ApplicationId appId;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected StorageService storageService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CoreService coreService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected TenantNetworkService tenantNetworkService;
+
+ @Activate
+ public void activate() {
+
+ appId = coreService.registerApplication(VTNRSC_APP);
+
+ subnetStore = storageService.<SubnetId, Subnet>consistentMapBuilder()
+ .withName(SUBNET)
+ .withApplicationId(appId)
+ .withPurgeOnUninstall()
+ .withSerializer(Serializer.using(Arrays.asList(KryoNamespaces.API),
+ Subnet.class,
+ SubnetId.class,
+ TenantNetworkId.class,
+ TenantId.class,
+ HostRoute.class,
+ DefaultHostRoute.class,
+ Subnet.Mode.class,
+ AllocationPool.class,
+ DefaultAllocationPool.class,
+ DefaultSubnet.class,
+ IpAddress.Version.class))
+ .build().asJavaMap();
+
+ log.info("Started");
+ }
+
+ @Deactivate
+ public void deactivate() {
+ log.info("Stopped");
+ }
+
+ @Override
+ public Iterable<Subnet> getSubnets() {
+ return Collections.unmodifiableCollection(subnetStore.values());
+ }
+
+ @Override
+ public Subnet getSubnet(SubnetId subnetId) {
+ checkNotNull(subnetId, SUBNET_ID_NULL);
+ return subnetStore.get(subnetId);
+ }
+
+ @Override
+ public boolean exists(SubnetId subnetId) {
+ checkNotNull(subnetId, SUBNET_ID_NULL);
+ return subnetStore.containsKey(subnetId);
+ }
+
+ @Override
+ public boolean createSubnets(Iterable<Subnet> subnets) {
+ checkNotNull(subnets, SUBNET_NOT_NULL);
+ for (Subnet subnet : subnets) {
+ if (!tenantNetworkService.exists(subnet.networkId())) {
+ log.debug("The network identifier that the subnet {} belong to is not exist",
+ subnet.networkId().toString(), subnet.id().toString());
+ return false;
+ }
+ subnetStore.put(subnet.id(), subnet);
+ if (!subnetStore.containsKey(subnet.id())) {
+ log.debug("The identified subnet whose identifier is {} create failed",
+ subnet.id().toString());
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public boolean updateSubnets(Iterable<Subnet> subnets) {
+ checkNotNull(subnets, SUBNET_NOT_NULL);
+ if (subnets != null) {
+ for (Subnet subnet : subnets) {
+ if (!subnetStore.containsKey(subnet.id())) {
+ log.debug("The subnet is not exist whose identifier is {}",
+ subnet.id().toString());
+ return false;
+ }
+
+ subnetStore.put(subnet.id(), subnet);
+
+ if (!subnet.equals(subnetStore.get(subnet.id()))) {
+ log.debug("The subnet is updated failed whose identifier is {}",
+ subnet.id().toString());
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public boolean removeSubnets(Iterable<SubnetId> subnetIds) {
+ checkNotNull(subnetIds, SUBNET_ID_NULL);
+ if (subnetIds != null) {
+ for (SubnetId subnetId : subnetIds) {
+ subnetStore.remove(subnetId);
+ if (subnetStore.containsKey(subnetId)) {
+ log.debug("The subnet created is failed whose identifier is {}",
+ subnetId.toString());
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/subnet/impl/package-info.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/subnet/impl/package-info.java
new file mode 100644
index 00000000..79040d8d
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/subnet/impl/package-info.java
@@ -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 Subnet service.
+ */
+package org.onosproject.vtnrsc.subnet.impl;
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/subnet/package-info.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/subnet/package-info.java
new file mode 100644
index 00000000..7b2bdb90
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/subnet/package-info.java
@@ -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 subnets.
+ */
+package org.onosproject.vtnrsc.subnet;
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/tenantnetwork/TenantNetworkService.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/tenantnetwork/TenantNetworkService.java
new file mode 100644
index 00000000..e246cc4e
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/tenantnetwork/TenantNetworkService.java
@@ -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.tenantnetwork;
+
+import org.onosproject.vtnrsc.TenantNetwork;
+import org.onosproject.vtnrsc.TenantNetworkId;
+
+/**
+ * Service for interacting with the inventory of tenantNetwork.
+ */
+public interface TenantNetworkService {
+
+ /**
+ * Returns if the tenantNetwork is existed.
+ *
+ * @param networkId tenantNetwork identifier
+ * @return true or false if one with the given identifier exists.
+ */
+ boolean exists(TenantNetworkId networkId);
+
+ /**
+ * Returns the number of tenantNetwork known to the system.
+ *
+ * @return number of tenantNetwork.
+ */
+ int getNetworkCount();
+
+ /**
+ * Returns an iterable collection of the currently known tenantNetwork.
+ *
+ * @return collection of tenantNetwork.
+ */
+ Iterable<TenantNetwork> getNetworks();
+
+ /**
+ * Returns the tenantNetwork with the identifier.
+ *
+ * @param networkId TenantNetwork identifier
+ * @return TenantNetwork or null if one with the given identifier is not
+ * known.
+ */
+ TenantNetwork getNetwork(TenantNetworkId networkId);
+
+ /**
+ * Creates tenantNetworks by networks.
+ *
+ * @param networks the collection of tenantNetworks
+ * @return true if all given identifiers created successfully.
+ */
+ boolean createNetworks(Iterable<TenantNetwork> networks);
+
+ /**
+ * Updates tenantNetworks by tenantNetworks.
+ *
+ * @param networks the collection of tenantNetworks
+ * @return true if all given identifiers updated successfully.
+ */
+ boolean updateNetworks(Iterable<TenantNetwork> networks);
+
+ /**
+ * Deletes tenantNetwork by tenantNetworkIds.
+ *
+ * @param networksIds the collection of tenantNetworkIds
+ * @return true if the specified tenantNetworks deleted successfully.
+ */
+ boolean removeNetworks(Iterable<TenantNetworkId> networksIds);
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/tenantnetwork/impl/TenantNetworkManager.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/tenantnetwork/impl/TenantNetworkManager.java
new file mode 100644
index 00000000..0dfc99e2
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/tenantnetwork/impl/TenantNetworkManager.java
@@ -0,0 +1,167 @@
+/*
+ * 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.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.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.store.serializers.KryoNamespaces;
+import org.onosproject.store.service.Serializer;
+import org.onosproject.store.service.StorageService;
+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 org.onosproject.vtnrsc.tenantnetwork.TenantNetworkService;
+import org.slf4j.Logger;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Map;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Provides implementation of the tenantNetworkService.
+ */
+@Component(immediate = true)
+@Service
+public class TenantNetworkManager implements TenantNetworkService {
+
+ private static final String NETWORK_ID_NULL = "Network ID cannot be null";
+ private static final String NETWORK_NOT_NULL = "Network ID cannot be null";
+ private static final String TENANTNETWORK = "vtn-tenant-network-store";
+ private static final String VTNRSC_APP = "org.onosproject.vtnrsc";
+
+ protected Map<TenantNetworkId, TenantNetwork> networkIdAsKeyStore;
+ protected ApplicationId appId;
+
+ private final Logger log = getLogger(getClass());
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected StorageService storageService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CoreService coreService;
+
+
+ @Activate
+ public void activate() {
+
+ appId = coreService.registerApplication(VTNRSC_APP);
+
+ networkIdAsKeyStore = storageService.<TenantNetworkId, TenantNetwork>consistentMapBuilder()
+ .withName(TENANTNETWORK)
+ .withApplicationId(appId)
+ .withPurgeOnUninstall()
+ .withSerializer(Serializer.using(Arrays.asList(KryoNamespaces.API),
+ TenantNetworkId.class,
+ DefaultTenantNetwork.class,
+ TenantNetwork.State.class,
+ TenantId.class,
+ TenantNetwork.Type.class,
+ PhysicalNetwork.class,
+ SegmentationId.class))
+ .build().asJavaMap();
+
+ log.info("Started");
+ }
+
+ @Deactivate
+ public void deactivate() {
+ log.info("Stopped");
+ }
+
+ @Override
+ public boolean exists(TenantNetworkId networkId) {
+ checkNotNull(networkId, NETWORK_ID_NULL);
+ return networkIdAsKeyStore.containsKey(networkId);
+ }
+
+ @Override
+ public int getNetworkCount() {
+ return networkIdAsKeyStore.size();
+ }
+
+ @Override
+ public Iterable<TenantNetwork> getNetworks() {
+ return Collections.unmodifiableCollection(networkIdAsKeyStore.values());
+ }
+
+ @Override
+ public TenantNetwork getNetwork(TenantNetworkId networkId) {
+ checkNotNull(networkId, NETWORK_ID_NULL);
+ return networkIdAsKeyStore.get(networkId);
+ }
+
+ @Override
+ public boolean createNetworks(Iterable<TenantNetwork> networks) {
+ checkNotNull(networks, NETWORK_NOT_NULL);
+ for (TenantNetwork network : networks) {
+ networkIdAsKeyStore.put(network.id(), network);
+ if (!networkIdAsKeyStore.containsKey(network.id())) {
+ log.debug("The tenantNetwork is created failed which identifier was {}", network.id()
+ .toString());
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public boolean updateNetworks(Iterable<TenantNetwork> networks) {
+ checkNotNull(networks, NETWORK_NOT_NULL);
+ for (TenantNetwork network : networks) {
+ if (!networkIdAsKeyStore.containsKey(network.id())) {
+ log.debug("The tenantNetwork is not exist whose identifier was {} ",
+ network.id().toString());
+ return false;
+ }
+
+ networkIdAsKeyStore.put(network.id(), network);
+
+ if (!network.equals(networkIdAsKeyStore.get(network.id()))) {
+ log.debug("The tenantNetwork is updated failed whose identifier was {} ",
+ network.id().toString());
+ return false;
+ }
+
+ }
+ return true;
+ }
+
+ @Override
+ public boolean removeNetworks(Iterable<TenantNetworkId> networkIds) {
+ checkNotNull(networkIds, NETWORK_NOT_NULL);
+ for (TenantNetworkId networkId : networkIds) {
+ networkIdAsKeyStore.remove(networkId);
+ if (networkIdAsKeyStore.containsKey(networkId)) {
+ log.debug("The tenantNetwork is removed failed whose identifier was {}",
+ networkId.toString());
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/tenantnetwork/impl/package-info.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/tenantnetwork/impl/package-info.java
new file mode 100644
index 00000000..f381fda6
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/tenantnetwork/impl/package-info.java
@@ -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.
+ */
+
+/**
+ * Implementation of service for interacting with the inventory of tenant networks.
+ */
+package org.onosproject.vtnrsc.tenantnetwork.impl;
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/tenantnetwork/package-info.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/tenantnetwork/package-info.java
new file mode 100644
index 00000000..1489c973
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/tenantnetwork/package-info.java
@@ -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 tenant networks.
+ */
+package org.onosproject.vtnrsc.tenantnetwork;
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
new file mode 100644
index 00000000..6f3cf653
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/tunnel/TunnelConfigService.java
@@ -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.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);
+
+
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/tunnel/package-info.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/tunnel/package-info.java
new file mode 100644
index 00000000..3a84e6e3
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/tunnel/package-info.java
@@ -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 subnets.
+ */
+package org.onosproject.vtnrsc.tunnel;
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/VirtualPortService.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/VirtualPortService.java
new file mode 100644
index 00000000..05ebccf9
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/VirtualPortService.java
@@ -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.vtnrsc.virtualport;
+
+import java.util.Collection;
+
+import org.onosproject.net.DeviceId;
+import org.onosproject.vtnrsc.TenantId;
+import org.onosproject.vtnrsc.TenantNetworkId;
+import org.onosproject.vtnrsc.VirtualPort;
+import org.onosproject.vtnrsc.VirtualPortId;
+
+/**
+ * Service for interacting with the inventory of virtualPort.
+ */
+public interface VirtualPortService {
+ /**
+ * Returns if the virtualPort is existed.
+ *
+ * @param virtualPortId virtualPort identifier
+ * @return true or false if one with the given identifier is not existed.
+ */
+ boolean exists(VirtualPortId virtualPortId);
+
+ /**
+ * Returns the virtualPort with the identifier.
+ *
+ * @param virtualPortId virtualPort ID
+ * @return VirtualPort or null if one with the given ID is not know.
+ */
+ VirtualPort getPort(VirtualPortId virtualPortId);
+
+ /**
+ * Returns the collection of the currently known virtualPort.
+ * @return collection of VirtualPort.
+ */
+ Collection<VirtualPort> getPorts();
+
+ /**
+ * Returns the collection of the virtualPorts associated with the networkId.
+ *
+ * @param networkId the network identifer
+ * @return collection of virtualPort.
+ */
+ Collection<VirtualPort> getPorts(TenantNetworkId networkId);
+
+ /**
+ * Returns the collection of the virtualPorts associated with the tenantId.
+ *
+ * @param tenantId the tenant identifier
+ * @return collection of virtualPorts.
+ */
+ Collection<VirtualPort> getPorts(TenantId tenantId);
+
+ /**
+ * Returns the collection of the virtualPorts associated with the deviceId.
+ *
+ * @param deviceId the device identifier
+ * @return collection of virtualPort.
+ */
+ Collection<VirtualPort> getPorts(DeviceId deviceId);
+
+ /**
+ * Creates virtualPorts by virtualPorts.
+ *
+ * @param virtualPorts the iterable collection of virtualPorts
+ * @return true if all given identifiers created successfully.
+ */
+ boolean createPorts(Iterable<VirtualPort> virtualPorts);
+
+ /**
+ * Updates virtualPorts by virtualPorts.
+ *
+ * @param virtualPorts the iterable collection of virtualPorts
+ * @return true if all given identifiers updated successfully.
+ */
+ boolean updatePorts(Iterable<VirtualPort> virtualPorts);
+
+ /**
+ * Deletes virtualPortIds by virtualPortIds.
+ *
+ * @param virtualPortIds the iterable collection of virtualPort identifiers
+ * @return true or false if one with the given identifier to delete is
+ * successfully.
+ */
+ boolean removePorts(Iterable<VirtualPortId> virtualPortIds);
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/impl/VirtualPortManager.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/impl/VirtualPortManager.java
new file mode 100644
index 00000000..926809c9
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/impl/VirtualPortManager.java
@@ -0,0 +1,208 @@
+/*
+ * 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.impl;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+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.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.DeviceId;
+import org.onosproject.store.serializers.KryoNamespaces;
+import org.onosproject.store.service.Serializer;
+import org.onosproject.store.service.StorageService;
+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 org.onosproject.vtnrsc.tenantnetwork.TenantNetworkService;
+import org.onosproject.vtnrsc.virtualport.VirtualPortService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Provides implementation of the VirtualPort APIs.
+ */
+@Component(immediate = true)
+@Service
+public class VirtualPortManager implements VirtualPortService {
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ private static final String VIRTUALPORT = "vtn-virtual-port";
+ private static final String VTNRSC_APP = "org.onosproject.vtnrsc";
+
+ private static final String VIRTUALPORT_ID_NULL = "VirtualPort ID cannot be null";
+ private static final String VIRTUALPORT_NOT_NULL = "VirtualPort cannot be null";
+ private static final String TENANTID_NOT_NULL = "TenantId cannot be null";
+ private static final String NETWORKID_NOT_NULL = "NetworkId cannot be null";
+ private static final String DEVICEID_NOT_NULL = "DeviceId cannot be null";
+
+ protected Map<VirtualPortId, VirtualPort> vPortStore;
+ protected ApplicationId appId;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected StorageService storageService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected TenantNetworkService networkService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CoreService coreService;
+
+ @Activate
+ public void activate() {
+
+ appId = coreService.registerApplication(VTNRSC_APP);
+
+ vPortStore = storageService.<VirtualPortId, VirtualPort>consistentMapBuilder()
+ .withName(VIRTUALPORT)
+ .withApplicationId(appId)
+ .withPurgeOnUninstall()
+ .withSerializer(Serializer.using(Arrays.asList(KryoNamespaces.API),
+ VirtualPortId.class,
+ TenantNetworkId.class,
+ VirtualPort.State.class,
+ TenantId.class,
+ AllowedAddressPair.class,
+ FixedIp.class,
+ BindingHostId.class,
+ SecurityGroup.class,
+ SubnetId.class,
+ IpAddress.class,
+ DefaultVirtualPort.class))
+ .build().asJavaMap();
+ log.info("Started");
+ }
+
+ @Deactivate
+ public void deactivate() {
+ vPortStore.clear();
+ log.info("Stoppped");
+ }
+
+ @Override
+ public boolean exists(VirtualPortId vPortId) {
+ checkNotNull(vPortId, VIRTUALPORT_ID_NULL);
+ return vPortStore.containsKey(vPortId);
+ }
+
+ @Override
+ public VirtualPort getPort(VirtualPortId vPortId) {
+ checkNotNull(vPortId, VIRTUALPORT_ID_NULL);
+ return vPortStore.get(vPortId);
+ }
+
+ @Override
+ public Collection<VirtualPort> getPorts() {
+ return Collections.unmodifiableCollection(vPortStore.values());
+ }
+
+ @Override
+ public Collection<VirtualPort> getPorts(TenantNetworkId networkId) {
+ checkNotNull(networkId, NETWORKID_NOT_NULL);
+ return vPortStore.values().stream().filter(d -> d.networkId().equals(networkId))
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public Collection<VirtualPort> getPorts(TenantId tenantId) {
+ checkNotNull(tenantId, TENANTID_NOT_NULL);
+ return vPortStore.values().stream().filter(d -> d.tenantId().equals(tenantId))
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public Collection<VirtualPort> getPorts(DeviceId deviceId) {
+ checkNotNull(deviceId, DEVICEID_NOT_NULL);
+ return vPortStore.values().stream().filter(d -> d.deviceId().equals(deviceId))
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public boolean createPorts(Iterable<VirtualPort> vPorts) {
+ checkNotNull(vPorts, VIRTUALPORT_NOT_NULL);
+ for (VirtualPort vPort : vPorts) {
+ log.debug("vPortId is {} ", vPort.portId().toString());
+ vPortStore.put(vPort.portId(), vPort);
+ if (!vPortStore.containsKey(vPort.portId())) {
+ log.debug("The virtualPort is created failed whose identifier is {} ",
+ vPort.portId().toString());
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @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;
+ }
+
+ 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;
+ }
+ }
+ }
+ return true;
+ }
+
+ @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;
+ }
+ }
+ }
+ return true;
+ }
+
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/impl/package-info.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/impl/package-info.java
new file mode 100644
index 00000000..24eb0d3f
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/impl/package-info.java
@@ -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.
+ */
+
+/**
+ * Implementation of service for interacting with the inventory of virtual ports.
+ */
+package org.onosproject.vtnrsc.virtualport.impl;
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/package-info.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/package-info.java
new file mode 100644
index 00000000..06a01a04
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/package-info.java
@@ -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 virtual ports.
+ */
+package org.onosproject.vtnrsc.virtualport;
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/AllocationPoolsCodec.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/AllocationPoolsCodec.java
new file mode 100644
index 00000000..57c97c1c
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/AllocationPoolsCodec.java
@@ -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.vtnrsc.web;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.vtnrsc.AllocationPool;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * Subnet AllocationPool codec.
+ */
+public final class AllocationPoolsCodec extends JsonCodec<AllocationPool> {
+
+ @Override
+ public ObjectNode encode(AllocationPool alocPool, CodecContext context) {
+ checkNotNull(alocPool, "AllocationPools cannot be null");
+ ObjectNode result = context.mapper().createObjectNode()
+ .put("start", alocPool.startIp().toString())
+ .put("end", alocPool.endIp().toString());
+ return result;
+ }
+
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/AllowedAddressPairCodec.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/AllowedAddressPairCodec.java
new file mode 100644
index 00000000..7960808f
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/AllowedAddressPairCodec.java
@@ -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.vtnrsc.web;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.vtnrsc.AllowedAddressPair;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * VirtualPort AllowedAddressPair codec.
+ */
+public final class AllowedAddressPairCodec extends JsonCodec<AllowedAddressPair> {
+
+ @Override
+ public ObjectNode encode(AllowedAddressPair alocAddPair, CodecContext context) {
+ checkNotNull(alocAddPair, "AllowedAddressPair cannot be null");
+ ObjectNode result = context.mapper().createObjectNode()
+ .put("ip_address", alocAddPair.ip().toString())
+ .put("mac_address", alocAddPair.mac().toString());
+ return result;
+ }
+
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/FixedIpCodec.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/FixedIpCodec.java
new file mode 100644
index 00000000..96c9bb4e
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/FixedIpCodec.java
@@ -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.vtnrsc.web;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.vtnrsc.FixedIp;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * VirtualPort FixedIp codec.
+ */
+public final class FixedIpCodec extends JsonCodec<FixedIp> {
+
+ @Override
+ public ObjectNode encode(FixedIp fixIp, CodecContext context) {
+ checkNotNull(fixIp, "FixedIp cannot be null");
+ ObjectNode result = context.mapper().createObjectNode()
+ .put("subnet_id", fixIp.subnetId().toString())
+ .put("ip_address", fixIp.ip().toString());
+ return result;
+ }
+
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/HostRoutesCodec.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/HostRoutesCodec.java
new file mode 100644
index 00000000..69ca6b3f
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/HostRoutesCodec.java
@@ -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.vtnrsc.web;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.vtnrsc.HostRoute;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * Subnet HostRoute codec.
+ */
+public final class HostRoutesCodec extends JsonCodec<HostRoute> {
+
+ @Override
+ public ObjectNode encode(HostRoute hostRoute, CodecContext context) {
+ checkNotNull(hostRoute, "HostRoute cannot be null");
+ ObjectNode result = context.mapper().createObjectNode()
+ .put("nexthop", hostRoute.nexthop().toString())
+ .put("destination", hostRoute.destination().toString());
+ return result;
+ }
+
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/SecurityGroupCodec.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/SecurityGroupCodec.java
new file mode 100644
index 00000000..c2ded196
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/SecurityGroupCodec.java
@@ -0,0 +1,39 @@
+/*
+ * 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 org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.vtnrsc.SecurityGroup;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * Virtualport SecurityGroup codec.
+ */
+public final class SecurityGroupCodec extends JsonCodec<SecurityGroup> {
+
+ @Override
+ public ObjectNode encode(SecurityGroup securGroup, CodecContext context) {
+ checkNotNull(securGroup, "SecurityGroup cannot be null");
+ ObjectNode result = context.mapper().createObjectNode()
+ .put("security_group", securGroup.securityGroup());
+ return result;
+ }
+
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/SubnetCodec.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/SubnetCodec.java
new file mode 100644
index 00000000..122b75a9
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/SubnetCodec.java
@@ -0,0 +1,53 @@
+/*
+ * 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 org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.vtnrsc.Subnet;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * Subnet JSON codec.
+ */
+public final class SubnetCodec extends JsonCodec<Subnet> {
+ @Override
+ public ObjectNode encode(Subnet subnet, CodecContext context) {
+ checkNotNull(subnet, "Subnet cannot be null");
+ ObjectNode result = context.mapper().createObjectNode()
+ .put("id", subnet.id().toString())
+ .put("gateway_ip", subnet.gatewayIp().toString())
+ .put("network_id", subnet.networkId().toString())
+ .put("name", subnet.subnetName())
+ .put("ip_version", subnet.ipVersion().toString())
+ .put("cidr", subnet.cidr().toString())
+ .put("shared", subnet.shared())
+ .put("enabled_dchp", subnet.dhcpEnabled())
+ .put("tenant_id", subnet.tenantId().toString())
+ .put("ipv6_address_mode", subnet.ipV6AddressMode() == null ? null
+ : subnet.ipV6AddressMode().toString())
+ .put("ipv6_ra_mode", subnet.ipV6RaMode() == null ? null
+ : subnet.ipV6RaMode().toString());
+ result.set("allocation_pools", new AllocationPoolsCodec().encode(subnet
+ .allocationPools(), context));
+ result.set("host_routes",
+ new HostRoutesCodec().encode(subnet.hostRoutes(), context));
+ return result;
+ }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/TenantNetworkCodec.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/TenantNetworkCodec.java
new file mode 100644
index 00000000..48ba3b97
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/TenantNetworkCodec.java
@@ -0,0 +1,47 @@
+/*
+ * 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 org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.vtnrsc.TenantNetwork;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * TenantNetwork JSON codec.
+ */
+public final class TenantNetworkCodec extends JsonCodec<TenantNetwork> {
+
+ @Override
+ public ObjectNode encode(TenantNetwork network, CodecContext context) {
+ checkNotNull(network, "Network cannot be null");
+ ObjectNode result = context.mapper().createObjectNode()
+ .put("id", network.id().toString())
+ .put("name", network.name())
+ .put("admin_state_up", network.adminStateUp())
+ .put("status", "" + network.state())
+ .put("shared", network.shared())
+ .put("tenant_id", network.tenantId().toString())
+ .put("router:external", network.routerExternal())
+ .put("provider:network_type", "" + network.type())
+ .put("provider:physical_network", network.physicalNetwork().toString())
+ .put("provider:segmentation_id", network.segmentationId().toString());
+ return result;
+ }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/VirtualPortCodec.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/VirtualPortCodec.java
new file mode 100644
index 00000000..e57d56bc
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/VirtualPortCodec.java
@@ -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.vtnrsc.web;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.vtnrsc.VirtualPort;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * VirtualPort JSON codec.
+ */
+public final class VirtualPortCodec extends JsonCodec<VirtualPort> {
+ @Override
+ public ObjectNode encode(VirtualPort vPort, CodecContext context) {
+ checkNotNull(vPort, "VPort cannot be null");
+ ObjectNode result = context
+ .mapper()
+ .createObjectNode()
+ .put("id", vPort.portId().toString())
+ .put("network_id", vPort.networkId().toString())
+ .put("admin_state_up", vPort.adminStateUp())
+ .put("name", vPort.name())
+ .put("status", vPort.state().toString())
+ .put("mac_address", vPort.macAddress().toString())
+ .put("tenant_id", vPort.tenantId().toString())
+ .put("device_id", vPort.deviceId().toString())
+ .put("device_owner", vPort.deviceOwner())
+ .put("binding:vnic_type", vPort.bindingVnicType())
+ .put("binding:Vif_type", vPort.bindingVifType())
+ .put("binding:host_id", vPort.bindingHostId().toString())
+ .put("binding:vif_details", vPort.bindingVifDetails());
+ result.set("allowed_address_pairs", new AllowedAddressPairCodec().encode(
+ vPort.allowedAddressPairs(), context));
+ result.set("fixed_ips", new FixedIpCodec().encode(
+ vPort.fixedIps(), context));
+ result.set("security_groups", new SecurityGroupCodec().encode(
+ vPort.securityGroups(), context));
+ return result;
+ }
+}
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/package-info.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/package-info.java
new file mode 100644
index 00000000..34636a9f
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/package-info.java
@@ -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.vtnrsc.web;
diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/framework/src/onos/apps/vtn/vtnrsc/src/main/resources/OSGI-INF/blueprint/shell-config.xml
new file mode 100644
index 00000000..c6a9c81b
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -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.
+ -->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+
+ <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
+ <command>
+ <action class="org.onosproject.vtnrsc.cli.network.TenantNetworkCreateCommand"/>
+ </command>
+ <command>
+ <action class="org.onosproject.vtnrsc.cli.network.TenantNetworkQueryCommand"/>
+ </command>
+ <command>
+ <action class="org.onosproject.vtnrsc.cli.network.TenantNetworkRemoveCommand"/>
+ </command>
+ <command>
+ <action class="org.onosproject.vtnrsc.cli.network.TenantNetworkUpdateCommand"/>
+ </command>
+ <command>
+ <action class="org.onosproject.vtnrsc.cli.subnet.SubnetCreateCommand"/>
+ </command>
+ <command>
+ <action class="org.onosproject.vtnrsc.cli.subnet.SubnetQueryCommand"/>
+ </command>
+ <command>
+ <action class="org.onosproject.vtnrsc.cli.subnet.SubnetRemoveCommand"/>
+ </command>
+ <command>
+ <action class="org.onosproject.vtnrsc.cli.subnet.SubnetUpdateCommand"/>
+ </command>
+ <command>
+ <action class="org.onosproject.vtnrsc.cli.virtualport.VirtualPortCreateCommand"/>
+ </command>
+ <command>
+ <action class="org.onosproject.vtnrsc.cli.virtualport.VirtualPortQueryCommand"/>
+ </command>
+ <command>
+ <action class="org.onosproject.vtnrsc.cli.virtualport.VirtualPortRemoveCommand"/>
+ </command>
+ <command>
+ <action class="org.onosproject.vtnrsc.cli.virtualport.VirtualPortUpdateCommand"/>
+ </command>
+ </command-bundle>
+</blueprint>
diff --git a/framework/src/onos/apps/vtn/vtnweb/pom.xml b/framework/src/onos/apps/vtn/vtnweb/pom.xml
new file mode 100644
index 00000000..bcb71d9f
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnweb/pom.xml
@@ -0,0 +1,87 @@
+<?xml version="1.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.
+ -->
+<project
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+ xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-app-vtn</artifactId>
+ <version>1.4.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+
+ <artifactId>onos-app-vtn-web</artifactId>
+ <packaging>bundle</packaging>
+ <properties>
+ <web.context>/onos/vtn</web.context>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>javax.ws.rs</groupId>
+ <artifactId>jsr311-api</artifactId>
+ <version>1.1.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-app-vtn-rsc</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <_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,
+ org.apache.commons.lang.math.*,
+ 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> \ No newline at end of file
diff --git a/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/SubnetWebResource.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/SubnetWebResource.java
new file mode 100644
index 00000000..deb9ca37
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/SubnetWebResource.java
@@ -0,0 +1,379 @@
+/*
+ * 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 com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
+import static javax.ws.rs.core.Response.Status.NOT_FOUND;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+
+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.onlab.packet.IpAddress;
+import org.onlab.packet.IpAddress.Version;
+import org.onlab.packet.IpPrefix;
+import org.onlab.util.ItemNotFoundException;
+import org.onosproject.rest.AbstractWebResource;
+import org.onosproject.vtnrsc.AllocationPool;
+import org.onosproject.vtnrsc.DefaultAllocationPool;
+import org.onosproject.vtnrsc.DefaultHostRoute;
+import org.onosproject.vtnrsc.DefaultSubnet;
+import org.onosproject.vtnrsc.HostRoute;
+import org.onosproject.vtnrsc.Subnet;
+import org.onosproject.vtnrsc.SubnetId;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+@Path("subnets")
+public class SubnetWebResource extends AbstractWebResource {
+ private final Logger log = LoggerFactory.getLogger(SubnetWebResource.class);
+ public static final String SUBNET_NOT_CREATE = "Subnets is failed to create!";
+ public static final String SUBNET_NOT_FOUND = "Subnets is not found";
+ public static final String JSON_NOT_NULL = "JsonNode can not be null";
+
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response listSubnets() {
+ Iterable<Subnet> subnets = get(SubnetService.class).getSubnets();
+ ObjectNode result = new ObjectMapper().createObjectNode();
+ result.set("subnets", new SubnetCodec().encode(subnets, this));
+ return ok(result.toString()).build();
+ }
+
+ @GET
+ @Path("{subnetUUID}")
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getSubnet(@PathParam("subnetUUID") String id) {
+
+ if (!get(SubnetService.class).exists(SubnetId.subnetId(id))) {
+ return Response.status(NOT_FOUND)
+ .entity(SUBNET_NOT_FOUND).build();
+ }
+ Subnet sub = nullIsNotFound(get(SubnetService.class)
+ .getSubnet(SubnetId.subnetId(id)),
+ SUBNET_NOT_FOUND);
+
+ ObjectNode result = new ObjectMapper().createObjectNode();
+ result.set("subnet", new SubnetCodec().encode(sub, this));
+ return ok(result.toString()).build();
+ }
+
+ @POST
+ @Produces(MediaType.APPLICATION_JSON)
+ @Consumes(MediaType.APPLICATION_JSON)
+ public Response createSubnet(final InputStream input) {
+
+ try {
+ ObjectMapper mapper = new ObjectMapper();
+ JsonNode subnode = mapper.readTree(input);
+ Iterable<Subnet> subnets = createOrUpdateByInputStream(subnode);
+ Boolean result = nullIsNotFound((get(SubnetService.class)
+ .createSubnets(subnets)),
+ SUBNET_NOT_CREATE);
+
+ if (!result) {
+ return Response.status(INTERNAL_SERVER_ERROR)
+ .entity(SUBNET_NOT_CREATE).build();
+ }
+ return Response.status(202).entity(result.toString()).build();
+ } catch (Exception e) {
+ return Response.status(INTERNAL_SERVER_ERROR).entity(e.toString())
+ .build();
+ }
+ }
+
+ @PUT
+ @Path("{subnetUUID}")
+ @Produces(MediaType.APPLICATION_JSON)
+ @Consumes(MediaType.APPLICATION_JSON)
+ public Response updateSubnet(@PathParam("id") String id,
+ final InputStream input) {
+ try {
+ ObjectMapper mapper = new ObjectMapper();
+ JsonNode subnode = mapper.readTree(input);
+ Iterable<Subnet> subnets = createOrUpdateByInputStream(subnode);
+ Boolean result = nullIsNotFound(get(SubnetService.class)
+ .updateSubnets(subnets), SUBNET_NOT_FOUND);
+ if (!result) {
+ return Response.status(INTERNAL_SERVER_ERROR)
+ .entity(SUBNET_NOT_FOUND).build();
+ }
+ return Response.status(203).entity(result.toString()).build();
+ } catch (Exception e) {
+ return Response.status(INTERNAL_SERVER_ERROR).entity(e.toString())
+ .build();
+ }
+ }
+
+ @Path("{subnetUUID}")
+ @DELETE
+ public Response deleteSingleSubnet(@PathParam("subnetUUID") String id)
+ throws IOException {
+ try {
+ SubnetId subId = SubnetId.subnetId(id);
+ Set<SubnetId> subIds = new HashSet<>();
+ subIds.add(subId);
+ get(SubnetService.class).removeSubnets(subIds);
+ return Response.status(201).entity("SUCCESS").build();
+ } catch (Exception e) {
+ return Response.status(INTERNAL_SERVER_ERROR).entity(e.toString())
+ .build();
+ }
+ }
+
+ private Iterable<Subnet> createOrUpdateByInputStream(JsonNode subnode) {
+ checkNotNull(subnode, JSON_NOT_NULL);
+ Iterable<Subnet> subnets = null;
+ JsonNode subnetNodes = subnode.get("subnets");
+ if (subnetNodes == null) {
+ subnetNodes = subnode.get("subnet");
+ }
+ log.debug("subnetNodes is {}", subnetNodes.toString());
+ if (subnetNodes.isArray()) {
+ subnets = changeJsonToSubs(subnetNodes);
+ } else {
+ subnets = changeJsonToSub(subnetNodes);
+ }
+ return subnets;
+ }
+
+ /**
+ * Returns a collection of subnets from subnetNodes.
+ *
+ * @param subnetNodes the subnet json node
+ * @return subnets a collection of subnets
+ */
+ public Iterable<Subnet> changeJsonToSubs(JsonNode subnetNodes) {
+ checkNotNull(subnetNodes, JSON_NOT_NULL);
+ Map<SubnetId, Subnet> subMap = new HashMap<>();
+ for (JsonNode subnetNode : subnetNodes) {
+ if (!subnetNode.hasNonNull("id")) {
+ return null;
+ }
+ SubnetId id = SubnetId.subnetId(subnetNode.get("id").asText());
+ String subnetName = subnetNode.get("name").asText();
+ TenantId tenantId = TenantId
+ .tenantId(subnetNode.get("tenant_id").asText());
+ TenantNetworkId networkId = TenantNetworkId
+ .networkId(subnetNode.get("network_id").asText());
+ String version = subnetNode.get("ip_version").asText();
+ Version ipVersion;
+ switch (version) {
+ case "4":
+ ipVersion = Version.INET;
+ break;
+ case "6":
+ ipVersion = Version.INET;
+ break;
+ default:
+ throw new IllegalArgumentException("ipVersion should be 4 or 6.");
+ }
+ IpPrefix cidr = IpPrefix.valueOf(subnetNode.get("cidr").asText());
+ IpAddress gatewayIp = IpAddress
+ .valueOf(subnetNode.get("gateway_ip").asText());
+ Boolean dhcpEnabled = subnetNode.get("enable_dhcp").asBoolean();
+ Boolean shared = subnetNode.get("shared").asBoolean();
+ JsonNode hostRoutes = subnetNode.get("host_routes");
+ Iterable<HostRoute> hostRoutesIt = jsonNodeToHostRoutes(hostRoutes);
+ JsonNode allocationPools = subnetNode.get("allocation_pools");
+ Iterable<AllocationPool> allocationPoolsIt = jsonNodeToAllocationPools(allocationPools);
+ Mode ipV6AddressMode = Mode
+ .valueOf(subnetNode.get("ipv6_address_mode").asText());
+ Mode ipV6RaMode = Mode
+ .valueOf(subnetNode.get("ipv6_ra_mode").asText());
+ Subnet subnet = new DefaultSubnet(id, subnetName, networkId,
+ tenantId, ipVersion, cidr,
+ gatewayIp, dhcpEnabled, shared,
+ Sets.newHashSet(hostRoutesIt), ipV6AddressMode,
+ ipV6RaMode, Sets.newHashSet(allocationPoolsIt));
+ subMap.put(id, subnet);
+ }
+ return Collections.unmodifiableCollection(subMap.values());
+ }
+
+ /**
+ * Returns a collection of subnets from subnetNodes.
+ *
+ * @param subnetNodes the subnet json node
+ * @return subnets a collection of subnets
+ */
+ public Iterable<Subnet> changeJsonToSub(JsonNode subnetNodes) {
+ checkNotNull(subnetNodes, JSON_NOT_NULL);
+ checkArgument(subnetNodes.get("enable_dhcp").isBoolean(), "enable_dhcp should be boolean");
+ checkArgument(subnetNodes.get("shared").isBoolean(), "shared should be boolean");
+ Map<SubnetId, Subnet> subMap = new HashMap<>();
+ if (!subnetNodes.hasNonNull("id")) {
+ return null;
+ }
+ SubnetId id = SubnetId.subnetId(subnetNodes.get("id").asText());
+ String subnetName = subnetNodes.get("name").asText();
+ TenantId tenantId = TenantId
+ .tenantId(subnetNodes.get("tenant_id").asText());
+ TenantNetworkId networkId = TenantNetworkId
+ .networkId(subnetNodes.get("network_id").asText());
+ String version = subnetNodes.get("ip_version").asText();
+ Version ipVersion;
+ switch (version) {
+ case "4":
+ ipVersion = Version.INET;
+ break;
+ case "6":
+ ipVersion = Version.INET;
+ break;
+ default:
+ throw new IllegalArgumentException("ipVersion should be 4 or 6.");
+ }
+
+ IpPrefix cidr = IpPrefix.valueOf(subnetNodes.get("cidr").asText());
+ IpAddress gatewayIp = IpAddress
+ .valueOf(subnetNodes.get("gateway_ip").asText());
+ Boolean dhcpEnabled = subnetNodes.get("enable_dhcp").asBoolean();
+ Boolean shared = subnetNodes.get("shared").asBoolean();
+ JsonNode hostRoutes = subnetNodes.get("host_routes");
+ Iterable<HostRoute> hostRoutesIt = jsonNodeToHostRoutes(hostRoutes);
+ JsonNode allocationPools = subnetNodes.get("allocation_pools");
+ Iterable<AllocationPool> allocationPoolsIt = jsonNodeToAllocationPools(allocationPools);
+
+ Mode ipV6AddressMode = getMode(subnetNodes.get("ipv6_address_mode")
+ .asText());
+ Mode ipV6RaMode = getMode(subnetNodes.get("ipv6_ra_mode").asText());
+
+ Subnet subnet = new DefaultSubnet(id, subnetName, networkId, tenantId,
+ ipVersion, cidr, gatewayIp,
+ dhcpEnabled, shared, Sets.newHashSet(hostRoutesIt),
+ ipV6AddressMode, ipV6RaMode,
+ Sets.newHashSet(allocationPoolsIt));
+ subMap.put(id, subnet);
+ return Collections.unmodifiableCollection(subMap.values());
+ }
+
+ /**
+ * Gets ipv6_address_mode or ipv6_ra_mode type.
+ *
+ * @param mode the String value in JsonNode
+ * @return ipV6Mode Mode of the ipV6Mode
+ */
+ private Mode getMode(String mode) {
+ Mode ipV6Mode;
+ if (mode == null) {
+ return null;
+ }
+ switch (mode) {
+ case "dhcpv6-stateful":
+ ipV6Mode = Mode.DHCPV6_STATEFUL;
+ break;
+ case "dhcpv6-stateless":
+ ipV6Mode = Mode.DHCPV6_STATELESS;
+ break;
+ case "slaac":
+ ipV6Mode = Mode.SLAAC;
+ break;
+ default:
+ ipV6Mode = null;
+ }
+ return ipV6Mode;
+ }
+
+ /**
+ * Changes JsonNode alocPools to a collection of the alocPools.
+ *
+ * @param allocationPools the allocationPools JsonNode
+ * @return a collection of allocationPools
+ */
+ public Iterable<AllocationPool> jsonNodeToAllocationPools(JsonNode allocationPools) {
+ checkNotNull(allocationPools, JSON_NOT_NULL);
+ ConcurrentMap<Integer, AllocationPool> alocplMaps = Maps
+ .newConcurrentMap();
+ Integer i = 0;
+ for (JsonNode node : allocationPools) {
+ IpAddress startIp = IpAddress.valueOf(node.get("start").asText());
+ IpAddress endIp = IpAddress.valueOf(node.get("end").asText());
+ AllocationPool alocPls = new DefaultAllocationPool(startIp, endIp);
+ alocplMaps.putIfAbsent(i, alocPls);
+ i++;
+ }
+ return Collections.unmodifiableCollection(alocplMaps.values());
+ }
+
+ /**
+ * Changes hostRoutes JsonNode to a collection of the hostRoutes.
+ *
+ * @param hostRoutes the hostRoutes json node
+ * @return a collection of hostRoutes
+ */
+ public Iterable<HostRoute> jsonNodeToHostRoutes(JsonNode hostRoutes) {
+ checkNotNull(hostRoutes, JSON_NOT_NULL);
+ ConcurrentMap<Integer, HostRoute> hostRouteMaps = Maps
+ .newConcurrentMap();
+ Integer i = 0;
+ for (JsonNode node : hostRoutes) {
+ IpAddress nexthop = IpAddress.valueOf(node.get("nexthop").asText());
+ IpPrefix destination = IpPrefix.valueOf(node.get("destination")
+ .asText());
+ HostRoute hostRoute = new DefaultHostRoute(nexthop, destination);
+ hostRouteMaps.putIfAbsent(i, hostRoute);
+ i++;
+ }
+ return Collections.unmodifiableCollection(hostRouteMaps.values());
+ }
+
+ /**
+ * Returns the specified item if that items is null; otherwise throws not
+ * found exception.
+ *
+ * @param item item to check
+ * @param <T> item type
+ * @param message not found message
+ * @return item if not null
+ * @throws org.onlab.util.ItemNotFoundException if item is null
+ */
+ protected <T> T nullIsNotFound(T item, String message) {
+ if (item == null) {
+ throw new ItemNotFoundException(message);
+ }
+ return item;
+ }
+
+}
diff --git a/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/TenantNetworkWebResource.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/TenantNetworkWebResource.java
new file mode 100644
index 00000000..0b877822
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/TenantNetworkWebResource.java
@@ -0,0 +1,373 @@
+/*
+ * 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 com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkArgument;
+import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
+import static javax.ws.rs.core.Response.Status.OK;
+import static javax.ws.rs.core.Response.Status.NOT_FOUND;
+
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+
+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.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.onlab.util.ItemNotFoundException;
+import org.onosproject.rest.AbstractWebResource;
+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 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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.Maps;
+
+/**
+ * REST resource for interacting with the inventory of networks.
+ */
+@Path("networks")
+public class TenantNetworkWebResource extends AbstractWebResource {
+ public static final String NETWORK_NOT_FOUND = "Network is not found";
+ public static final String NETWORK_ID_EXIST = "Network id is existed";
+ public static final String NETWORK_ID_NOT_EXIST = "Network id is not existed";
+ public static final String CREATE_NETWORK = "create network";
+ public static final String UPDATE_NETWORK = "update network";
+ public static final String DELETE_NETWORK = "delete network";
+ public static final String JSON_NOT_NULL = "JsonNode can not be null";
+
+ protected static final Logger log = LoggerFactory
+ .getLogger(TenantNetworkWebResource.class);
+ private final ConcurrentMap<TenantNetworkId, TenantNetwork> networksMap = Maps
+ .newConcurrentMap();
+
+ @GET
+ @Produces({ MediaType.APPLICATION_JSON })
+ public Response getNetworks(@QueryParam("id") String queryId,
+ @QueryParam("name") String queryName,
+ @QueryParam("admin_state_up") String queryadminStateUp,
+ @QueryParam("status") String querystate,
+ @QueryParam("shared") String queryshared,
+ @QueryParam("tenant_id") String querytenantId,
+ @QueryParam("router:external") String routerExternal,
+ @QueryParam("provider:network_type") String type,
+ @QueryParam("provider:physical_network") String physicalNetwork,
+ @QueryParam("provider:segmentation_id") String segmentationId) {
+ Iterable<TenantNetwork> networks = get(TenantNetworkService.class)
+ .getNetworks();
+ Iterator<TenantNetwork> networkors = networks.iterator();
+ while (networkors.hasNext()) {
+ TenantNetwork network = networkors.next();
+ if ((queryId == null || queryId.equals(network.id().toString()))
+ && (queryName == null || queryName.equals(network.name()))
+ && (queryadminStateUp == null || queryadminStateUp
+ .equals(network.adminStateUp()))
+ && (querystate == null || querystate.equals(network.state()
+ .toString()))
+ && (queryshared == null || queryshared.equals(network
+ .shared()))
+ && (querytenantId == null || querytenantId.equals(network
+ .tenantId().toString()))
+ && (routerExternal == null || routerExternal.equals(network
+ .routerExternal()))
+ && (type == null || type.equals(network.type()))
+ && (physicalNetwork == null || physicalNetwork
+ .equals(network.physicalNetwork()))
+ && (segmentationId == null || segmentationId.equals(network
+ .segmentationId()))) {
+ networksMap.putIfAbsent(network.id(), network);
+ }
+ }
+ networks = Collections.unmodifiableCollection(networksMap.values());
+ ObjectNode result = new ObjectMapper().createObjectNode();
+ result.set("networks", new TenantNetworkCodec().encode(networks, this));
+
+ return ok(result.toString()).build();
+ }
+
+ private State isState(String state) {
+ if (state.equals("ACTIVE")) {
+ return TenantNetwork.State.ACTIVE;
+ } else if (state.equals("BUILD")) {
+ return TenantNetwork.State.BUILD;
+ } else if (state.equals("DOWN")) {
+ return TenantNetwork.State.DOWN;
+ } else if (state.equals("ERROR")) {
+ return TenantNetwork.State.ERROR;
+ } else {
+ return null;
+ }
+ }
+
+ private Type isType(String type) {
+ if (type.equals("LOCAL")) {
+ return TenantNetwork.Type.LOCAL;
+ } else {
+ return null;
+ }
+ }
+
+ @GET
+ @Path("{id}")
+ @Produces({ MediaType.APPLICATION_JSON })
+ public Response getNetwork(@PathParam("id") String id) {
+
+ if (!get(TenantNetworkService.class).exists(TenantNetworkId
+ .networkId(id))) {
+ return Response.status(NOT_FOUND)
+ .entity(NETWORK_NOT_FOUND).build();
+ }
+ TenantNetwork network = nullIsNotFound(get(TenantNetworkService.class)
+ .getNetwork(TenantNetworkId.networkId(id)), NETWORK_NOT_FOUND);
+ ObjectNode result = new ObjectMapper().createObjectNode();
+ result.set("network", new TenantNetworkCodec().encode(network, this));
+
+ return ok(result.toString()).build();
+
+ }
+
+ @POST
+ @Produces(MediaType.APPLICATION_JSON)
+ @Consumes(MediaType.APPLICATION_JSON)
+ public Response createNetworks(InputStream input) {
+ try {
+ ObjectMapper mapper = new ObjectMapper();
+ JsonNode cfg = mapper.readTree(input);
+ JsonNode nodes = null;
+ Iterable<TenantNetwork> networks = null;
+ if (cfg.get("network") != null) {
+ nodes = cfg.get("network");
+ if (nodes.isArray()) {
+ networks = changeJson2objs(nodes);
+ } else {
+ networks = changeJson2obj(CREATE_NETWORK, null, nodes);
+ }
+ } else if (cfg.get("networks") != null) {
+ nodes = cfg.get("networks");
+ networks = changeJson2objs(nodes);
+ }
+ Boolean issuccess = nullIsNotFound((get(TenantNetworkService.class)
+ .createNetworks(networks)),
+ NETWORK_NOT_FOUND);
+
+ if (!issuccess) {
+ return Response.status(INTERNAL_SERVER_ERROR)
+ .entity(NETWORK_ID_EXIST).build();
+ }
+ return Response.status(OK).entity(issuccess.toString()).build();
+ } catch (Exception e) {
+ log.error("Creates tenantNetwork exception {}.", e.toString());
+ return Response.status(INTERNAL_SERVER_ERROR).entity(e.toString())
+ .build();
+ }
+ }
+
+ @PUT
+ @Path("{id}")
+ @Produces(MediaType.APPLICATION_JSON)
+ @Consumes(MediaType.APPLICATION_JSON)
+ public Response updateNetworks(@PathParam("id") String id, InputStream input) {
+ try {
+ ObjectMapper mapper = new ObjectMapper();
+ JsonNode cfg = mapper.readTree(input);
+ JsonNode nodes = null;
+ Iterable<TenantNetwork> networks = null;
+ if (cfg.get("network") != null) {
+ nodes = cfg.get("network");
+ if (nodes.isArray()) {
+ networks = changeJson2objs(nodes);
+ } else {
+ networks = changeJson2obj(UPDATE_NETWORK,
+ TenantNetworkId.networkId(id),
+ nodes);
+ }
+ } else if (cfg.get("networks") != null) {
+ nodes = cfg.get("networks");
+ networks = changeJson2objs(nodes);
+ }
+ Boolean issuccess = nullIsNotFound((get(TenantNetworkService.class)
+ .updateNetworks(networks)),
+ NETWORK_NOT_FOUND);
+ if (!issuccess) {
+ return Response.status(INTERNAL_SERVER_ERROR)
+ .entity(NETWORK_ID_NOT_EXIST).build();
+ }
+ return Response.status(OK).entity(issuccess.toString()).build();
+ } catch (Exception e) {
+ log.error("Updates tenantNetwork failed because of exception {}.",
+ e.toString());
+ return Response.status(INTERNAL_SERVER_ERROR).entity(e.toString())
+ .build();
+ }
+ }
+
+ @DELETE
+ @Path("{id}")
+ public Response deleteNetworks(@PathParam("id") String id) {
+ log.debug("Deletes network by identifier {}.", id);
+ Set<TenantNetworkId> networkSet = new HashSet<>();
+ networkSet.add(TenantNetworkId.networkId(id));
+ Boolean issuccess = nullIsNotFound(get(TenantNetworkService.class)
+ .removeNetworks(networkSet), NETWORK_NOT_FOUND);
+ if (!issuccess) {
+ log.debug("Network identifier {} is not existed", id);
+ return Response.status(INTERNAL_SERVER_ERROR)
+ .entity(NETWORK_ID_NOT_EXIST).build();
+ }
+ return Response.status(OK).entity(issuccess.toString()).build();
+ }
+
+ /**
+ * Returns a collection of tenantNetworks.
+ *
+ * @param flag the flag
+ * @param networkId network identifier
+ * @param node the network json node
+ * @return a collection of tenantNetworks
+ */
+ public Iterable<TenantNetwork> changeJson2obj(String flag,
+ TenantNetworkId networkId,
+ JsonNode node) {
+ checkNotNull(node, JSON_NOT_NULL);
+ TenantNetwork network = null;
+ ConcurrentMap<TenantNetworkId, TenantNetwork> networksMap = Maps
+ .newConcurrentMap();
+ if (node != null) {
+ checkArgument(node.get("admin_state_up").isBoolean(), "admin_state_up should be boolean");
+ checkArgument(node.get("shared").isBoolean(), "shared should be boolean");
+ checkArgument(node.get("router:external").isBoolean(), "router:external should be boolean");
+ String name = node.get("name").asText();
+ boolean adminStateUp = node.get("admin_state_up").asBoolean();
+ String state = node.get("status").asText();
+ boolean shared = node.get("shared").asBoolean();
+ String tenantId = node.get("tenant_id").asText();
+ boolean routerExternal = node.get("router:external").asBoolean();
+ String type = node.get("provider:network_type").asText();
+ String physicalNetwork = node.get("provider:physical_network")
+ .asText();
+ String segmentationId = node.get("provider:segmentation_id")
+ .asText();
+ TenantNetworkId id = null;
+ if (flag == CREATE_NETWORK) {
+ id = TenantNetworkId.networkId(node.get("id").asText());
+ } else if (flag == UPDATE_NETWORK) {
+ id = networkId;
+ }
+ network = new DefaultTenantNetwork(
+ id,
+ name,
+ adminStateUp,
+ isState(state),
+ shared,
+ TenantId.tenantId(tenantId),
+ routerExternal,
+ isType(type),
+ PhysicalNetwork
+ .physicalNetwork(physicalNetwork),
+ SegmentationId
+ .segmentationId(segmentationId));
+ networksMap.putIfAbsent(id, network);
+ }
+ return Collections.unmodifiableCollection(networksMap.values());
+ }
+
+ /**
+ * Returns a collection of tenantNetworks.
+ *
+ * @param nodes the network jsonnodes
+ * @return a collection of tenantNetworks
+ */
+ public Iterable<TenantNetwork> changeJson2objs(JsonNode nodes) {
+ checkNotNull(nodes, JSON_NOT_NULL);
+ TenantNetwork network = null;
+ ConcurrentMap<TenantNetworkId, TenantNetwork> networksMap = Maps
+ .newConcurrentMap();
+ if (nodes != null) {
+ for (JsonNode node : nodes) {
+ String id = node.get("id").asText();
+ String name = node.get("name").asText();
+ boolean adminStateUp = node.get("admin_state_up").asBoolean();
+ String state = node.get("status").asText();
+ boolean shared = node.get("shared").asBoolean();
+ String tenantId = node.get("tenant_id").asText();
+ boolean routerExternal = node.get("router:external")
+ .asBoolean();
+ String type = node.get("provider:network_type").asText();
+ String physicalNetwork = node.get("provider:physical_network")
+ .asText();
+ String segmentationId = node.get("provider:segmentation_id")
+ .asText();
+ network = new DefaultTenantNetwork(
+ TenantNetworkId
+ .networkId(id),
+ name,
+ adminStateUp,
+ isState(state),
+ shared,
+ TenantId.tenantId(tenantId),
+ routerExternal,
+ isType(type),
+ PhysicalNetwork
+ .physicalNetwork(physicalNetwork),
+ SegmentationId
+ .segmentationId(segmentationId));
+ networksMap.putIfAbsent(TenantNetworkId.networkId(id), network);
+ }
+ }
+ return Collections.unmodifiableCollection(networksMap.values());
+ }
+
+ /**
+ * Returns the specified item if that items is null; otherwise throws not
+ * found exception.
+ *
+ * @param item item to check
+ * @param <T> item type
+ * @param message not found message
+ * @return item if not null
+ * @throws org.onlab.util.ItemNotFoundException if item is null
+ */
+ protected <T> T nullIsNotFound(T item, String message) {
+ if (item == null) {
+ throw new ItemNotFoundException(message);
+ }
+ return item;
+ }
+}
diff --git a/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/VirtualPortWebResource.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/VirtualPortWebResource.java
new file mode 100644
index 00000000..03d3a653
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/VirtualPortWebResource.java
@@ -0,0 +1,412 @@
+/*
+ * 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 com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
+import static javax.ws.rs.core.Response.Status.OK;
+import static javax.ws.rs.core.Response.Status.NOT_FOUND;
+
+import java.io.InputStream;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+
+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.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onlab.util.ItemNotFoundException;
+import org.onosproject.net.DeviceId;
+import org.onosproject.rest.AbstractWebResource;
+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.VirtualPort.State;
+import org.onosproject.vtnrsc.VirtualPortId;
+import org.onosproject.vtnrsc.virtualport.VirtualPortService;
+import org.onosproject.vtnrsc.web.VirtualPortCodec;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+/**
+ * REST resource for interacting with the inventory of infrastructure
+ * virtualPort.
+ */
+@Path("ports")
+public class VirtualPortWebResource extends AbstractWebResource {
+ public static final String VPORT_NOT_FOUND = "VirtualPort is not found";
+ public static final String VPORT_ID_EXIST = "VirtualPort id is exist";
+ public static final String VPORT_ID_NOT_EXIST = "VirtualPort id is not exist";
+ public static final String JSON_NOT_NULL = "JsonNode can not be null";
+ protected static final Logger log = LoggerFactory
+ .getLogger(VirtualPortService.class);
+
+ @GET
+ @Produces({ MediaType.APPLICATION_JSON })
+ public Response getPorts() {
+ Iterable<VirtualPort> virtualPorts = get(VirtualPortService.class)
+ .getPorts();
+ ObjectNode result = new ObjectMapper().createObjectNode();
+ result.set("ports", new VirtualPortCodec().encode(virtualPorts, this));
+ return ok(result.toString()).build();
+ }
+
+ @GET
+ @Path("{id}")
+ @Produces({ MediaType.APPLICATION_JSON })
+ public Response getportsById(@PathParam("id") String id) {
+
+ if (!get(VirtualPortService.class).exists(VirtualPortId.portId(id))) {
+ return Response.status(NOT_FOUND)
+ .entity(VPORT_NOT_FOUND).build();
+ }
+ VirtualPort virtualPort = nullIsNotFound(get(VirtualPortService.class)
+ .getPort(VirtualPortId.portId(id)), VPORT_NOT_FOUND);
+ ObjectNode result = new ObjectMapper().createObjectNode();
+ result.set("port", new VirtualPortCodec().encode(virtualPort, this));
+ return ok(result.toString()).build();
+ }
+
+ @POST
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response createPorts(InputStream input) {
+ try {
+ ObjectMapper mapper = new ObjectMapper();
+ JsonNode cfg = mapper.readTree(input);
+ Iterable<VirtualPort> vPorts = createOrUpdateByInputStream(cfg);
+ Boolean issuccess = nullIsNotFound(get(VirtualPortService.class)
+ .createPorts(vPorts), VPORT_NOT_FOUND);
+ if (!issuccess) {
+ return Response.status(INTERNAL_SERVER_ERROR)
+ .entity(VPORT_ID_NOT_EXIST).build();
+ }
+ return Response.status(OK).entity(issuccess.toString()).build();
+ } catch (Exception e) {
+ log.error("Creates VirtualPort failed because of exception {}",
+ e.toString());
+ return Response.status(INTERNAL_SERVER_ERROR).entity(e.toString())
+ .build();
+ }
+ }
+
+ @Path("{portUUID}")
+ @DELETE
+ public Response deletePorts(@PathParam("portUUID") String id) {
+ Set<VirtualPortId> vPortIds = new HashSet<>();
+ try {
+ if (id != null) {
+ vPortIds.add(VirtualPortId.portId(id));
+ }
+ Boolean issuccess = nullIsNotFound(get(VirtualPortService.class)
+ .removePorts(vPortIds), VPORT_NOT_FOUND);
+ if (!issuccess) {
+ return Response.status(INTERNAL_SERVER_ERROR)
+ .entity(VPORT_ID_NOT_EXIST).build();
+ }
+ return Response.status(OK).entity(issuccess.toString()).build();
+ } catch (Exception e) {
+ log.error("Deletes VirtualPort failed because of exception {}",
+ e.toString());
+ return Response.status(INTERNAL_SERVER_ERROR).entity(e.toString())
+ .build();
+ }
+ }
+
+ @PUT
+ @Path("{id}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response updatePorts(@PathParam("id") String id, InputStream input) {
+ try {
+ ObjectMapper mapper = new ObjectMapper();
+ JsonNode cfg = mapper.readTree(input);
+ Iterable<VirtualPort> vPorts = createOrUpdateByInputStream(cfg);
+ Boolean issuccess = nullIsNotFound(get(VirtualPortService.class)
+ .updatePorts(vPorts), VPORT_NOT_FOUND);
+ if (!issuccess) {
+ return Response.status(INTERNAL_SERVER_ERROR)
+ .entity(VPORT_ID_NOT_EXIST).build();
+ }
+ return Response.status(OK).entity(issuccess.toString()).build();
+ } catch (Exception e) {
+ log.error("Updates failed because of exception {}", e.toString());
+ return Response.status(INTERNAL_SERVER_ERROR).entity(e.toString())
+ .build();
+ }
+ }
+
+ /**
+ * Returns a Object of the currently known infrastructure virtualPort.
+ *
+ * @param vPortNode the virtualPort json node
+ * @return a collection of virtualPorts
+ */
+ public Iterable<VirtualPort> createOrUpdateByInputStream(JsonNode vPortNode) {
+ checkNotNull(vPortNode, JSON_NOT_NULL);
+ JsonNode vPortNodes = vPortNode.get("ports");
+ if (vPortNodes == null) {
+ vPortNodes = vPortNode.get("port");
+ }
+ if (vPortNodes.isArray()) {
+ return changeJsonToPorts(vPortNodes);
+ } else {
+ return changeJsonToPort(vPortNodes);
+ }
+ }
+
+ /**
+ * Returns the iterable collection of virtualports from subnetNodes.
+ *
+ * @param vPortNodes the virtualPort json node
+ * @return virtualPorts a collection of virtualPorts
+ */
+ public Iterable<VirtualPort> changeJsonToPorts(JsonNode vPortNodes) {
+ checkNotNull(vPortNodes, JSON_NOT_NULL);
+ Map<VirtualPortId, VirtualPort> portMap = new HashMap<>();
+ Map<String, String> strMap = new HashMap<>();
+ for (JsonNode vPortnode : vPortNodes) {
+ VirtualPortId id = VirtualPortId.portId(vPortnode.get("id")
+ .asText());
+ String name = vPortnode.get("name").asText();
+ TenantId tenantId = TenantId.tenantId(vPortnode.get("tenant_id")
+ .asText());
+ TenantNetworkId networkId = TenantNetworkId.networkId(vPortnode
+ .get("network_id").asText());
+ checkArgument(vPortnode.get("admin_state_up").isBoolean(), "admin_state_up should be boolean");
+ Boolean adminStateUp = vPortnode.get("admin_state_up").asBoolean();
+ String state = vPortnode.get("status").asText();
+ MacAddress macAddress = MacAddress.valueOf(vPortnode
+ .get("mac_address").asText());
+ DeviceId deviceId = DeviceId.deviceId(vPortnode.get("device_id")
+ .asText());
+ String deviceOwner = vPortnode.get("device_owner").asText();
+ JsonNode fixedIpNodes = vPortNodes.get("fixed_ips");
+ Set<FixedIp> fixedIps = new HashSet<>();
+ for (JsonNode fixedIpNode : fixedIpNodes) {
+ FixedIp fixedIp = jsonNodeToFixedIps(fixedIpNode);
+ fixedIps.add(fixedIp);
+ }
+
+ BindingHostId bindingHostId = BindingHostId
+ .bindingHostId(vPortnode.get("binding:host_id").asText());
+ String bindingVnicType = vPortnode.get("binding:vnic_type")
+ .asText();
+ String bindingVifType = vPortnode.get("binding:vif_type").asText();
+ String bindingVifDetails = vPortnode.get("binding:vif_details")
+ .asText();
+ JsonNode allowedAddressPairJsonNode = vPortnode
+ .get("allowed_address_pairs");
+ Collection<AllowedAddressPair> allowedAddressPairs =
+ jsonNodeToAllowedAddressPair(allowedAddressPairJsonNode);
+ JsonNode securityGroupNode = vPortnode.get("security_groups");
+ Collection<SecurityGroup> securityGroups = jsonNodeToSecurityGroup(securityGroupNode);
+ strMap.put("name", name);
+ strMap.put("deviceOwner", deviceOwner);
+ strMap.put("bindingVnicType", bindingVnicType);
+ strMap.put("bindingVifType", bindingVifType);
+ strMap.put("bindingVifDetails", bindingVifDetails);
+ VirtualPort vPort = new DefaultVirtualPort(id, networkId,
+ adminStateUp, strMap,
+ isState(state),
+ macAddress, tenantId,
+ deviceId, fixedIps,
+ bindingHostId,
+ Sets.newHashSet(allowedAddressPairs),
+ Sets.newHashSet(securityGroups));
+ portMap.put(id, vPort);
+ }
+ return Collections.unmodifiableCollection(portMap.values());
+ }
+
+ /**
+ * Returns a collection of virtualPorts from subnetNodes.
+ *
+ * @param vPortNodes the virtualPort json node
+ * @return virtualPorts a collection of virtualPorts
+ */
+ public Iterable<VirtualPort> changeJsonToPort(JsonNode vPortNodes) {
+ checkNotNull(vPortNodes, JSON_NOT_NULL);
+ Map<VirtualPortId, VirtualPort> vportMap = new HashMap<>();
+ Map<String, String> strMap = new HashMap<>();
+ VirtualPortId id = VirtualPortId.portId(vPortNodes.get("id").asText());
+ String name = vPortNodes.get("name").asText();
+ TenantId tenantId = TenantId.tenantId(vPortNodes.get("tenant_id")
+ .asText());
+ TenantNetworkId networkId = TenantNetworkId.networkId(vPortNodes
+ .get("network_id").asText());
+ Boolean adminStateUp = vPortNodes.get("admin_state_up").asBoolean();
+ String state = vPortNodes.get("status").asText();
+ MacAddress macAddress = MacAddress.valueOf(vPortNodes
+ .get("mac_address").asText());
+ DeviceId deviceId = DeviceId.deviceId(vPortNodes.get("device_id")
+ .asText());
+ String deviceOwner = vPortNodes.get("device_owner").asText();
+ JsonNode fixedIpNodes = vPortNodes.get("fixed_ips");
+ Set<FixedIp> fixedIps = new HashSet<>();
+ for (JsonNode fixedIpNode : fixedIpNodes) {
+ FixedIp fixedIp = jsonNodeToFixedIps(fixedIpNode);
+ fixedIps.add(fixedIp);
+ }
+
+ BindingHostId bindingHostId = BindingHostId
+ .bindingHostId(vPortNodes.get("binding:host_id").asText());
+ String bindingVnicType = vPortNodes.get("binding:vnic_type").asText();
+ String bindingVifType = vPortNodes.get("binding:vif_type").asText();
+ String bindingVifDetails = vPortNodes.get("binding:vif_details")
+ .asText();
+ JsonNode allowedAddressPairJsonNode = vPortNodes
+ .get("allowed_address_pairs");
+ Collection<AllowedAddressPair> allowedAddressPairs =
+ jsonNodeToAllowedAddressPair(allowedAddressPairJsonNode);
+ JsonNode securityGroupNode = vPortNodes.get("security_groups");
+ Collection<SecurityGroup> securityGroups = jsonNodeToSecurityGroup(securityGroupNode);
+ strMap.put("name", name);
+ strMap.put("deviceOwner", deviceOwner);
+ strMap.put("bindingVnicType", bindingVnicType);
+ strMap.put("bindingVifType", bindingVifType);
+ strMap.put("bindingVifDetails", bindingVifDetails);
+ VirtualPort vPort = new DefaultVirtualPort(id, networkId, adminStateUp,
+ strMap, isState(state),
+ macAddress, tenantId,
+ deviceId, fixedIps,
+ bindingHostId,
+ Sets.newHashSet(allowedAddressPairs),
+ Sets.newHashSet(securityGroups));
+ vportMap.put(id, vPort);
+
+ return Collections.unmodifiableCollection(vportMap.values());
+ }
+
+ /**
+ * Returns a Object of the currently known infrastructure virtualPort.
+ *
+ * @param allowedAddressPairs the allowedAddressPairs json node
+ * @return a collection of allowedAddressPair
+ */
+ public Collection<AllowedAddressPair> jsonNodeToAllowedAddressPair(JsonNode allowedAddressPairs) {
+ checkNotNull(allowedAddressPairs, JSON_NOT_NULL);
+ ConcurrentMap<Integer, AllowedAddressPair> allowMaps = Maps
+ .newConcurrentMap();
+ int i = 0;
+ for (JsonNode node : allowedAddressPairs) {
+ IpAddress ip = IpAddress.valueOf(node.get("ip_address").asText());
+ MacAddress mac = MacAddress.valueOf(node.get("mac_address")
+ .asText());
+ AllowedAddressPair allows = AllowedAddressPair
+ .allowedAddressPair(ip, mac);
+ allowMaps.put(i, allows);
+ i++;
+ }
+ log.debug("The jsonNode of allowedAddressPairallow is {}"
+ + allowedAddressPairs.toString());
+ return Collections.unmodifiableCollection(allowMaps.values());
+ }
+
+ /**
+ * Returns a collection of virtualPorts.
+ *
+ * @param securityGroups the virtualPort jsonnode
+ * @return a collection of securityGroups
+ */
+ public Collection<SecurityGroup> jsonNodeToSecurityGroup(JsonNode securityGroups) {
+ checkNotNull(securityGroups, JSON_NOT_NULL);
+ ConcurrentMap<Integer, SecurityGroup> securMaps = Maps
+ .newConcurrentMap();
+ int i = 0;
+ for (JsonNode node : securityGroups) {
+ SecurityGroup securityGroup = SecurityGroup
+ .securityGroup(node.asText());
+ securMaps.put(i, securityGroup);
+ i++;
+ }
+ return Collections.unmodifiableCollection(securMaps.values());
+ }
+
+ /**
+ * Returns a collection of fixedIps.
+ *
+ * @param fixedIpNode the fixedIp jsonnode
+ * @return a collection of SecurityGroup
+ */
+ public FixedIp jsonNodeToFixedIps(JsonNode fixedIpNode) {
+ SubnetId subnetId = SubnetId.subnetId(fixedIpNode.get("subnet_id")
+ .asText());
+ IpAddress ipAddress = IpAddress.valueOf(fixedIpNode.get("ip_address")
+ .asText());
+ FixedIp fixedIps = FixedIp.fixedIp(subnetId, ipAddress);
+ return fixedIps;
+ }
+
+ /**
+ * Returns VirtualPort State.
+ *
+ * @param state the virtualport state
+ * @return the virtualPort state
+ */
+ private State isState(String state) {
+ if (state.equals("ACTIVE")) {
+ return VirtualPort.State.ACTIVE;
+ } else {
+ return VirtualPort.State.DOWN;
+ }
+
+ }
+
+ /**
+ * Returns the specified item if that items is null; otherwise throws not
+ * found exception.
+ *
+ * @param item item to check
+ * @param <T> item type
+ * @param message not found message
+ * @return item if not null
+ * @throws org.onlab.util.ItemNotFoundException if item is null
+ */
+ protected <T> T nullIsNotFound(T item, String message) {
+ if (item == null) {
+ throw new ItemNotFoundException(message);
+ }
+ return item;
+ }
+}
diff --git a/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/package-info.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/package-info.java
new file mode 100644
index 00000000..c81fc3d8
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/package-info.java
@@ -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.
+ */
+
+/**
+ * VTN web that used rest to creat vtn resources.
+ */
+package org.onosproject.vtnweb.resources;
diff --git a/framework/src/onos/apps/vtn/vtnweb/src/main/webapp/WEB-INF/web.xml b/framework/src/onos/apps/vtn/vtnweb/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 00000000..4cc12455
--- /dev/null
+++ b/framework/src/onos/apps/vtn/vtnweb/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,45 @@
+<?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>VTNRSC 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.vtnweb.resources.TenantNetworkWebResource,
+ org.onosproject.vtnweb.resources.SubnetWebResource,
+ org.onosproject.vtnweb.resources.VirtualPortWebResource
+ </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>
diff --git a/framework/src/onos/bgp/api/pom.xml b/framework/src/onos/bgp/api/pom.xml
new file mode 100755
index 00000000..6fa1cc7b
--- /dev/null
+++ b/framework/src/onos/bgp/api/pom.xml
@@ -0,0 +1,95 @@
+<?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-bgp</artifactId>
+ <version>1.4.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>onos-bgp-api</artifactId>
+ <packaging>bundle</packaging>
+
+ <description>ONOS BGP controller subsystem API</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-bgpio</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.netty</groupId>
+ <artifactId>netty</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onlab-misc</artifactId>
+ </dependency>
+
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-shade-plugin</artifactId>
+ <version>2.3</version>
+ <configuration>
+ <artifactSet>
+ <excludes>
+ <exclude>io.netty:netty</exclude>
+ <exclude>com.google.guava:guava</exclude>
+ <exclude>org.slf4j:slfj-api</exclude>
+ <exclude>ch.qos.logback:logback-core</exclude>
+ <exclude>ch.qos.logback:logback-classic</exclude>
+ <exclude>com.google.code.findbugs:annotations</exclude>
+ </excludes>
+ </artifactSet>
+ </configuration>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>shade</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Export-Package>
+ org.onosproject.bgp.*,org.onosproject.bgpio.*,org.onosproject.bgp.controller
+ </Export-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/framework/src/onos/bgp/api/src/main/java/org/onosproject/bgp/controller/BGPCfg.java b/framework/src/onos/bgp/api/src/main/java/org/onosproject/bgp/controller/BGPCfg.java
new file mode 100755
index 00000000..46165d87
--- /dev/null
+++ b/framework/src/onos/bgp/api/src/main/java/org/onosproject/bgp/controller/BGPCfg.java
@@ -0,0 +1,297 @@
+/*
+ * 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;
+
+import java.util.TreeMap;
+
+/**
+ * Abstraction of an BGP configuration. Manages the BGP configuration from CLI to the BGP controller.
+ */
+public interface BGPCfg {
+
+ enum State {
+ /**
+ * Signifies that its just created.
+ */
+ INIT,
+
+ /**
+ * Signifies that only IP Address is configured.
+ */
+ IP_CONFIGURED,
+
+ /**
+ * Signifies that only Autonomous System is configured.
+ */
+ AS_CONFIGURED,
+
+ /**
+ * Signifies that both IP and Autonomous System is configured.
+ */
+ IP_AS_CONFIGURED
+ }
+
+ /**
+ * Returns the status of the configuration based on this state certain operations like connection is handled.
+ *
+ * @return State of the configuration
+ */
+ State getState();
+
+ /**
+ * To set the current state of the configuration.
+ *
+ * @param state Configuration State enum
+ */
+ void setState(State state);
+
+ /**
+ * Get the status of the link state support for this BGP speaker.
+ *
+ * @return true if the link state is supported else false
+ */
+ boolean getLsCapability();
+
+ /**
+ * Set the link state support to this BGP speaker.
+ *
+ * @param lscapability true value if link state is supported else false
+ */
+ void setLsCapability(boolean lscapability);
+
+ /**
+ * Get the status of the 32 bit AS support for this BGP speaker.
+ *
+ * @return true if the 32 bit AS number is supported else false
+ */
+ boolean getLargeASCapability();
+
+ /**
+ * Set the 32 bit AS support capability to this BGP speaker.
+ *
+ * @param largeAs true value if the 32 bit AS is supported else false
+ */
+ void setLargeASCapability(boolean largeAs);
+
+ /**
+ * Set the AS number to which this BGP speaker belongs.
+ *
+ * @param localAs 16 or 32 bit AS number, length is dependent on the capability
+ */
+ void setAsNumber(int localAs);
+
+ /**
+ * Get the AS number to which this BGP speaker belongs.
+ *
+ * @return 16 or 32 bit AS number, length is dependent on the capability
+ */
+ int getAsNumber();
+
+ /**
+ * Get the connection retry count number.
+ *
+ * @return connection retry count if there is a connection error
+ */
+ int getMaxConnRetryCount();
+
+ /**
+ * Set the connection retry count.
+ *
+ * @param retryCount number of times to try to connect if there is any error
+ */
+ void setMaxConnRetryCout(int retryCount);
+
+ /**
+ * Get the connection retry time in seconds.
+ *
+ * @return connection retry time in seconds
+ */
+ int getMaxConnRetryTime();
+
+ /**
+ * Set the connection retry time in seconds.
+ *
+ * @param retryTime connection retry times in seconds
+ */
+ void setMaxConnRetryTime(int retryTime);
+
+ /**
+ * Set the keep alive timer for the connection.
+ *
+ * @param holdTime connection hold timer in seconds
+ */
+ void setHoldTime(short holdTime);
+
+ /**
+ * Returns the connection hold timer in seconds.
+ *
+ * @return connection hold timer in seconds
+ */
+ short getHoldTime();
+
+ /**
+ * Returns the maximum number of session supported.
+ *
+ * @return maximum number of session supported
+ */
+ int getMaxSession();
+
+ /**
+ * Set the maximum number of sessions to support.
+ *
+ * @param maxsession maximum number of session
+ */
+ void setMaxSession(int maxsession);
+
+ /**
+ * Returns the Router ID of this BGP speaker.
+ *
+ * @return IP address in string format
+ */
+ String getRouterId();
+
+ /**
+ * Set the Router ID of this BGP speaker.
+ *
+ * @param routerid IP address in string format
+ */
+ void setRouterId(String routerid);
+
+ /**
+ * Add the BGP peer IP address and the AS number to which it belongs.
+ *
+ * @param routerid IP address in string format
+ * @param remoteAs AS number to which it belongs
+ *
+ * @return true if added successfully else false
+ */
+ boolean addPeer(String routerid, int remoteAs);
+
+ /**
+ * Add the BGP peer IP address and the keep alive time.
+ *
+ * @param routerid IP address in string format
+ * @param holdTime keep alive time for the connection
+ *
+ * @return true if added successfully else false
+ */
+ boolean addPeer(String routerid, short holdTime);
+
+ /**
+ * Add the BGP peer IP address, the AS number to which it belongs and keep alive time.
+ *
+ * @param routerid IP address in string format
+ * @param remoteAs AS number to which it belongs
+ * @param holdTime keep alive time for the connection
+ *
+ * @return true if added successfully else false
+ */
+ boolean addPeer(String routerid, int remoteAs, short holdTime);
+
+ /**
+ * Remove the BGP peer with this IP address.
+ *
+ * @param routerid router IP address
+ *
+ * @return true if removed successfully else false
+ */
+ boolean removePeer(String routerid);
+
+ /**
+ * Connect to BGP peer with this IP address.
+ *
+ * @param routerid router IP address
+ *
+ * @return true of the configuration is found and able to connect else false
+ */
+ boolean connectPeer(String routerid);
+
+ /**
+ * Disconnect this BGP peer with this IP address.
+ *
+ * @param routerid router IP address in string format
+ *
+ * @return true if the configuration is found and able to disconnect else false
+ */
+ boolean disconnectPeer(String routerid);
+
+ /**
+ * Returns the peer tree information.
+ *
+ * @return return the tree map with IP as key and BGPPeerCfg as object
+ */
+ TreeMap<String, BGPPeerCfg> displayPeers();
+
+ /**
+ * Return the BGP Peer information with this matching IP.
+ *
+ * @param routerid router IP address in string format
+ *
+ * @return BGPPeerCfg object
+ */
+ BGPPeerCfg displayPeers(String routerid);
+
+ /**
+ * Check if this BGP peer is configured.
+ *
+ * @param routerid router IP address in string format
+ *
+ * @return true if configured exists else false
+ */
+ boolean isPeerConfigured(String routerid);
+
+ /**
+ * Check if this BGP speaker is having connection with the peer.
+ *
+ * @param routerid router IP address in string format
+ *
+ * @return true if the connection exists else false
+ */
+ boolean isPeerConnected(String routerid);
+
+ /**
+ * Return the peer tree map.
+ *
+ * @return return the tree map with IP as key and BGPPeerCfg as object
+ */
+ TreeMap<String, BGPPeerCfg> getPeerTree();
+
+ /**
+ * Set the current connection state information.
+ *
+ * @param routerid router IP address in string format
+ * @param state state information
+ */
+ void setPeerConnState(String routerid, BGPPeerCfg.State state);
+
+ /**
+ * Check if the peer can be connected or not.
+ *
+ * @param routerid router IP address in string format
+ *
+ * @return true if the peer can be connected else false
+ */
+ boolean isPeerConnectable(String routerid);
+
+ /**
+ * Get the current peer connection state information.
+ *
+ * @param routerid router IP address in string format
+ *
+ * @return state information
+ */
+ BGPPeerCfg.State getPeerConnState(String routerid);
+}
diff --git a/framework/src/onos/bgp/api/src/main/java/org/onosproject/bgp/controller/BGPController.java b/framework/src/onos/bgp/api/src/main/java/org/onosproject/bgp/controller/BGPController.java
new file mode 100755
index 00000000..6d758122
--- /dev/null
+++ b/framework/src/onos/bgp/api/src/main/java/org/onosproject/bgp/controller/BGPController.java
@@ -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.bgp.controller;
+
+import org.onosproject.bgpio.protocol.BGPMessage;
+
+/**
+ * Abstraction of an BGP controller. Serves as a one stop shop for obtaining BGP devices and (un)register listeners
+ * on bgp events
+ */
+public interface BGPController {
+
+ /**
+ * Send a message to a particular bgp peer.
+ *
+ * @param bgpId the id of the peer to send message.
+ * @param msg the message to send
+ */
+ void writeMsg(BGPId bgpId, BGPMessage msg);
+
+ /**
+ * Process a message and notify the appropriate listeners.
+ *
+ * @param bgpId id of the peer the message arrived on
+ * @param msg the message to process.
+ */
+ void processBGPPacket(BGPId bgpId, BGPMessage msg);
+
+ /**
+ * Get the BGPConfig class to the caller.
+ *
+ * @return configuration object
+ */
+ BGPCfg getConfig();
+} \ No newline at end of file
diff --git a/framework/src/onos/bgp/api/src/main/java/org/onosproject/bgp/controller/BGPId.java b/framework/src/onos/bgp/api/src/main/java/org/onosproject/bgp/controller/BGPId.java
new file mode 100755
index 00000000..636e72f3
--- /dev/null
+++ b/framework/src/onos/bgp/api/src/main/java/org/onosproject/bgp/controller/BGPId.java
@@ -0,0 +1,121 @@
+/*
+ * 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;
+
+import org.onlab.packet.IpAddress;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Objects;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+/**
+ * The class representing a network peer bgp ip.
+ * This class is immutable.
+ */
+public final class BGPId {
+
+ private static final String SCHEME = "bgp";
+ private static final long UNKNOWN = 0;
+ private final IpAddress ipAddress;
+
+ /**
+ * Private constructor.
+ */
+ private BGPId(IpAddress ipAddress) {
+ this.ipAddress = ipAddress;
+ }
+
+ /**
+ * Create a BGPId from ip address.
+ *
+ * @param ipAddress IP address
+ * @return object of BGPId
+ */
+ public static BGPId bgpId(IpAddress ipAddress) {
+ return new BGPId(ipAddress);
+ }
+
+ /**
+ * Returns the ip address.
+ *
+ * @return ipAddress
+ */
+ public IpAddress ipAddress() {
+ return ipAddress;
+ }
+
+ /**
+ * Convert the BGPId value to a ':' separated hexadecimal string.
+ *
+ * @return the BGPId value as a ':' separated hexadecimal string.
+ */
+ @Override
+ public String toString() {
+ return ipAddress.toString();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof BGPId)) {
+ return false;
+ }
+
+ BGPId otherBGPid = (BGPId) other;
+ return Objects.equals(ipAddress, otherBGPid.ipAddress);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(ipAddress);
+ }
+
+ /**
+ * Returns BGPId created from the given device URI.
+ *
+ * @param uri device URI
+ * @return object of BGPId
+ */
+ public static BGPId bgpId(URI uri) {
+ checkArgument(uri.getScheme().equals(SCHEME), "Unsupported URI scheme");
+ return new BGPId(IpAddress.valueOf(uri.getSchemeSpecificPart()));
+ }
+
+ /**
+ * Produces device URI from the given DPID.
+ *
+ * @param bgpId device bgpId
+ * @return device URI
+ */
+ public static URI uri(BGPId bgpId) {
+ return uri(bgpId.ipAddress());
+ }
+
+ /**
+ * Produces device URI from the given DPID long.
+ *
+ * @param ipAddress device ip address
+ * @return device URI
+ */
+ public static URI uri(IpAddress ipAddress) {
+ try {
+ return new URI(SCHEME, ipAddress.toString(), null);
+ } catch (URISyntaxException e) {
+ return null;
+ }
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/bgp/api/src/main/java/org/onosproject/bgp/controller/BGPPacketStats.java b/framework/src/onos/bgp/api/src/main/java/org/onosproject/bgp/controller/BGPPacketStats.java
new file mode 100755
index 00000000..95f83a2d
--- /dev/null
+++ b/framework/src/onos/bgp/api/src/main/java/org/onosproject/bgp/controller/BGPPacketStats.java
@@ -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.controller;
+
+/**
+ * A representation of a packet context which allows any provider to view a packet in event, but may block the response
+ * to the event if blocked has been called. This packet context can be used to react to the packet in event with a
+ * packet out.
+ */
+public interface BGPPacketStats {
+ /**
+ * Returns the count for no of packets sent out.
+ *
+ * @return int value of no of packets sent
+ */
+ int outPacketCount();
+
+ /**
+ * Returns the count for no of packets received.
+ *
+ * @return int value of no of packets sent
+ */
+ int inPacketCount();
+
+ /**
+ * Returns the count for no of wrong packets received.
+ *
+ * @return int value of no of wrong packets received
+ */
+ int wrongPacketCount();
+
+ /**
+ * Returns the time.
+ *
+ * @return the time
+ */
+ long getTime();
+} \ No newline at end of file
diff --git a/framework/src/onos/bgp/api/src/main/java/org/onosproject/bgp/controller/BGPPeerCfg.java b/framework/src/onos/bgp/api/src/main/java/org/onosproject/bgp/controller/BGPPeerCfg.java
new file mode 100755
index 00000000..87ec031f
--- /dev/null
+++ b/framework/src/onos/bgp/api/src/main/java/org/onosproject/bgp/controller/BGPPeerCfg.java
@@ -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.bgp.controller;
+
+/**
+ * BGP Peer configuration information.
+ */
+public interface BGPPeerCfg {
+
+ enum State {
+
+ /**
+ * Signifies that peer connection is idle.
+ */
+ IDLE,
+
+ /**
+ * Signifies that connection is initiated.
+ */
+ CONNECT,
+
+ /**
+ * Signifies that state is active and connection can be established.
+ */
+ ACTIVE,
+
+ /**
+ * Signifies that open is sent and anticipating reply.
+ */
+ OPENSENT,
+
+ /**
+ * Signifies that peer sent the open message as reply.
+ */
+ OPENCONFIRM,
+
+ /**
+ * Signifies that all the negotiation is successful and ready to exchange other messages.
+ */
+ ESTABLISHED,
+
+ /**
+ * Signifies that invalid state.
+ */
+ INVALID
+ }
+
+ /**
+ * Returns the connection State information of the peer.
+ *
+ * @return
+ * enum state is returned
+ */
+ State getState();
+
+ /**
+ * Set the connection state information of the peer.
+ *
+ * @param state
+ * enum state
+ */
+ void setState(State state);
+
+ /**
+ * Returns the connection is initiated from us or not.
+ *
+ * @return
+ * true if the connection is initiated by this peer, false if it has been received.
+ */
+ boolean getSelfInnitConnection();
+
+ /**
+ * Set the connection is initiated from us or not.
+ *
+ * @param selfInit
+ * true if the connection is initiated by this peer, false if it has been received.
+ */
+ void setSelfInnitConnection(boolean selfInit);
+
+ /**
+ * Returns the AS number to which this peer belongs.
+ *
+ * @return
+ * AS number
+ */
+ int getAsNumber();
+
+ /**
+ * Set the AS number to which this peer belongs.
+ *
+ * @param asNumber
+ * AS number
+ */
+ void setAsNumber(int asNumber);
+
+ /**
+ * Get the keep alive timer value configured.
+ *
+ * @return
+ * keep alive timer value in seconds
+ */
+ short getHoldtime();
+
+ /**
+ * Set the keep alive timer value.
+ *
+ * @param holdTime
+ * keep alive timer value in seconds
+ */
+ void setHoldtime(short holdTime);
+
+ /**
+ * Return the connection type eBGP or iBGP.
+ *
+ * @return
+ * true if iBGP, false if it is eBGP
+ */
+ boolean getIsIBgp();
+
+ /**
+ * Set the connection type eBGP or iBGP.
+ *
+ * @param isIBgp
+ * true if iBGP, false if it is eBGP
+ */
+ void setIsIBgp(boolean isIBgp);
+
+ /**
+ * Return the peer router IP address.
+ *
+ * @return
+ * IP address in string format
+ */
+ String getPeerRouterId();
+
+ /**
+ * Set the peer router IP address.
+ *
+ * @param peerId
+ * IP address in string format
+ */
+ void setPeerRouterId(String peerId);
+
+ /**
+ * Set the peer router IP address and AS number.
+ *
+ * @param peerId
+ * IP address in string format
+ * @param asNumber
+ * AS number
+ */
+ void setPeerRouterId(String peerId, int asNumber);
+}
diff --git a/framework/src/onos/bgp/api/src/main/java/org/onosproject/bgp/controller/package-info.java b/framework/src/onos/bgp/api/src/main/java/org/onosproject/bgp/controller/package-info.java
new file mode 100755
index 00000000..4dd775b8
--- /dev/null
+++ b/framework/src/onos/bgp/api/src/main/java/org/onosproject/bgp/controller/package-info.java
@@ -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.
+ */
+
+/**
+ * BGP controller API.
+ */
+package org.onosproject.bgp.controller;
diff --git a/framework/src/onos/bgp/bgpio/pom.xml b/framework/src/onos/bgp/bgpio/pom.xml
new file mode 100755
index 00000000..5d67f18c
--- /dev/null
+++ b/framework/src/onos/bgp/bgpio/pom.xml
@@ -0,0 +1,76 @@
+<?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-bgp</artifactId>
+ <version>1.4.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>onos-bgpio</artifactId>
+ <packaging>bundle</packaging>
+
+ <description>ONOS BGPio Protocol subsystem</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onlab-osgi</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.core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.karaf.shell</groupId>
+ <artifactId>org.apache.karaf.shell.console</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.scr.annotations</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/exceptions/BGPParseException.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/exceptions/BGPParseException.java
new file mode 100755
index 00000000..62427a44
--- /dev/null
+++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/exceptions/BGPParseException.java
@@ -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.bgpio.exceptions;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * Custom Exception for BGP IO.
+ */
+public class BGPParseException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+ private byte errorCode;
+ private byte errorSubCode;
+ private ChannelBuffer data;
+
+ /**
+ * Default constructor to create a new exception.
+ */
+ public BGPParseException() {
+ super();
+ }
+
+ /**
+ * Constructor to create exception from message and cause.
+ *
+ * @param message the detail of exception in string
+ * @param cause underlying cause of the error
+ */
+ public BGPParseException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Constructor to create exception from message.
+ *
+ * @param message the detail of exception in string
+ */
+ public BGPParseException(final String message) {
+ super(message);
+ }
+
+ /**
+ * Constructor to create exception from cause.
+ *
+ * @param cause underlying cause of the error
+ */
+ public BGPParseException(final Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * Constructor to create exception from error code and error subcode.
+ *
+ * @param errorCode error code of BGP message
+ * @param errorSubCode error subcode of BGP message
+ * @param data error data of BGP message
+ */
+ public BGPParseException(final byte errorCode, final byte errorSubCode, final ChannelBuffer data) {
+ super();
+ this.errorCode = errorCode;
+ this.errorSubCode = errorSubCode;
+ this.data = data;
+ }
+
+ /**
+ * Returns errorcode for this exception.
+ *
+ * @return errorcode for this exception
+ */
+ public byte getErrorCode() {
+ return this.errorCode;
+ }
+
+ /**
+ * Returns error Subcode for this exception.
+ *
+ * @return error Subcode for this exception
+ */
+ public byte getErrorSubCode() {
+ return this.errorSubCode;
+ }
+
+ /**
+ * Returns error data for this exception.
+ *
+ * @return error data for this exception
+ */
+ public ChannelBuffer getData() {
+ return this.data;
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/exceptions/package-info.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/exceptions/package-info.java
new file mode 100755
index 00000000..78b28072
--- /dev/null
+++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/exceptions/package-info.java
@@ -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.
+ */
+
+/**
+ * BGP custom exceptions.
+ */
+package org.onosproject.bgpio.exceptions;
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPKeepaliveMsg.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPKeepaliveMsg.java
new file mode 100644
index 00000000..c8aef36e
--- /dev/null
+++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPKeepaliveMsg.java
@@ -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;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.onosproject.bgpio.types.BGPHeader;
+
+/**
+ * Abstraction of an entity providing BGP Keepalive Message.
+ */
+public interface BGPKeepaliveMsg extends BGPMessage {
+
+ @Override
+ BGPVersion getVersion();
+
+ @Override
+ BGPType getType();
+
+ @Override
+ void writeTo(ChannelBuffer channelBuffer);
+
+ @Override
+ BGPHeader getHeader();
+
+ /**
+ * Builder interface with get and set functions to build Keepalive message.
+ */
+ interface Builder extends BGPMessage.Builder {
+
+ @Override
+ BGPKeepaliveMsg build();
+
+ @Override
+ BGPVersion getVersion();
+
+ @Override
+ BGPType getType();
+
+ @Override
+ Builder setHeader(BGPHeader bgpMsgHeader);
+
+ @Override
+ BGPHeader getHeader();
+ }
+}
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPMessage.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPMessage.java
new file mode 100644
index 00000000..a5d8154f
--- /dev/null
+++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPMessage.java
@@ -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.bgpio.protocol;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.onosproject.bgpio.exceptions.BGPParseException;
+import org.onosproject.bgpio.types.BGPHeader;
+
+/**
+ * Abstraction of an entity providing BGP Messages.
+ */
+public interface BGPMessage extends Writeable {
+ /**
+ * Returns BGP Header of BGP Message.
+ *
+ * @return BGP Header of BGP Message
+ */
+ BGPHeader getHeader();
+
+ /**
+ * Returns version of BGP Message.
+ *
+ * @return version of BGP Message
+ */
+ BGPVersion getVersion();
+
+ /**
+ * Returns BGP Type of BGP Message.
+ *
+ * @return BGP Type of BGP Message
+ */
+ BGPType getType();
+
+ @Override
+ void writeTo(ChannelBuffer cb) throws BGPParseException;
+
+ /**
+ * Builder interface with get and set functions to build BGP Message.
+ */
+ interface Builder {
+ /**
+ * Builds BGP Message.
+ *
+ * @return BGP Message
+ * @throws BGPParseException while building bgp message
+ */
+ BGPMessage build() throws BGPParseException;
+
+ /**
+ * Returns BGP Version of BGP Message.
+ *
+ * @return BGP Version of BGP Message
+ */
+ BGPVersion getVersion();
+
+ /**
+ * Returns BGP Type of BGP Message.
+ *
+ * @return BGP Type of BGP Message
+ */
+ BGPType getType();
+
+ /**
+ * Returns BGP Header of BGP Message.
+ *
+ * @return BGP Header of BGP Message
+ */
+ BGPHeader getHeader();
+
+ /**
+ * Sets BgpHeader and return its builder.
+ *
+ * @param bgpMsgHeader BGP Message Header
+ * @return builder by setting BGP message header
+ */
+ Builder setHeader(BGPHeader bgpMsgHeader);
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPMessageReader.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPMessageReader.java
new file mode 100755
index 00000000..18b8f58d
--- /dev/null
+++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPMessageReader.java
@@ -0,0 +1,36 @@
+/*
+ * 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;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.onosproject.bgpio.exceptions.BGPParseException;
+import org.onosproject.bgpio.types.BGPHeader;
+
+/**
+ * Abstraction of an entity providing BGP Message Reader.
+ */
+public interface BGPMessageReader<T> {
+
+ /**
+ * Reads the Objects in the BGP Message and Returns BGP Message.
+ *
+ * @param cb Channel Buffer
+ * @param bgpHeader BGP message header
+ * @return BGP Message
+ * @throws BGPParseException while parsing BGP message.
+ */
+ T readFrom(ChannelBuffer cb, BGPHeader bgpHeader) throws BGPParseException;
+} \ No newline at end of file
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPMessageWriter.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPMessageWriter.java
new file mode 100644
index 00000000..11f161c4
--- /dev/null
+++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPMessageWriter.java
@@ -0,0 +1,36 @@
+/*
+ * 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;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.onosproject.bgpio.exceptions.BGPParseException;
+
+/**
+ * Abstraction of an entity providing BGP Message Writer.
+ */
+public interface BGPMessageWriter<T> {
+
+ /**
+ * Writes the Objects of the BGP Message into Channel Buffer.
+ *
+ * @param cb Channel Buffer
+ * @param message BGP Message
+ * @throws BGPParseException
+ * While writing message
+ */
+ void write(ChannelBuffer cb, T message) throws BGPParseException;
+} \ No newline at end of file
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPOpenMsg.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPOpenMsg.java
new file mode 100644
index 00000000..c41e5eb6
--- /dev/null
+++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPOpenMsg.java
@@ -0,0 +1,151 @@
+/*
+ * 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;
+
+import java.util.LinkedList;
+
+import org.onosproject.bgpio.exceptions.BGPParseException;
+import org.onosproject.bgpio.types.BGPHeader;
+import org.onosproject.bgpio.types.BGPValueType;
+
+/**
+ * Abstraction of an entity providing BGP Open Message.
+ */
+public interface BGPOpenMsg extends BGPMessage {
+
+ @Override
+ BGPHeader getHeader();
+
+ @Override
+ BGPVersion getVersion();
+
+ @Override
+ BGPType getType();
+
+ /**
+ * Returns hold time of Open Message.
+ *
+ * @return hold time of Open Message
+ */
+ short getHoldTime();
+
+ /**
+ * Returns AS Number of Open Message.
+ *
+ * @return AS Number of Open Message
+ */
+ short getAsNumber();
+
+ /**
+ * Returns BGP Identifier of Open Message.
+ *
+ * @return BGP Identifier of Open Message
+ */
+ int getBgpId();
+
+ /**
+ * Returns capabilities of Open Message.
+ *
+ * @return capabilities of Open Message
+ */
+ LinkedList<BGPValueType> getCapabilityTlv();
+
+ /**
+ * Builder interface with get and set functions to build Open message.
+ */
+ interface Builder extends BGPMessage.Builder {
+
+ @Override
+ BGPOpenMsg build() throws BGPParseException;
+
+ @Override
+ BGPHeader getHeader();
+
+ @Override
+ BGPVersion getVersion();
+
+ @Override
+ BGPType getType();
+
+ /**
+ * Returns hold time of Open Message.
+ *
+ * @return hold time of Open Message
+ */
+ short getHoldTime();
+
+ /**
+ * Sets hold time in Open Message and return its builder.
+ *
+ * @param holdtime
+ * hold timer value in open message
+ * @return builder by setting hold time
+ */
+ Builder setHoldTime(short holdtime);
+
+ /**
+ * Returns as number of Open Message.
+ *
+ * @return as number of Open Message
+ */
+ short getAsNumber();
+
+ /**
+ * Sets AS number in Open Message and return its builder.
+ *
+ * @param asNumber
+ * as number in open message
+ * @return builder by setting asNumber
+ */
+ Builder setAsNumber(short asNumber);
+
+ /**
+ * Returns BGP Identifier of Open Message.
+ *
+ * @return BGP Identifier of Open Message
+ */
+ int getBgpId();
+
+ /**
+ * Sets BGP Identifier in Open Message and return its builder.
+ *
+ * @param bgpId
+ * BGP Identifier in open message
+ * @return builder by setting BGP Identifier
+ */
+ Builder setBgpId(int bgpId);
+
+ /**
+ * Returns capabilities of Open Message.
+ *
+ * @return capabilities of Open Message
+ */
+ LinkedList<BGPValueType> getCapabilityTlv();
+
+ /**
+ * Sets capabilities in Open Message and return its builder.
+ *
+ * @param capabilityTlv
+ * capabilities in open message
+ * @return builder by setting capabilities
+ */
+ Builder setCapabilityTlv(LinkedList<BGPValueType> capabilityTlv);
+
+ @Override
+ Builder setHeader(BGPHeader bgpMsgHeader);
+ }
+}
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPType.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPType.java
new file mode 100755
index 00000000..d3349156
--- /dev/null
+++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPType.java
@@ -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.bgpio.protocol;
+
+/**
+ * Enum to Provide the Different types of BGP messages.
+ */
+public enum BGPType {
+
+ NONE(0), OPEN(1), UPDATE(2), NOTIFICATION(3), KEEP_ALIVE(4);
+
+ int value;
+
+ /**
+ * Assign value with the value val as the types of BGP message.
+ *
+ * @param val type of BGP message
+ */
+ BGPType(int val) {
+ value = val;
+ }
+
+ /**
+ * Returns value as type of BGP message.
+ *
+ * @return value type of BGP message
+ */
+ public byte getType() {
+ return (byte) value;
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPVersion.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPVersion.java
new file mode 100755
index 00000000..97bc7dce
--- /dev/null
+++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPVersion.java
@@ -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.bgpio.protocol;
+
+/**
+ * Enum to provide BGP Message Version.
+ */
+public enum BGPVersion {
+
+ BGP_4(4);
+
+ public final int packetVersion;
+
+ /**
+ * Assign BGP PacketVersion with specified packetVersion.
+ *
+ * @param packetVersion version of BGP
+ */
+ BGPVersion(final int packetVersion) {
+ this.packetVersion = packetVersion;
+ }
+
+ /**
+ * Returns Packet version of BGP Message.
+ *
+ * @return packetVersion
+ */
+ public int getPacketVersion() {
+ return packetVersion;
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/IGPRouterID.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/IGPRouterID.java
new file mode 100644
index 00000000..377d12b7
--- /dev/null
+++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/IGPRouterID.java
@@ -0,0 +1,23 @@
+/*
+ * 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;
+
+/**
+ * Provides Abstraction of IGP RouterID TLV.
+ */
+public interface IGPRouterID {
+} \ No newline at end of file
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/Writeable.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/Writeable.java
new file mode 100755
index 00000000..72df7f32
--- /dev/null
+++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/Writeable.java
@@ -0,0 +1,35 @@
+/*
+ * 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;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.onosproject.bgpio.exceptions.BGPParseException;
+
+/**
+ * Abstraction of an entity providing functionality to write byte streams of
+ * Messages to channel buffer.
+ */
+public interface Writeable {
+
+ /**
+ * Writes byte streams of messages to channel buffer.
+ *
+ * @param cb channelBuffer
+ * @throws BGPParseException when error occurs while writing BGP message to channel buffer
+ */
+ void writeTo(ChannelBuffer cb) throws BGPParseException;
+} \ No newline at end of file
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/link_state/BGPPrefixLSIdentifier.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/link_state/BGPPrefixLSIdentifier.java
new file mode 100644
index 00000000..4fef47ff
--- /dev/null
+++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/link_state/BGPPrefixLSIdentifier.java
@@ -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.bgpio.protocol.link_state;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+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.types.IPReachabilityInformationTlv;
+import org.onosproject.bgpio.types.OSPFRouteTypeTlv;
+import org.onosproject.bgpio.types.attr.BgpAttrNodeMultiTopologyId;
+import org.onosproject.bgpio.util.UnSupportedAttribute;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.MoreObjects;
+
+/**
+ * Provides Implementation of Local node descriptors and prefix descriptors.
+ */
+public class BGPPrefixLSIdentifier {
+
+ protected static final Logger log = LoggerFactory.getLogger(BGPPrefixLSIdentifier.class);
+ public static final int TYPE_AND_LEN = 4;
+ private NodeDescriptors localNodeDescriptors;
+ private LinkedList<BGPValueType> prefixDescriptor;
+
+ /**
+ * Resets parameters.
+ */
+ public BGPPrefixLSIdentifier() {
+ this.localNodeDescriptors = null;
+ this.prefixDescriptor = null;
+ }
+
+ /**
+ * Constructor to initialize parameters.
+ *
+ * @param localNodeDescriptors Local node descriptors
+ * @param prefixDescriptor Prefix Descriptors
+ */
+ public BGPPrefixLSIdentifier(NodeDescriptors localNodeDescriptors, LinkedList<BGPValueType> prefixDescriptor) {
+ this.localNodeDescriptors = localNodeDescriptors;
+ this.prefixDescriptor = prefixDescriptor;
+ }
+
+ /**
+ * Reads the channel buffer and parses Prefix Identifier.
+ *
+ * @param cb ChannelBuffer
+ * @param protocolId protocol ID
+ * @return object of this class
+ * @throws BGPParseException while parsing Prefix Identifier
+ */
+ public static BGPPrefixLSIdentifier parsePrefixIdendifier(ChannelBuffer cb, byte protocolId)
+ throws BGPParseException {
+ //Parse Local Node descriptor
+ NodeDescriptors localNodeDescriptors = new NodeDescriptors();
+ localNodeDescriptors = parseLocalNodeDescriptors(cb, protocolId);
+
+ //Parse Prefix descriptor
+ LinkedList<BGPValueType> prefixDescriptor = new LinkedList<>();
+ prefixDescriptor = parsePrefixDescriptors(cb);
+ return new BGPPrefixLSIdentifier(localNodeDescriptors, prefixDescriptor);
+ }
+
+ /**
+ * Parse local node descriptors.
+ *
+ * @param cb ChannelBuffer
+ * @param protocolId protocol identifier
+ * @return LocalNodeDescriptors
+ * @throws BGPParseException while parsing local node descriptors
+ */
+ public static NodeDescriptors parseLocalNodeDescriptors(ChannelBuffer cb, byte protocolId)
+ throws BGPParseException {
+ ChannelBuffer tempBuf = cb;
+ short type = cb.readShort();
+ short length = cb.readShort();
+ if (cb.readableBytes() < length) {
+ //length + 4 implies data contains type, length and value
+ throw new BGPParseException(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.OPTIONAL_ATTRIBUTE_ERROR,
+ tempBuf.readBytes(cb.readableBytes() + TYPE_AND_LEN));
+ }
+ NodeDescriptors localNodeDescriptors = new NodeDescriptors();
+ ChannelBuffer tempCb = cb.readBytes(length);
+
+ if (type == NodeDescriptors.LOCAL_NODE_DES_TYPE) {
+ localNodeDescriptors = NodeDescriptors.read(tempCb, length, type, protocolId);
+ } else {
+ throw new BGPParseException(BGPErrorType.UPDATE_MESSAGE_ERROR,
+ BGPErrorType.MALFORMED_ATTRIBUTE_LIST, null);
+ }
+ return localNodeDescriptors;
+ }
+
+ /**
+ * Parse list of prefix descriptors.
+ *
+ * @param cb ChannelBuffer
+ * @return list of prefix descriptors
+ * @throws BGPParseException while parsing list of prefix descriptors
+ */
+ public static LinkedList<BGPValueType> parsePrefixDescriptors(ChannelBuffer cb) throws BGPParseException {
+ LinkedList<BGPValueType> prefixDescriptor = new LinkedList<>();
+ BGPValueType tlv = null;
+ boolean isIpReachInfo = false;
+ ChannelBuffer tempCb;
+ int count = 0;
+
+ while (cb.readableBytes() > 0) {
+ ChannelBuffer tempBuf = cb;
+ short type = cb.readShort();
+ short length = cb.readShort();
+ if (cb.readableBytes() < length) {
+ //length + 4 implies data contains type, length and value
+ throw new BGPParseException(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.OPTIONAL_ATTRIBUTE_ERROR,
+ tempBuf.readBytes(cb.readableBytes() + TYPE_AND_LEN));
+ }
+ tempCb = cb.readBytes(length);
+ switch (type) {
+ case OSPFRouteTypeTlv.TYPE:
+ tlv = OSPFRouteTypeTlv.read(tempCb);
+ break;
+ case IPReachabilityInformationTlv.TYPE:
+ tlv = IPReachabilityInformationTlv.read(tempCb, length);
+ isIpReachInfo = true;
+ break;
+ case BgpAttrNodeMultiTopologyId.ATTRNODE_MULTITOPOLOGY:
+ tlv = BgpAttrNodeMultiTopologyId.read(tempCb);
+ count = count + 1;
+ if (count > 1) {
+ //length + 4 implies data contains type, length and value
+ throw new BGPParseException(BGPErrorType.UPDATE_MESSAGE_ERROR,
+ BGPErrorType.OPTIONAL_ATTRIBUTE_ERROR, tempBuf.readBytes(length + TYPE_AND_LEN));
+ }
+ break;
+ default:
+ UnSupportedAttribute.skipBytes(tempCb, length);
+ }
+ prefixDescriptor.add(tlv);
+ }
+
+ if (!isIpReachInfo) {
+ throw new BGPParseException(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.OPTIONAL_ATTRIBUTE_ERROR,
+ null);
+ }
+ return prefixDescriptor;
+ }
+
+ /**
+ * Returns local node descriptors.
+ *
+ * @return local node descriptors
+ */
+ public NodeDescriptors getLocalNodeDescriptors() {
+ return this.localNodeDescriptors;
+ }
+
+ /**
+ * Returns Prefix descriptors.
+ *
+ * @return Prefix descriptors
+ */
+ public LinkedList<BGPValueType> getPrefixdescriptor() {
+ return this.prefixDescriptor;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(prefixDescriptor.hashCode(), localNodeDescriptors);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj instanceof BGPPrefixLSIdentifier) {
+ int countObjSubTlv = 0;
+ int countOtherSubTlv = 0;
+ boolean isCommonSubTlv = true;
+ BGPPrefixLSIdentifier other = (BGPPrefixLSIdentifier) obj;
+
+ Iterator<BGPValueType> objListIterator = other.prefixDescriptor.iterator();
+ countOtherSubTlv = other.prefixDescriptor.size();
+ countObjSubTlv = prefixDescriptor.size();
+ if (countObjSubTlv != countOtherSubTlv) {
+ return false;
+ } else {
+ while (objListIterator.hasNext() && isCommonSubTlv) {
+ BGPValueType subTlv = objListIterator.next();
+ isCommonSubTlv = Objects.equals(prefixDescriptor.contains(subTlv),
+ other.prefixDescriptor.contains(subTlv));
+ }
+ return isCommonSubTlv && Objects.equals(this.localNodeDescriptors, other.localNodeDescriptors);
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("localNodeDescriptors", localNodeDescriptors)
+ .add("prefixDescriptor", prefixDescriptor)
+ .toString();
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/link_state/NodeDescriptors.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/link_state/NodeDescriptors.java
new file mode 100644
index 00000000..a03b2bae
--- /dev/null
+++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/link_state/NodeDescriptors.java
@@ -0,0 +1,225 @@
+/*
+ * 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.link_state;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Objects;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.onosproject.bgpio.exceptions.BGPParseException;
+import org.onosproject.bgpio.types.AreaIDTlv;
+import org.onosproject.bgpio.types.AutonomousSystemTlv;
+import org.onosproject.bgpio.types.BGPErrorType;
+import org.onosproject.bgpio.types.BGPLSIdentifierTlv;
+import org.onosproject.bgpio.types.BGPValueType;
+import org.onosproject.bgpio.types.IsIsNonPseudonode;
+import org.onosproject.bgpio.types.IsIsPseudonode;
+import org.onosproject.bgpio.types.OSPFNonPseudonode;
+import org.onosproject.bgpio.types.OSPFPseudonode;
+import org.onosproject.bgpio.util.UnSupportedAttribute;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.MoreObjects;
+
+/**
+ * Provides Local and Remote NodeDescriptors which contains Node Descriptor Sub-TLVs.
+ */
+public class NodeDescriptors {
+
+ /*
+ *Reference :draft-ietf-idr-ls-distribution-11
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Length |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ // Node Descriptor Sub-TLVs (variable) //
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ Figure : Local or Remote Node Descriptors TLV format
+ */
+
+ protected static final Logger log = LoggerFactory.getLogger(NodeDescriptors.class);
+
+ public static final short LOCAL_NODE_DES_TYPE = 256;
+ public static final short REMOTE_NODE_DES_TYPE = 257;
+ public static final short IGP_ROUTERID_TYPE = 515;
+ public static final short IS_IS_LEVEL_1_PROTOCOL_ID = 1;
+ public static final short IS_IS_LEVEL_2_PROTOCOL_ID = 2;
+ public static final short OSPF_V2_PROTOCOL_ID = 3;
+ public static final short OSPF_V3_PROTOCOL_ID = 6;
+ public static final int TYPE_AND_LEN = 4;
+ public static final int ISISNONPSEUDONODE_LEN = 6;
+ public static final int ISISPSEUDONODE_LEN = 7;
+ public static final int OSPFNONPSEUDONODE_LEN = 4;
+ public static final int OSPFPSEUDONODE_LEN = 8;
+ private LinkedList<BGPValueType> subTlvs;
+ private short deslength;
+ private short desType;
+
+ /**
+ * Resets parameters.
+ */
+ public NodeDescriptors() {
+ this.subTlvs = null;
+ this.deslength = 0;
+ this.desType = 0;
+ }
+
+ /**
+ * Constructor to initialize parameters.
+ *
+ * @param subTlvs list of subTlvs
+ * @param deslength Descriptors length
+ * @param desType local node descriptor or remote node descriptor type
+ */
+ public NodeDescriptors(LinkedList<BGPValueType> subTlvs, short deslength, short desType) {
+ this.subTlvs = subTlvs;
+ this.deslength = deslength;
+ this.desType = desType;
+ }
+
+ /**
+ * Returns list of subTlvs.
+ *
+ * @return subTlvs list of subTlvs
+ */
+ public LinkedList<BGPValueType> getSubTlvs() {
+ return subTlvs;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(subTlvs.hashCode());
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj instanceof NodeDescriptors) {
+ int countObjSubTlv = 0;
+ int countOtherSubTlv = 0;
+ boolean isCommonSubTlv = true;
+ NodeDescriptors other = (NodeDescriptors) obj;
+ Iterator<BGPValueType> objListIterator = other.subTlvs.iterator();
+ countOtherSubTlv = other.subTlvs.size();
+ countObjSubTlv = subTlvs.size();
+ if (countObjSubTlv != countOtherSubTlv) {
+ return false;
+ } else {
+ while (objListIterator.hasNext() && isCommonSubTlv) {
+ BGPValueType subTlv = objListIterator.next();
+ isCommonSubTlv = Objects.equals(subTlvs.contains(subTlv), other.subTlvs.contains(subTlv));
+ }
+ return isCommonSubTlv;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Reads node descriptors Sub-TLVs.
+ *
+ * @param cb ChannelBuffer
+ * @param desLength node descriptor length
+ * @param desType local node descriptor or remote node descriptor type
+ * @param protocolId protocol ID
+ * @return object of NodeDescriptors
+ * @throws BGPParseException while parsing node descriptors
+ */
+ public static NodeDescriptors read(ChannelBuffer cb, short desLength, short desType, byte protocolId)
+ throws BGPParseException {
+ LinkedList<BGPValueType> subTlvs;
+ subTlvs = new LinkedList<>();
+ BGPValueType tlv = null;
+
+ while (cb.readableBytes() > 0) {
+ ChannelBuffer tempBuf = cb;
+ short type = cb.readShort();
+ short length = cb.readShort();
+ if (cb.readableBytes() < length) {
+ throw new BGPParseException(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.OPTIONAL_ATTRIBUTE_ERROR,
+ tempBuf.readBytes(cb.readableBytes() + TYPE_AND_LEN));
+ }
+ ChannelBuffer tempCb = cb.readBytes(length);
+ switch (type) {
+ case AutonomousSystemTlv.TYPE:
+ tlv = AutonomousSystemTlv.read(tempCb);
+ break;
+ case BGPLSIdentifierTlv.TYPE:
+ tlv = BGPLSIdentifierTlv.read(tempCb);
+ break;
+ case AreaIDTlv.TYPE:
+ tlv = AreaIDTlv.read(tempCb);
+ break;
+ case IGP_ROUTERID_TYPE:
+ if (protocolId == IS_IS_LEVEL_1_PROTOCOL_ID || protocolId == IS_IS_LEVEL_2_PROTOCOL_ID) {
+ if (length == ISISNONPSEUDONODE_LEN) {
+ tlv = IsIsNonPseudonode.read(tempCb);
+ } else if (length == ISISPSEUDONODE_LEN) {
+ tlv = IsIsPseudonode.read(tempCb);
+ }
+ } else if (protocolId == OSPF_V2_PROTOCOL_ID || protocolId == OSPF_V3_PROTOCOL_ID) {
+ if (length == OSPFNONPSEUDONODE_LEN) {
+ tlv = OSPFNonPseudonode.read(tempCb);
+ } else if (length == OSPFPSEUDONODE_LEN) {
+ tlv = OSPFPseudonode.read(tempCb);
+ }
+ }
+ break;
+ default:
+ UnSupportedAttribute.skipBytes(tempCb, length);
+ }
+ subTlvs.add(tlv);
+ }
+ return new NodeDescriptors(subTlvs, desLength, desType);
+ }
+
+ /**
+ * Returns node descriptors length.
+ *
+ * @return node descriptors length
+ */
+ public short getLength() {
+ return this.deslength;
+ }
+
+ /**
+ * Returns node descriptors type.
+ *
+ * @return node descriptors type
+ */
+ public short getType() {
+ return this.desType;
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("desType", desType)
+ .add("deslength", deslength)
+ .add("subTlvs", subTlvs)
+ .toString();
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/link_state/package-info.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/link_state/package-info.java
new file mode 100755
index 00000000..d2a2ccf3
--- /dev/null
+++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/link_state/package-info.java
@@ -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.
+ */
+
+/**
+ * BGP Protocol specific link state details.
+ */
+package org.onosproject.bgpio.protocol.link_state; \ No newline at end of file
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/package-info.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/package-info.java
new file mode 100755
index 00000000..723b31b1
--- /dev/null
+++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/package-info.java
@@ -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.
+ */
+
+/**
+ * BGP Protocol specific components.
+ */
+package org.onosproject.bgpio.protocol;
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPKeepaliveMsgVer4.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPKeepaliveMsgVer4.java
new file mode 100644
index 00000000..a6668b3a
--- /dev/null
+++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPKeepaliveMsgVer4.java
@@ -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.protocol.ver4;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.onosproject.bgpio.exceptions.BGPParseException;
+import org.onosproject.bgpio.protocol.BGPKeepaliveMsg;
+import org.onosproject.bgpio.protocol.BGPMessageReader;
+import org.onosproject.bgpio.protocol.BGPMessageWriter;
+import org.onosproject.bgpio.types.BGPHeader;
+import org.onosproject.bgpio.protocol.BGPType;
+import org.onosproject.bgpio.protocol.BGPVersion;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.MoreObjects;
+
+/**
+ * Provides BGP keep alive message.
+ */
+class BGPKeepaliveMsgVer4 implements BGPKeepaliveMsg {
+
+ /*
+ <Keepalive Message>::= <Common Header>
+ A KEEPALIVE message consists of only the message header and has a
+ length of 19 octets.
+
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ + +
+ | |
+ + +
+ | Marker |
+ + +
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Length | Type |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ REFERENCE : RFC 4271
+ */
+
+ protected static final Logger log = LoggerFactory
+ .getLogger(BGPKeepaliveMsgVer4.class);
+
+ private BGPHeader bgpMsgHeader;
+ public static final byte PACKET_VERSION = 4;
+ public static final int PACKET_MINIMUM_LENGTH = 19;
+ public static final int MARKER_LENGTH = 16;
+ public static final BGPType MSG_TYPE = BGPType.KEEP_ALIVE;
+ public static byte[] marker = new byte[] {(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};
+
+ public static final BGPKeepaliveMsgVer4.Reader READER = new Reader();
+
+ /**
+ * Reader class for reading BGP keepalive message from channel buffer.
+ */
+ static class Reader implements BGPMessageReader<BGPKeepaliveMsg> {
+
+ @Override
+ public BGPKeepaliveMsg readFrom(ChannelBuffer cb, BGPHeader bgpHeader)
+ throws BGPParseException {
+
+ /* bgpHeader is not required in case of keepalive message and
+ Header is already read and no other fields except header in keepalive message.*/
+ return new BGPKeepaliveMsgVer4();
+ }
+ }
+
+ /**
+ * Default constructor.
+ */
+ BGPKeepaliveMsgVer4() {
+ }
+
+ /**
+ * Builder class for BGP keepalive message.
+ */
+ static class Builder implements BGPKeepaliveMsg.Builder {
+ BGPHeader bgpMsgHeader;
+
+ @Override
+ public BGPVersion getVersion() {
+ return BGPVersion.BGP_4;
+ }
+
+ @Override
+ public BGPType getType() {
+ return BGPType.KEEP_ALIVE;
+ }
+
+ @Override
+ public BGPHeader getHeader() {
+ return this.bgpMsgHeader;
+ }
+
+ @Override
+ public Builder setHeader(BGPHeader bgpMsgHeader) {
+ this.bgpMsgHeader = bgpMsgHeader;
+ return this;
+ }
+
+ @Override
+ public BGPKeepaliveMsg build() {
+ return new BGPKeepaliveMsgVer4();
+ }
+ }
+
+ @Override
+ public void writeTo(ChannelBuffer cb) {
+ WRITER.write(cb, this);
+ }
+
+ static final Writer WRITER = new Writer();
+
+ /**
+ * Writer class for writing the BGP keepalive message to channel buffer.
+ */
+ static class Writer implements BGPMessageWriter<BGPKeepaliveMsgVer4> {
+
+ @Override
+ public void write(ChannelBuffer cb, BGPKeepaliveMsgVer4 message) {
+
+ // write marker
+ cb.writeBytes(marker, 0, MARKER_LENGTH);
+
+ // write length of header
+ cb.writeShort(PACKET_MINIMUM_LENGTH);
+
+ // write the type of message
+ cb.writeByte(MSG_TYPE.getType());
+ }
+ }
+
+ @Override
+ public BGPVersion getVersion() {
+ return BGPVersion.BGP_4;
+ }
+
+ @Override
+ public BGPType getType() {
+ return MSG_TYPE;
+ }
+
+ @Override
+ public BGPHeader getHeader() {
+ return this.bgpMsgHeader;
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass()).toString();
+ }
+}
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPOpenMsgVer4.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPOpenMsgVer4.java
new file mode 100644
index 00000000..1348ecfd
--- /dev/null
+++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPOpenMsgVer4.java
@@ -0,0 +1,468 @@
+/*
+ * 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.ListIterator;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.onosproject.bgpio.exceptions.BGPParseException;
+import org.onosproject.bgpio.protocol.BGPMessageReader;
+import org.onosproject.bgpio.protocol.BGPMessageWriter;
+import org.onosproject.bgpio.protocol.BGPOpenMsg;
+import org.onosproject.bgpio.protocol.BGPType;
+import org.onosproject.bgpio.protocol.BGPVersion;
+import org.onosproject.bgpio.types.BGPErrorType;
+import org.onosproject.bgpio.types.BGPHeader;
+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;
+
+/**
+ * Provides BGP open message.
+ */
+public class BGPOpenMsgVer4 implements BGPOpenMsg {
+
+ /*
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+
+ | Version |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | My Autonomous System |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Hold Time |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | BGP Identifier |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Opt Parm Len |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Optional Parameters (variable) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ OPEN Message Format
+ REFERENCE : RFC 4271
+ */
+
+ protected static final Logger log = LoggerFactory.getLogger(BGPOpenMsgVer4.class);
+
+ public static final byte PACKET_VERSION = 4;
+ public static final int OPEN_MSG_MINIMUM_LENGTH = 10;
+ public static final int MSG_HEADER_LENGTH = 19;
+ public static final int MARKER_LENGTH = 16;
+ public static final int DEFAULT_HOLD_TIME = 120;
+ public static final int OPT_PARA_TYPE_CAPABILITY = 2;
+ public static final BGPType MSG_TYPE = BGPType.OPEN;
+ public static final byte[] MARKER = new byte[]{(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};
+ public static final BGPHeader DEFAULT_OPEN_HEADER = new BGPHeader(MARKER,
+ (short) OPEN_MSG_MINIMUM_LENGTH, (byte) 0X01);
+ private BGPHeader bgpMsgHeader;
+ private byte version;
+ private short asNumber;
+ private short holdTime;
+ private int bgpId;
+ private LinkedList<BGPValueType> capabilityTlv;
+
+ public static final BGPOpenMsgVer4.Reader READER = new Reader();
+
+ /**
+ * reset variables.
+ */
+ public BGPOpenMsgVer4() {
+ this.bgpMsgHeader = null;
+ this.version = 0;
+ this.holdTime = 0;
+ this.asNumber = 0;
+ this.bgpId = 0;
+ this.capabilityTlv = null;
+ }
+
+ /**
+ * Constructor to initialize all variables of BGP Open message.
+ *
+ * @param bgpMsgHeader
+ * BGP Header in open message
+ * @param version
+ * BGP version in open message
+ * @param holdTime
+ * hold time in open message
+ * @param asNumber
+ * AS number in open message
+ * @param bgpId
+ * BGP identifier in open message
+ * @param capabilityTlv
+ * capabilities in open message
+ */
+ public BGPOpenMsgVer4(BGPHeader bgpMsgHeader, byte version, short asNumber, short holdTime,
+ int bgpId, LinkedList<BGPValueType> capabilityTlv) {
+ this.bgpMsgHeader = bgpMsgHeader;
+ this.version = version;
+ this.asNumber = asNumber;
+ this.holdTime = holdTime;
+ this.bgpId = bgpId;
+ this.capabilityTlv = capabilityTlv;
+ }
+
+ @Override
+ public BGPHeader getHeader() {
+ return this.bgpMsgHeader;
+ }
+
+ @Override
+ public BGPVersion getVersion() {
+ return BGPVersion.BGP_4;
+ }
+
+ @Override
+ public BGPType getType() {
+ return MSG_TYPE;
+ }
+
+ @Override
+ public short getHoldTime() {
+ return this.holdTime;
+ }
+
+ @Override
+ public short getAsNumber() {
+ return this.asNumber;
+ }
+
+ @Override
+ public int getBgpId() {
+ return this.bgpId;
+ }
+
+ @Override
+ public LinkedList<BGPValueType> getCapabilityTlv() {
+ return this.capabilityTlv;
+ }
+
+ /**
+ * Reader class for reading BGP open message from channel buffer.
+ */
+ public static class Reader implements BGPMessageReader<BGPOpenMsg> {
+
+ @Override
+ public BGPOpenMsg readFrom(ChannelBuffer cb, BGPHeader bgpHeader) throws BGPParseException {
+
+ byte version;
+ short holdTime;
+ short asNumber;
+ int bgpId;
+ byte optParaLen = 0;
+ byte optParaType;
+ byte capParaLen = 0;
+ LinkedList<BGPValueType> capabilityTlv = new LinkedList<>();
+
+ if (cb.readableBytes() < OPEN_MSG_MINIMUM_LENGTH) {
+ log.error("[readFrom] Invalid length: Packet size is less than the minimum length ");
+ Validation.validateLen(BGPErrorType.OPEN_MESSAGE_ERROR, BGPErrorType.BAD_MESSAGE_LENGTH,
+ cb.readableBytes());
+ }
+
+ // Read version
+ version = cb.readByte();
+ if (version != PACKET_VERSION) {
+ log.error("[readFrom] Invalid version: " + version);
+ throw new BGPParseException(BGPErrorType.OPEN_MESSAGE_ERROR,
+ BGPErrorType.UNSUPPORTED_VERSION_NUMBER, null);
+ }
+
+ // Read AS number
+ asNumber = cb.readShort();
+
+ // Read Hold timer
+ holdTime = cb.readShort();
+
+ // Read BGP Identifier
+ bgpId = cb.readInt();
+
+ // Read optional parameter length
+ optParaLen = cb.readByte();
+
+ // Read Capabilities if optional parameter length is greater than 0
+ if (optParaLen != 0) {
+ // Read optional parameter type
+ optParaType = cb.readByte();
+
+ // Read optional parameter length
+ capParaLen = cb.readByte();
+
+ if (cb.readableBytes() < capParaLen) {
+ throw new BGPParseException(BGPErrorType.OPEN_MESSAGE_ERROR, (byte) 0, null);
+ }
+
+ ChannelBuffer capaCb = cb.readBytes(capParaLen);
+
+ // Parse capabilities only if optional parameter type is 2
+ if ((optParaType == OPT_PARA_TYPE_CAPABILITY) && (capParaLen != 0)) {
+ capabilityTlv = parseCapabilityTlv(capaCb);
+ } else {
+ throw new BGPParseException(BGPErrorType.OPEN_MESSAGE_ERROR,
+ BGPErrorType.UNSUPPORTED_OPTIONAL_PARAMETER, null);
+ }
+ }
+ return new BGPOpenMsgVer4(bgpHeader, version, asNumber, holdTime, bgpId, capabilityTlv);
+ }
+ }
+
+ /**
+ * Parsing capabilities.
+ *
+ * @param cb of type channel buffer
+ * @return capabilityTlv of open message
+ * @throws BGPParseException while parsing capabilities
+ */
+ protected static LinkedList<BGPValueType> parseCapabilityTlv(ChannelBuffer cb) throws BGPParseException {
+
+ LinkedList<BGPValueType> capabilityTlv = new LinkedList<>();
+
+ // TODO: Capability parsing
+ return capabilityTlv;
+ }
+
+ /**
+ * Builder class for BGP open message.
+ */
+ static class Builder implements BGPOpenMsg.Builder {
+
+ private boolean isHeaderSet = false;
+ private BGPHeader bgpMsgHeader;
+ private boolean isHoldTimeSet = false;
+ private short holdTime;
+ private boolean isAsNumSet = false;
+ private short asNumber;
+ private boolean isBgpIdSet = false;
+ private int bgpId;
+
+ LinkedList<BGPValueType> capabilityTlv = new LinkedList<>();
+
+ @Override
+ public BGPOpenMsg build() throws BGPParseException {
+ BGPHeader bgpMsgHeader = this.isHeaderSet ? this.bgpMsgHeader : DEFAULT_OPEN_HEADER;
+ short holdTime = this.isHoldTimeSet ? this.holdTime : DEFAULT_HOLD_TIME;
+
+ if (!this.isAsNumSet) {
+ throw new BGPParseException("BGP AS number is not set (mandatory)");
+ }
+
+ if (!this.isBgpIdSet) {
+ throw new BGPParseException("BGPID is not set (mandatory)");
+ }
+
+ // TODO: capabilities build
+
+ return new BGPOpenMsgVer4(bgpMsgHeader, PACKET_VERSION, this.asNumber, holdTime, this.bgpId,
+ this.capabilityTlv);
+ }
+
+ @Override
+ public BGPHeader getHeader() {
+ return this.bgpMsgHeader;
+ }
+
+ @Override
+ public Builder setHeader(BGPHeader bgpMsgHeader) {
+ this.bgpMsgHeader = bgpMsgHeader;
+ return this;
+ }
+
+ @Override
+ public BGPVersion getVersion() {
+ return BGPVersion.BGP_4;
+ }
+
+ @Override
+ public BGPType getType() {
+ return MSG_TYPE;
+ }
+
+ @Override
+ public short getHoldTime() {
+ return this.holdTime;
+ }
+
+ @Override
+ public short getAsNumber() {
+ return this.asNumber;
+ }
+
+ @Override
+ public int getBgpId() {
+ return this.bgpId;
+ }
+
+ @Override
+ public LinkedList<BGPValueType> getCapabilityTlv() {
+ return this.capabilityTlv;
+ }
+
+ @Override
+ public Builder setHoldTime(short holdTime) {
+ this.holdTime = holdTime;
+ this.isHoldTimeSet = true;
+ return this;
+ }
+
+ @Override
+ public Builder setAsNumber(short asNumber) {
+ this.asNumber = asNumber;
+ this.isAsNumSet = true;
+ return this;
+ }
+
+ @Override
+ public Builder setBgpId(int bgpId) {
+ this.bgpId = bgpId;
+ this.isBgpIdSet = true;
+ return this;
+ }
+
+ @Override
+ public Builder setCapabilityTlv(LinkedList<BGPValueType> capabilityTlv) {
+ this.capabilityTlv = capabilityTlv;
+ return this;
+ }
+ }
+
+ @Override
+ public void writeTo(ChannelBuffer cb) {
+ try {
+ WRITER.write(cb, this);
+ } catch (BGPParseException e) {
+ log.debug("[writeTo] Error: " + e.toString());
+ }
+ }
+
+ public static final Writer WRITER = new Writer();
+
+ /**
+ * Writer class for writing BGP open message to channel buffer.
+ */
+ public static class Writer implements BGPMessageWriter<BGPOpenMsgVer4> {
+
+ @Override
+ public void write(ChannelBuffer cb, BGPOpenMsgVer4 message) throws BGPParseException {
+
+ int optParaLen = 0;
+
+ int startIndex = cb.writerIndex();
+
+ // write common header and get msg length index
+ int msgLenIndex = message.bgpMsgHeader.write(cb);
+
+ if (msgLenIndex <= 0) {
+ throw new BGPParseException("Unable to write message header.");
+ }
+
+ // write version in 1-octet
+ cb.writeByte(message.version);
+
+ // TODO : Write AS number based on capabilities
+ cb.writeShort(message.asNumber);
+
+ // write HoldTime in next 2-octet
+ cb.writeShort(message.holdTime);
+
+ // write BGP Identifier in next 4-octet
+ cb.writeInt(message.bgpId);
+
+ // store the index of Optional parameter length
+ int optParaLenIndex = cb.writerIndex();
+
+ // set optional parameter length as 0
+ cb.writeByte(0);
+
+ // Pack capability TLV
+ optParaLen = message.packCapabilityTlv(cb, message);
+
+ if (optParaLen != 0) {
+ // Update optional parameter length
+ cb.setByte(optParaLenIndex, (byte) (optParaLen + 2)); //+2 for optional parameter type.
+ }
+
+ // write OPEN Object Length
+ int length = cb.writerIndex() - startIndex;
+ cb.setShort(msgLenIndex, (short) length);
+ message.bgpMsgHeader.setLength((short) length);
+ }
+ }
+
+ /**
+ * returns length of capability tlvs.
+ *
+ * @param cb of type channel buffer
+ * @param message of type BGPOpenMsgVer4
+ * @return capParaLen of open message
+ */
+ protected int packCapabilityTlv(ChannelBuffer cb, BGPOpenMsgVer4 message) {
+ int startIndex = cb.writerIndex();
+ int capParaLen = 0;
+ int capParaLenIndex = 0;
+
+ LinkedList<BGPValueType> capabilityTlv = message.capabilityTlv;
+ ListIterator<BGPValueType> listIterator = capabilityTlv.listIterator();
+
+ if (listIterator.hasNext()) {
+ // Set optional parameter type as 2
+ cb.writeByte(OPT_PARA_TYPE_CAPABILITY);
+
+ // Store the index of capability parameter length and update length at the end
+ capParaLenIndex = cb.writerIndex();
+
+ // Set capability parameter length as 0
+ cb.writeByte(0);
+
+ // Update the startIndex to know the length of capability tlv
+ startIndex = cb.writerIndex();
+ }
+
+ while (listIterator.hasNext()) {
+ BGPValueType tlv = listIterator.next();
+ if (tlv == null) {
+ log.debug("Warning: tlv is null from CapabilityTlv list");
+ continue;
+ }
+ tlv.write(cb);
+ }
+
+ capParaLen = cb.writerIndex() - startIndex;
+
+ if (capParaLen != 0) {
+ // Update capability parameter length
+ cb.setByte(capParaLenIndex, (byte) capParaLen);
+ }
+ return capParaLen;
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("bgpMsgHeader", bgpMsgHeader)
+ .add("version", version)
+ .add("holdTime", holdTime)
+ .add("asNumber", asNumber)
+ .add("bgpId", bgpId)
+ .add("capabilityTlv", capabilityTlv)
+ .toString();
+ }
+}
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/package-info.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/package-info.java
new file mode 100755
index 00000000..fb8c67c0
--- /dev/null
+++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/package-info.java
@@ -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.
+ */
+
+/**
+ * BGP Protocol specific details of version 4.
+ */
+package org.onosproject.bgpio.protocol.ver4; \ No newline at end of file
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/AreaIDTlv.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/AreaIDTlv.java
new file mode 100644
index 00000000..52bae466
--- /dev/null
+++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/AreaIDTlv.java
@@ -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.bgpio.types;
+
+import java.util.Objects;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.MoreObjects;
+
+/**
+ * Provides AreaID Tlv which contains opaque value (32 Bit Area-ID).
+ */
+public class AreaIDTlv implements BGPValueType {
+
+ /* Reference :draft-ietf-idr-ls-distribution-11
+ * 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type= 514 | Length=4 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | opaque value (32 Bit Area-ID) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+ protected static final Logger log = LoggerFactory.getLogger(AreaIDTlv.class);
+
+ public static final short TYPE = 514;
+ public static final short LENGTH = 4;
+
+ private final int areaID;
+
+ /**
+ * Constructor to initialize areaID.
+ *
+ * @param areaID of BGP AreaID Tlv
+ */
+ public AreaIDTlv(int areaID) {
+ this.areaID = areaID;
+ }
+
+ /**
+ * Returns object of this class with specified areaID.
+ *
+ * @param areaID opaque value of area id
+ * @return object of AreaIDTlv
+ */
+ public static AreaIDTlv of(final int areaID) {
+ return new AreaIDTlv(areaID);
+ }
+
+ /**
+ * Returns opaque value of area id.
+ *
+ * @return opaque value of area id
+ */
+ public int getAreaID() {
+ return areaID;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(areaID);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj instanceof AreaIDTlv) {
+ AreaIDTlv other = (AreaIDTlv) obj;
+ return Objects.equals(areaID, other.areaID);
+ }
+ return false;
+ }
+
+ @Override
+ public int write(ChannelBuffer c) {
+ int iLenStartIndex = c.writerIndex();
+ c.writeShort(TYPE);
+ c.writeShort(LENGTH);
+ c.writeInt(areaID);
+ return c.writerIndex() - iLenStartIndex;
+ }
+
+ /**
+ * Reads the channel buffer and returns object of AreaIDTlv.
+ *
+ * @param cb ChannelBuffer
+ * @return object of AreaIDTlv
+ */
+ public static AreaIDTlv read(ChannelBuffer cb) {
+ return AreaIDTlv.of(cb.readInt());
+ }
+
+ @Override
+ public short getType() {
+ return TYPE;
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("Type", TYPE)
+ .add("Length", LENGTH)
+ .add("Value", areaID)
+ .toString();
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/AutonomousSystemTlv.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/AutonomousSystemTlv.java
new file mode 100644
index 00000000..5d8a9193
--- /dev/null
+++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/AutonomousSystemTlv.java
@@ -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.bgpio.types;
+
+import java.util.Objects;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.MoreObjects;
+
+/**
+ * Provides Autonomous System Tlv which contains opaque value (32 Bit AS Number).
+ */
+public class AutonomousSystemTlv implements BGPValueType {
+
+ /* Reference :draft-ietf-idr-ls-distribution-11
+ * 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type= 512 | Length=4 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | opaque value (32 Bit AS Number) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+ protected static final Logger log = LoggerFactory.getLogger(AutonomousSystemTlv.class);
+
+ public static final short TYPE = 512;
+ public static final short LENGTH = 4;
+
+ private final int asNum;
+
+ /**
+ * Constructor to initialize asNum.
+ *
+ * @param asNum 32 Bit AS Number
+ */
+ public AutonomousSystemTlv(int asNum) {
+ this.asNum = asNum;
+ }
+
+ /**
+ * Returns object of this class with specified asNum.
+ *
+ * @param asNum 32 Bit AS Number
+ * @return object of AutonomousSystemTlv
+ */
+ public static AutonomousSystemTlv of(final int asNum) {
+ return new AutonomousSystemTlv(asNum);
+ }
+
+ /**
+ * Returns opaque value of AS Number.
+ *
+ * @return opaque value of AS Number
+ */
+ public int getAsNum() {
+ return asNum;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(asNum);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj instanceof AutonomousSystemTlv) {
+ AutonomousSystemTlv other = (AutonomousSystemTlv) obj;
+ return Objects.equals(asNum, other.asNum);
+ }
+ return false;
+ }
+
+ @Override
+ public int write(ChannelBuffer c) {
+ int iLenStartIndex = c.writerIndex();
+ c.writeShort(TYPE);
+ c.writeShort(LENGTH);
+ c.writeInt(asNum);
+ return c.writerIndex() - iLenStartIndex;
+ }
+
+ /**
+ * Reads the channel buffer and returns object of AutonomousSystemTlv.
+ *
+ * @param c ChannelBuffer
+ * @return object of AutonomousSystemTlv
+ */
+ public static AutonomousSystemTlv read(ChannelBuffer c) {
+ return AutonomousSystemTlv.of(c.readInt());
+ }
+
+ @Override
+ public short getType() {
+ return TYPE;
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("Type", TYPE)
+ .add("Length", LENGTH)
+ .add("asNum", asNum)
+ .toString();
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/BGPErrorType.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/BGPErrorType.java
new file mode 100644
index 00000000..f643ae00
--- /dev/null
+++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/BGPErrorType.java
@@ -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.bgpio.types;
+
+/**
+ * BgpErrorType class defines all errorCodes and error Subcodes required for Notification message.
+ */
+public final class BGPErrorType {
+ private BGPErrorType() {
+ }
+
+ //Error Codes
+ public static final byte MESSAGE_HEADER_ERROR = 1;
+ public static final byte OPEN_MESSAGE_ERROR = 2;
+ public static final byte UPDATE_MESSAGE_ERROR = 3;
+ public static final byte HOLD_TIMER_EXPIRED = 4;
+ public static final byte FINITE_STATE_MACHINE_ERROR = 4;
+ public static final byte CEASE = 5;
+
+ //Message Header Error subcodes
+ public static final byte CONNECTION_NOT_SYNCHRONIZED = 1;
+ public static final byte BAD_MESSAGE_LENGTH = 2;
+ public static final byte BAD_MESSAGE_TYPE = 3;
+
+ //OPEN Message Error subcodes
+ public static final byte UNSUPPORTED_VERSION_NUMBER = 1;
+ public static final byte BAD_PEER_AS = 2;
+ public static final byte BAD_BGP_IDENTIFIER = 3;
+ public static final byte UNSUPPORTED_OPTIONAL_PARAMETER = 4;
+ public static final byte UNACCEPTABLE_HOLD_TIME = 5;
+
+ //UPDATE Message Error subcodes
+ public static final byte MALFORMED_ATTRIBUTE_LIST = 1;
+ public static final byte UNRECOGNIZED_WELLKNOWN_ATTRIBUTE = 2;
+ public static final byte MISSING_WELLKNOWN_ATTRIBUTE = 3;
+ public static final byte ATTRIBUTE_FLAGS_ERROR = 4;
+ public static final byte ATTRIBUTE_LENGTH_ERROR = 5;
+ public static final byte INVALID_ORIGIN_ATTRIBUTE = 6;
+ public static final byte INVALID_NEXTHOP_ATTRIBUTE = 8;
+ public static final byte OPTIONAL_ATTRIBUTE_ERROR = 9;
+ public static final byte INVALID_NETWORK_FIELD = 10;
+ public static final byte MALFORMED_ASPATH = 11;
+} \ No newline at end of file
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/BGPHeader.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/BGPHeader.java
new file mode 100755
index 00000000..6acda0d6
--- /dev/null
+++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/BGPHeader.java
@@ -0,0 +1,161 @@
+/*
+ * 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 org.jboss.netty.buffer.ChannelBuffer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Provides BGP Message Header which is common for all the Messages.
+ */
+
+public class BGPHeader {
+
+ /* 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ + +
+ | |
+ + +
+ | Marker |
+ + +
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Length | Type |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+ protected static final Logger log = LoggerFactory.getLogger(BGPHeader.class);
+
+ public static final int MARKER_LENGTH = 16;
+ public static final short DEFAULT_HEADER_LENGTH = 19;
+
+ private byte[] marker;
+ private byte type;
+ private short length;
+
+ /**
+ * Reset fields.
+ */
+ public BGPHeader() {
+ this.marker = null;
+ this.length = 0;
+ this.type = 0;
+ }
+
+ /**
+ * Constructors to initialize parameters.
+ *
+ * @param marker field in BGP header
+ * @param length message length
+ * @param type message type
+ */
+ public BGPHeader(byte[] marker, short length, byte type) {
+ this.marker = marker;
+ this.length = length;
+ this.type = type;
+ }
+
+ /**
+ * Sets marker field.
+ *
+ * @param value marker field
+ */
+ public void setMarker(byte[] value) {
+ this.marker = value;
+ }
+
+ /**
+ * Sets message type.
+ *
+ * @param value message type
+ */
+ public void setType(byte value) {
+ this.type = value;
+ }
+
+ /**
+ * Sets message length.
+ *
+ * @param value message length
+ */
+ public void setLength(short value) {
+ this.length = value;
+ }
+
+ /**
+ * Returns message length.
+ *
+ * @return message length
+ */
+ public short getLength() {
+ return this.length;
+ }
+
+ /**
+ * Returns message marker.
+ *
+ * @return message marker
+ */
+ public byte[] getMarker() {
+ return this.marker;
+ }
+
+ /**
+ * Returns message type.
+ *
+ * @return message type
+ */
+ public byte getType() {
+ return this.type;
+ }
+
+ /**
+ * Writes Byte stream of BGP header to channel buffer.
+ *
+ * @param cb ChannelBuffer
+ * @return length index of message header
+ */
+ public int write(ChannelBuffer cb) {
+
+ cb.writeBytes(getMarker(), 0, MARKER_LENGTH);
+
+ int headerLenIndex = cb.writerIndex();
+ cb.writeShort((short) 0);
+ cb.writeByte(type);
+
+ return headerLenIndex;
+ }
+
+ /**
+ * Read from channel buffer and Returns BGP header.
+ *
+ * @param cb ChannelBuffer
+ * @return object of BGPHeader
+ */
+ public static BGPHeader read(ChannelBuffer cb) {
+
+ byte[] marker = new byte[MARKER_LENGTH];
+ byte type;
+ short length;
+ cb.readBytes(marker, 0, MARKER_LENGTH);
+ length = cb.readShort();
+ type = cb.readByte();
+ return new BGPHeader(marker, length, type);
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/BGPLSIdentifierTlv.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/BGPLSIdentifierTlv.java
new file mode 100644
index 00000000..f723d2ca
--- /dev/null
+++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/BGPLSIdentifierTlv.java
@@ -0,0 +1,127 @@
+/*
+ * 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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.MoreObjects;
+
+/**
+ * Provides BGPLSIdentifier Tlv which contains opaque value (32 Bit BGPLS-Identifier).
+ */
+public class BGPLSIdentifierTlv implements BGPValueType {
+
+ /* Reference :draft-ietf-idr-ls-distribution-11
+ * 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type= 513 | Length=4 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | opaque value (32 Bit BGPLS-Identifier) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+ protected static final Logger log = LoggerFactory.getLogger(BGPLSIdentifierTlv.class);
+
+ public static final short TYPE = 513;
+ public static final short LENGTH = 4;
+
+ private final int bgpLSIdentifier;
+
+ /**
+ * Constructor to initialize bgpLSIdentifier.
+ *
+ * @param bgpLSIdentifier BgpLS-Identifier
+ */
+ public BGPLSIdentifierTlv(int bgpLSIdentifier) {
+ this.bgpLSIdentifier = bgpLSIdentifier;
+ }
+
+ /**
+ * Returns object of this class with specified rbgpLSIdentifier.
+ *
+ * @param bgpLSIdentifier BgpLS-Identifier
+ * @return BgpLS-Identifier
+ */
+ public static BGPLSIdentifierTlv of(final int bgpLSIdentifier) {
+ return new BGPLSIdentifierTlv(bgpLSIdentifier);
+ }
+
+ /**
+ * Returns opaque value of BgpLS-Identifier.
+ *
+ * @return opaque value of BgpLS-Identifier
+ */
+ public int getBgpLSIdentifier() {
+ return bgpLSIdentifier;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(bgpLSIdentifier);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj instanceof BGPLSIdentifierTlv) {
+ BGPLSIdentifierTlv other = (BGPLSIdentifierTlv) obj;
+ return Objects.equals(bgpLSIdentifier, other.bgpLSIdentifier);
+ }
+ return false;
+ }
+
+ @Override
+ public int write(ChannelBuffer c) {
+ int iLenStartIndex = c.writerIndex();
+ c.writeShort(TYPE);
+ c.writeShort(LENGTH);
+ c.writeInt(bgpLSIdentifier);
+ return c.writerIndex() - iLenStartIndex;
+ }
+
+ /**
+ * Reads the channel buffer and parses BGPLS Identifier TLV.
+ *
+ * @param cb ChannelBuffer
+ * @return object of BGPLSIdentifierTlv
+ */
+ public static BGPLSIdentifierTlv read(ChannelBuffer cb) {
+ return BGPLSIdentifierTlv.of(cb.readInt());
+ }
+
+ @Override
+ public short getType() {
+ return TYPE;
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("Type", TYPE)
+ .add("Length", LENGTH)
+ .add("Value", bgpLSIdentifier)
+ .toString();
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/BGPValueType.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/BGPValueType.java
new file mode 100755
index 00000000..54a8b43c
--- /dev/null
+++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/BGPValueType.java
@@ -0,0 +1,39 @@
+/*
+ * 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 org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * Abstraction which Provides the BGP of TLV format.
+ */
+public interface BGPValueType {
+ /**
+ * Returns the Type of BGP Message.
+ *
+ * @return short value of type
+ */
+ short getType();
+
+ /**
+ * Writes the byte Stream of BGP Message to channel buffer.
+ *
+ * @param cb channel buffer
+ * @return length written to channel buffer
+ */
+ int write(ChannelBuffer cb);
+} \ No newline at end of file
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/IPReachabilityInformationTlv.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/IPReachabilityInformationTlv.java
new file mode 100644
index 00000000..85fb748b
--- /dev/null
+++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/IPReachabilityInformationTlv.java
@@ -0,0 +1,156 @@
+/*
+ * 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.onlab.packet.IpPrefix;
+import org.onosproject.bgpio.util.Validation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.MoreObjects;
+
+/**
+ * Provides IP Reachability InformationTlv Tlv which contains IP Prefix.
+ */
+public class IPReachabilityInformationTlv implements BGPValueType {
+
+ /*
+ * Reference :draft-ietf-idr-ls-distribution-11
+
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Length |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Prefix Length | IP Prefix (variable) //
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ Figure 14: IP Reachability Information TLV Format
+ */
+
+ protected static final Logger log = LoggerFactory.getLogger(IPReachabilityInformationTlv.class);
+
+ public static final short TYPE = 265;
+ public static final int ONE_BYTE_LEN = 8;
+ private byte prefixLen;
+ private byte[] ipPrefix;
+ public short length;
+
+ /**
+ * Constructor to initialize parameters.
+ *
+ * @param prefixLen length of IP Prefix
+ * @param ipPrefix IP Prefix
+ * @param length length of value field
+ */
+ public IPReachabilityInformationTlv(byte prefixLen, byte[] ipPrefix, short length) {
+ this.ipPrefix = ipPrefix;
+ this.prefixLen = prefixLen;
+ this.length = length;
+ }
+
+ /**
+ * Returns IP Prefix.
+ *
+ * @return IP Prefix
+ */
+ public IpPrefix getPrefixValue() {
+ IpPrefix prefix = Validation.bytesToPrefix(ipPrefix, prefixLen);
+ return prefix;
+ }
+
+ /**
+ * Returns IP Prefix length.
+ *
+ * @return IP Prefix length
+ */
+ public byte getPrefixLen() {
+ return this.prefixLen;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(ipPrefix, prefixLen);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj instanceof IPReachabilityInformationTlv) {
+ IPReachabilityInformationTlv other = (IPReachabilityInformationTlv) obj;
+ return Objects.equals(prefixLen, other.prefixLen) && Objects.equals(ipPrefix, other.ipPrefix);
+ }
+ return false;
+ }
+
+ @Override
+ public int write(ChannelBuffer cb) {
+ int iLenStartIndex = cb.writerIndex();
+ cb.writeShort(TYPE);
+ cb.writeShort(length);
+ cb.writeByte(prefixLen);
+ cb.writeBytes(ipPrefix);
+ return cb.writerIndex() - iLenStartIndex;
+ }
+
+ /**
+ * Reads the channel buffer and returns object of IPReachabilityInformationTlv.
+ *
+ * @param cb ChannelBuffer
+ * @param length of value field
+ * @return object of IPReachabilityInformationTlv
+ */
+ public static IPReachabilityInformationTlv read(ChannelBuffer cb, short length) {
+ byte preficLen = cb.readByte();
+ byte[] prefix;
+ if (preficLen == 0) {
+ prefix = new byte[] {0};
+ } else {
+ int len = preficLen / ONE_BYTE_LEN;
+ int reminder = preficLen % ONE_BYTE_LEN;
+ if (reminder > 0) {
+ len = len + 1;
+ }
+ prefix = new byte[len];
+ cb.readBytes(prefix, 0, len);
+ }
+ return IPReachabilityInformationTlv.of(preficLen, prefix, length);
+ }
+
+ public static IPReachabilityInformationTlv of(final byte preficLen, final byte[] prefix, final short length) {
+ return new IPReachabilityInformationTlv(preficLen, prefix, length);
+ }
+ @Override
+ public short getType() {
+ return TYPE;
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("Type", TYPE)
+ .add("Length", length)
+ .add("Prefixlength", getPrefixLen())
+ .add("Prefixvalue", getPrefixValue())
+ .toString();
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/IsIsNonPseudonode.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/IsIsNonPseudonode.java
new file mode 100644
index 00000000..d5f3e7f3
--- /dev/null
+++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/IsIsNonPseudonode.java
@@ -0,0 +1,117 @@
+/*
+ * 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.protocol.IGPRouterID;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.MoreObjects;
+
+/**
+ * Provides Implementation of IsIsNonPseudonode Tlv.
+ */
+public class IsIsNonPseudonode implements IGPRouterID, BGPValueType {
+ protected static final Logger log = LoggerFactory.getLogger(IsIsNonPseudonode.class);
+
+ public static final short TYPE = 515;
+ public static final short LENGTH = 6;
+
+ private final byte[] isoNodeID;
+
+ /**
+ * Constructor to initialize isoNodeID.
+ *
+ * @param isoNodeID ISO system-ID
+ */
+ public IsIsNonPseudonode(byte[] isoNodeID) {
+ this.isoNodeID = isoNodeID;
+ }
+
+ /**
+ * Returns object of this class with specified isoNodeID.
+ *
+ * @param isoNodeID ISO system-ID
+ * @return object of IsIsNonPseudonode
+ */
+ public static IsIsNonPseudonode of(final byte[] isoNodeID) {
+ return new IsIsNonPseudonode(isoNodeID);
+ }
+
+ /**
+ * Returns ISO NodeID.
+ *
+ * @return ISO NodeID
+ */
+ public byte[] getISONodeID() {
+ return isoNodeID;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(isoNodeID);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof IsIsNonPseudonode) {
+ IsIsNonPseudonode other = (IsIsNonPseudonode) obj;
+ return Objects.equals(isoNodeID, other.isoNodeID);
+ }
+ return false;
+ }
+
+ @Override
+ public int write(ChannelBuffer c) {
+ int iLenStartIndex = c.writerIndex();
+ c.writeShort(TYPE);
+ c.writeShort(LENGTH);
+ c.writeBytes(isoNodeID);
+ return c.writerIndex() - iLenStartIndex;
+ }
+
+ /**
+ * Reads the channel buffer and returns object of IsIsNonPseudonode.
+ *
+ * @param cb ChannelBuffer
+ * @return object of IsIsNonPseudonode
+ */
+ public static IsIsNonPseudonode read(ChannelBuffer cb) {
+ byte[] isoNodeID = new byte[LENGTH];
+ cb.readBytes(isoNodeID, 0, LENGTH);
+ return IsIsNonPseudonode.of(isoNodeID);
+ }
+
+ @Override
+ public short getType() {
+ return TYPE;
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("Type", TYPE)
+ .add("Length", LENGTH)
+ .add("ISONodeID", isoNodeID)
+ .toString();
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/IsIsPseudonode.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/IsIsPseudonode.java
new file mode 100644
index 00000000..5c742d0f
--- /dev/null
+++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/IsIsPseudonode.java
@@ -0,0 +1,133 @@
+/*
+ * 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.protocol.IGPRouterID;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.MoreObjects;
+
+/**
+ * Provides implementation of IsIsPseudonode Tlv.
+ */
+public class IsIsPseudonode implements IGPRouterID, BGPValueType {
+ protected static final Logger log = LoggerFactory.getLogger(IsIsPseudonode.class);
+
+ public static final short TYPE = 515;
+ public static final short LENGTH = 7;
+
+ private final byte[] isoNodeID;
+ private byte psnIdentifier;
+
+ /**
+ * Constructor to initialize isoNodeID.
+ *
+ * @param isoNodeID ISO system-ID
+ * @param psnIdentifier PSN identifier
+ */
+ public IsIsPseudonode(byte[] isoNodeID, byte psnIdentifier) {
+ this.isoNodeID = isoNodeID;
+ this.psnIdentifier = psnIdentifier;
+ }
+
+ /**
+ * Returns object of this class with specified values.
+ *
+ * @param isoNodeID ISO system-ID
+ * @param psnIdentifier PSN identifier
+ * @return object of IsIsPseudonode
+ */
+ public static IsIsPseudonode of(final byte[] isoNodeID, final byte psnIdentifier) {
+ return new IsIsPseudonode(isoNodeID, psnIdentifier);
+ }
+
+ /**
+ * Returns ISO NodeID.
+ *
+ * @return ISO NodeID
+ */
+ public byte[] getISONodeID() {
+ return isoNodeID;
+ }
+
+ /**
+ * Returns PSN Identifier.
+ *
+ * @return PSN Identifier
+ */
+ public byte getPSNIdentifier() {
+ return this.psnIdentifier;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(isoNodeID, psnIdentifier);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof IsIsPseudonode) {
+ IsIsPseudonode other = (IsIsPseudonode) obj;
+ return Objects.equals(isoNodeID, other.isoNodeID) && Objects.equals(psnIdentifier, other.psnIdentifier);
+ }
+ return false;
+ }
+
+ @Override
+ public int write(ChannelBuffer c) {
+ int iLenStartIndex = c.writerIndex();
+ c.writeShort(TYPE);
+ c.writeShort(LENGTH);
+ c.writeBytes(isoNodeID);
+ c.writeByte(psnIdentifier);
+ return c.writerIndex() - iLenStartIndex;
+ }
+
+ /**
+ * Reads the channel buffer and returns object of IsIsPseudonode.
+ *
+ * @param cb ChannelBuffer
+ * @return object of IsIsPseudonode
+ */
+ public static IsIsPseudonode read(ChannelBuffer cb) {
+ byte[] isoNodeID = new byte[LENGTH - 1];
+ cb.readBytes(isoNodeID, 0, LENGTH - 1);
+ byte psnIdentifier = cb.readByte();
+ return IsIsPseudonode.of(isoNodeID, psnIdentifier);
+ }
+
+ @Override
+ public short getType() {
+ return TYPE;
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("Type", TYPE)
+ .add("Length", LENGTH)
+ .add("isoNodeID", isoNodeID)
+ .add("psnIdentifier", psnIdentifier)
+ .toString();
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/OSPFNonPseudonode.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/OSPFNonPseudonode.java
new file mode 100644
index 00000000..6d8282b7
--- /dev/null
+++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/OSPFNonPseudonode.java
@@ -0,0 +1,118 @@
+/*
+ * 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.protocol.IGPRouterID;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.MoreObjects;
+
+/**
+ * Provides implementation of OSPFNonPseudonode Tlv.
+ */
+public class OSPFNonPseudonode implements IGPRouterID, BGPValueType {
+
+ protected static final Logger log = LoggerFactory.getLogger(OSPFNonPseudonode.class);
+
+ public static final short TYPE = 515;
+ public static final short LENGTH = 4;
+
+ private final int routerID;
+
+ /**
+ * Constructor to initialize routerID.
+ *
+ * @param routerID routerID
+ */
+ public OSPFNonPseudonode(int routerID) {
+ this.routerID = routerID;
+ }
+
+ /**
+ * Returns object of this class with specified routerID.
+ *
+ * @param routerID routerID
+ * @return object of OSPFNonPseudonode
+ */
+ public static OSPFNonPseudonode of(final int routerID) {
+ return new OSPFNonPseudonode(routerID);
+ }
+
+ /**
+ * Returns RouterID.
+ *
+ * @return RouterID
+ */
+ public int getrouterID() {
+ return this.routerID;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(routerID);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj instanceof OSPFNonPseudonode) {
+ OSPFNonPseudonode other = (OSPFNonPseudonode) obj;
+ return Objects.equals(routerID, other.routerID);
+ }
+ return false;
+ }
+
+ @Override
+ public int write(ChannelBuffer c) {
+ int iLenStartIndex = c.writerIndex();
+ c.writeShort(TYPE);
+ c.writeShort(LENGTH);
+ c.writeInt(routerID);
+ return c.writerIndex() - iLenStartIndex;
+ }
+
+ /**
+ * Reads the channel buffer and returns object of OSPFNonPseudonode.
+ *
+ * @param cb ChannelBuffer
+ * @return object of OSPFNonPseudonode
+ */
+ public static OSPFNonPseudonode read(ChannelBuffer cb) {
+ return OSPFNonPseudonode.of(cb.readInt());
+ }
+
+ @Override
+ public short getType() {
+ return TYPE;
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("Type", TYPE)
+ .add("Length", LENGTH)
+ .add("RouterID", routerID)
+ .toString();
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/OSPFPseudonode.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/OSPFPseudonode.java
new file mode 100644
index 00000000..82a39bd1
--- /dev/null
+++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/OSPFPseudonode.java
@@ -0,0 +1,125 @@
+/*
+ * 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.onlab.packet.Ip4Address;
+import org.onosproject.bgpio.protocol.IGPRouterID;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.MoreObjects;
+
+/**
+ * Provides implementation of OSPFPseudonode Tlv.
+ */
+public class OSPFPseudonode implements IGPRouterID, BGPValueType {
+
+ protected static final Logger log = LoggerFactory.getLogger(OSPFPseudonode.class);
+
+ public static final short TYPE = 515;
+ public static final short LENGTH = 8;
+
+ private final int routerID;
+ private final Ip4Address drInterface;
+
+ /**
+ * Constructor to initialize parameters.
+ *
+ * @param routerID routerID
+ * @param drInterface IPv4 address of the DR's interface
+ */
+ public OSPFPseudonode(int routerID, Ip4Address drInterface) {
+ this.routerID = routerID;
+ this.drInterface = drInterface;
+ }
+
+ /**
+ * Returns object of this class with specified values.
+ *
+ * @param routerID routerID
+ * @param drInterface IPv4 address of the DR's interface
+ * @return object of OSPFPseudonode
+ */
+ public static OSPFPseudonode of(final int routerID, final Ip4Address drInterface) {
+ return new OSPFPseudonode(routerID, drInterface);
+ }
+
+ /**
+ * Returns RouterID.
+ *
+ * @return RouterID
+ */
+ public int getrouterID() {
+ return this.routerID;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(routerID, drInterface);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof OSPFPseudonode) {
+ OSPFPseudonode other = (OSPFPseudonode) obj;
+ return Objects.equals(routerID, other.routerID) && Objects.equals(drInterface, other.drInterface);
+ }
+ return false;
+ }
+
+ @Override
+ public int write(ChannelBuffer c) {
+ int iLenStartIndex = c.writerIndex();
+ c.writeShort(TYPE);
+ c.writeShort(LENGTH);
+ c.writeInt(routerID);
+ c.writeInt(drInterface.toInt());
+ return c.writerIndex() - iLenStartIndex;
+ }
+
+ /**
+ * Reads the channel buffer and returns object of OSPFPseudonode.
+ *
+ * @param cb ChannelBuffer
+ * @return object of OSPFPseudonode
+ */
+ public static OSPFPseudonode read(ChannelBuffer cb) {
+ int routerID = cb.readInt();
+ Ip4Address drInterface = Ip4Address.valueOf(cb.readInt());
+ return OSPFPseudonode.of(routerID, drInterface);
+ }
+
+ @Override
+ public short getType() {
+ return TYPE;
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("Type", TYPE)
+ .add("Length", LENGTH)
+ .add("RouterID", routerID)
+ .add("DRInterface", drInterface)
+ .toString();
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/OSPFRouteTypeTlv.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/OSPFRouteTypeTlv.java
new file mode 100644
index 00000000..20fffbfa
--- /dev/null
+++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/OSPFRouteTypeTlv.java
@@ -0,0 +1,163 @@
+/*
+ * 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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.MoreObjects;
+
+/**
+ * Provides OSPF Route Type Tlv which contains route type.
+ */
+public class OSPFRouteTypeTlv implements BGPValueType {
+
+ /* Reference :draft-ietf-idr-ls-distribution-11
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Length |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Route Type |
+ +-+-+-+-+-+-+-+-+
+
+ Figure : OSPF Route Type TLV Format
+ */
+
+ protected static final Logger log = LoggerFactory.getLogger(OSPFRouteTypeTlv.class);
+
+ public static final short TYPE = 264;
+ public static final short LENGTH = 1;
+ public static final int INTRA_AREA_TYPE = 1;
+ public static final short INTER_AREA_TYPE = 2;
+ public static final short EXTERNAL_TYPE_1 = 3;
+ public static final short EXTERNAL_TYPE_2 = 4;
+ public static final short NSSA_TYPE_1 = 5;
+ public static final short NSSA_TYPE_2 = 6;
+ private final byte routeType;
+
+ /**
+ * Enum for Route Type.
+ */
+ public enum ROUTETYPE {
+ Intra_Area(1), Inter_Area(2), External_1(3), External_2(4), NSSA_1(5), NSSA_2(6);
+ int value;
+ ROUTETYPE(int val) {
+ value = val;
+ }
+ public byte getType() {
+ return (byte) value;
+ }
+ }
+
+ /**
+ * Constructor to initialize routeType.
+ *
+ * @param routeType Route type
+ */
+ public OSPFRouteTypeTlv(byte routeType) {
+ this.routeType = routeType;
+ }
+
+ /**
+ * Returns object of this class with specified routeType.
+ *
+ * @param routeType Route type
+ * @return object of OSPFRouteTypeTlv
+ */
+ public static OSPFRouteTypeTlv of(final byte routeType) {
+ return new OSPFRouteTypeTlv(routeType);
+ }
+
+ /**
+ * Returns RouteType.
+ *
+ * @return RouteType
+ * @throws BGPParseException if routeType is not matched
+ */
+ public ROUTETYPE getValue() throws BGPParseException {
+ switch (routeType) {
+ case INTRA_AREA_TYPE:
+ return ROUTETYPE.Intra_Area;
+ case INTER_AREA_TYPE:
+ return ROUTETYPE.Inter_Area;
+ case EXTERNAL_TYPE_1:
+ return ROUTETYPE.External_1;
+ case EXTERNAL_TYPE_2:
+ return ROUTETYPE.External_2;
+ case NSSA_TYPE_1:
+ return ROUTETYPE.NSSA_1;
+ case NSSA_TYPE_2:
+ return ROUTETYPE.NSSA_2;
+ default:
+ throw new BGPParseException(BGPErrorType.UPDATE_MESSAGE_ERROR, (byte) 0, null);
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(routeType);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof OSPFRouteTypeTlv) {
+ OSPFRouteTypeTlv other = (OSPFRouteTypeTlv) obj;
+ return Objects.equals(routeType, other.routeType);
+ }
+ return false;
+ }
+
+ @Override
+ public int write(ChannelBuffer c) {
+ int iLenStartIndex = c.writerIndex();
+ c.writeShort(TYPE);
+ c.writeShort(LENGTH);
+ c.writeByte(routeType);
+ return c.writerIndex() - iLenStartIndex;
+ }
+
+ /**
+ * Reads from ChannelBuffer and parses OSPFRouteTypeTlv.
+ *
+ * @param cb channelBuffer
+ * @return object of OSPFRouteTypeTlv
+ */
+ public static OSPFRouteTypeTlv read(ChannelBuffer cb) {
+ return OSPFRouteTypeTlv.of(cb.readByte());
+ }
+
+ @Override
+ public short getType() {
+ return TYPE;
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("Type", TYPE)
+ .add("Length", LENGTH)
+ .add("Value", routeType)
+ .toString();
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpAttrNodeFlagBitTlv.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpAttrNodeFlagBitTlv.java
new file mode 100755
index 00000000..ba02f6d1
--- /dev/null
+++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpAttrNodeFlagBitTlv.java
@@ -0,0 +1,177 @@
+/*
+ * 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 attribute node flag.
+ */
+public class BgpAttrNodeFlagBitTlv implements BGPValueType {
+
+ protected static final Logger log = LoggerFactory
+ .getLogger(BgpAttrNodeFlagBitTlv.class);
+
+ public static final int ATTRNODE_FLAGBIT = 1024;
+
+ /* Node flag bit TLV */
+ private boolean bOverloadBit;
+ private boolean bAttachedBit;
+ private boolean bExternalBit;
+ private 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;
+
+ /**
+ * Constructor to initialize parameters.
+ *
+ * @param bOverloadBit Overload bit
+ * @param bAttachedBit Attached bit
+ * @param bExternalBit External bit
+ * @param bABRBit ABR Bit
+ */
+ BgpAttrNodeFlagBitTlv(boolean bOverloadBit, boolean bAttachedBit,
+ boolean bExternalBit, boolean bABRBit) {
+ this.bOverloadBit = bOverloadBit;
+ this.bAttachedBit = bAttachedBit;
+ this.bExternalBit = bExternalBit;
+ this.bABRBit = bABRBit;
+ }
+
+ /**
+ * Reads the Node Flag Bits.
+ *
+ * @param cb ChannelBuffer
+ * @return attribute node flag bit tlv
+ * @throws BGPParseException while parsing BgpAttrNodeFlagBitTlv
+ */
+ public static BgpAttrNodeFlagBitTlv read(ChannelBuffer cb)
+ throws BGPParseException {
+ boolean bOverloadBit = false;
+ boolean bAttachedBit = false;
+ boolean bExternalBit = false;
+ boolean bABRBit = false;
+
+ short lsAttrLength = cb.readShort();
+
+ if (lsAttrLength != 1) {
+ Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR,
+ BGPErrorType.ATTRIBUTE_LENGTH_ERROR,
+ lsAttrLength);
+ }
+
+ 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);
+
+ return new BgpAttrNodeFlagBitTlv(bOverloadBit, bAttachedBit,
+ bExternalBit, bABRBit);
+ }
+
+ /**
+ * Returns Overload Bit.
+ *
+ * @return Overload Bit
+ */
+ boolean getOverLoadBit() {
+ return bOverloadBit;
+ }
+
+ /**
+ * Returns Attached Bit.
+ *
+ * @return Attached Bit
+ */
+ boolean getAttachedBit() {
+ return bAttachedBit;
+ }
+
+ /**
+ * Returns External Bit.
+ *
+ * @return External Bit
+ */
+ boolean getExternalBit() {
+ return bExternalBit;
+ }
+
+ /**
+ * Returns ABR Bit.
+ *
+ * @return ABR Bit
+ */
+ boolean getABRBit() {
+ return bABRBit;
+ }
+
+ @Override
+ public short getType() {
+ return ATTRNODE_FLAGBIT;
+ }
+
+ @Override
+ public int write(ChannelBuffer cb) {
+ // TODO will be implementing it later
+ return 0;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(bOverloadBit, bAttachedBit, bExternalBit, bABRBit);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj instanceof BgpAttrNodeFlagBitTlv) {
+ BgpAttrNodeFlagBitTlv other = (BgpAttrNodeFlagBitTlv) obj;
+ return Objects.equals(bOverloadBit, other.bOverloadBit)
+ && Objects.equals(bAttachedBit, other.bAttachedBit)
+ && Objects.equals(bExternalBit, other.bExternalBit)
+ && Objects.equals(bABRBit, other.bABRBit);
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("bOverloadBit", bOverloadBit)
+ .add("bAttachedBit", bAttachedBit)
+ .add("bExternalBit", bExternalBit).add("bABRBit", bABRBit)
+ .toString();
+ }
+}
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpAttrNodeMultiTopologyId.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpAttrNodeMultiTopologyId.java
new file mode 100644
index 00000000..194d6dac
--- /dev/null
+++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpAttrNodeMultiTopologyId.java
@@ -0,0 +1,127 @@
+/*
+ * 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;
+
+/**
+ * BGP Multi-Topology ID of the LS attribute.
+ */
+public class BgpAttrNodeMultiTopologyId implements BGPValueType {
+
+ private static final Logger log = LoggerFactory
+ .getLogger(BgpAttrNodeMultiTopologyId.class);
+
+ public static final int ATTRNODE_MULTITOPOLOGY = 263;
+
+ /* Opaque Node Attribute */
+ private short[] multiTopologyId;
+
+ /**
+ * Constructor to initialize the Node attribute multi-topology ID.
+ *
+ * @param multiTopologyId multi-topology ID
+ */
+ BgpAttrNodeMultiTopologyId(short[] multiTopologyId) {
+ this.multiTopologyId = multiTopologyId;
+ }
+
+ /**
+ * Reads the Multi-topology ID of Node attribute.
+ *
+ * @param cb ChannelBuffer
+ * @return Constructor of BgpAttrNodeMultiTopologyId
+ * @throws BGPParseException while parsing BgpAttrNodeMultiTopologyId
+ */
+ public static BgpAttrNodeMultiTopologyId read(ChannelBuffer cb)
+ throws BGPParseException {
+
+ log.debug("BgpAttrNodeMultiTopologyId");
+ short lsAttrLength = cb.readShort();
+ int len = lsAttrLength / 2; // Length is 2*n and n is the number of MT-IDs
+
+ if (cb.readableBytes() < lsAttrLength) {
+ Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR,
+ BGPErrorType.ATTRIBUTE_LENGTH_ERROR,
+ cb.readableBytes());
+ }
+
+ short[] multiTopologyId;
+ multiTopologyId = new short[len];
+ for (int i = 0; i < len; i++) {
+ multiTopologyId[i] = cb.readShort();
+ }
+
+ return new BgpAttrNodeMultiTopologyId(multiTopologyId);
+ }
+
+ /**
+ * to get the multi-topology ID.
+ *
+ * @return multitopology ID
+ */
+ short[] getAttrMultiTopologyId() {
+ return multiTopologyId;
+ }
+
+ @Override
+ public short getType() {
+ return ATTRNODE_MULTITOPOLOGY;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(multiTopologyId);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj instanceof BgpAttrNodeMultiTopologyId) {
+ BgpAttrNodeMultiTopologyId other = (BgpAttrNodeMultiTopologyId) obj;
+ return Objects.equals(multiTopologyId, other.multiTopologyId);
+ }
+ return false;
+ }
+
+ @Override
+ public int write(ChannelBuffer cb) {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .omitNullValues()
+ .add("multiTopologyId", multiTopologyId)
+ .toString();
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/package-info.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/package-info.java
new file mode 100755
index 00000000..e2a74dbc
--- /dev/null
+++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/package-info.java
@@ -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.
+ */
+
+/**
+ * Implementation of BGP Link state attribute Tlvs.
+ */
+package org.onosproject.bgpio.types.attr;
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/package-info.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/package-info.java
new file mode 100755
index 00000000..1f2ed95e
--- /dev/null
+++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/package-info.java
@@ -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.
+ */
+
+/**
+ * Implementation of Tlvs, Attributes and Descriptors.
+ */
+package org.onosproject.bgpio.types;
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/util/UnSupportedAttribute.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/util/UnSupportedAttribute.java
new file mode 100644
index 00000000..663b1e9a
--- /dev/null
+++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/util/UnSupportedAttribute.java
@@ -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.bgpio.util;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Provides methods to handle UnSupportedAttribute.
+ */
+public final class UnSupportedAttribute {
+ protected static final Logger log = LoggerFactory.getLogger(UnSupportedAttribute.class);
+
+ private UnSupportedAttribute() {
+ }
+
+ /**
+ * Reads channel buffer parses attribute header and skips specified length.
+ *
+ * @param cb channelBuffer
+ */
+ public static void read(ChannelBuffer cb) {
+ Validation parseFlags = Validation.parseAttributeHeader(cb);
+ cb.skipBytes(parseFlags.getLength());
+ }
+
+ /**
+ * Skip specified bytes in channel buffer.
+ *
+ * @param cb channelBuffer
+ * @param length to be skipped
+ */
+ public static void skipBytes(ChannelBuffer cb, short length) {
+ cb.skipBytes(length);
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/util/Validation.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/util/Validation.java
new file mode 100644
index 00000000..915aa580
--- /dev/null
+++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/util/Validation.java
@@ -0,0 +1,189 @@
+/*
+ * 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.util;
+
+import java.util.Arrays;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onosproject.bgpio.exceptions.BGPParseException;
+
+import com.google.common.primitives.Ints;
+
+/**
+ * Provides methods to parse attribute header, validate length and type.
+ */
+public class Validation {
+ 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 IPV4_SIZE = 4;
+ private boolean firstBit;
+ private boolean secondBit;
+ private boolean thirdBit;
+ private boolean fourthBit;
+ private int len;
+ private boolean isShort;
+
+ Validation(boolean firstBit, boolean secondBit, boolean thirdBit, boolean fourthBit, int len, boolean isShort) {
+ this.firstBit = firstBit;
+ this.secondBit = secondBit;
+ this.thirdBit = thirdBit;
+ this.fourthBit = fourthBit;
+ this.len = len;
+ this.isShort = isShort;
+ }
+
+ /**
+ * Parses attribute Header.
+ *
+ * @param cb ChannelBuffer
+ * @return object of Validation
+ */
+ public static Validation parseAttributeHeader(ChannelBuffer cb) {
+
+ boolean firstBit;
+ boolean secondBit;
+ boolean thirdBit;
+ boolean fourthBit;
+ boolean isShort;
+ byte flags = cb.readByte();
+ byte typeCode = cb.readByte();
+ byte temp = flags;
+ //first Bit : Optional (1) or well-known (0)
+ firstBit = ((temp & FIRST_BIT) == FIRST_BIT);
+ //second Bit : Transitive (1) or non-Transitive (0)
+ secondBit = ((temp & SECOND_BIT) == SECOND_BIT);
+ //third Bit : partial (1) or complete (0)
+ thirdBit = ((temp & THIRD_BIT) == THIRD_BIT);
+ //forth Bit(Extended Length bit) : Attribute Length is 1 octects (0) or 2 octects (1)
+ fourthBit = ((temp & FOURTH_BIT) == FOURTH_BIT);
+ int len;
+ if (fourthBit) {
+ isShort = true;
+ short length = cb.readShort();
+ len = length;
+ } else {
+ isShort = false;
+ byte length = cb.readByte();
+ len = length;
+ }
+ return new Validation(firstBit, secondBit, thirdBit, fourthBit, len, isShort);
+ }
+
+ /**
+ * Throws exception if length is not correct.
+ *
+ * @param errorCode Error code
+ * @param subErrCode Sub Error Code
+ * @param length erroneous length
+ * @throws BGPParseException for erroneous length
+ */
+ public static void validateLen(byte errorCode, byte subErrCode, int length) throws BGPParseException {
+ byte[] errLen = Ints.toByteArray(length);
+ ChannelBuffer buffer = ChannelBuffers.dynamicBuffer();
+ buffer.writeBytes(errLen);
+ throw new BGPParseException(errorCode, subErrCode, buffer);
+ }
+
+ /**
+ * Throws exception if type is not correct.
+ *
+ * @param errorCode Error code
+ * @param subErrCode Sub Error Code
+ * @param type erroneous type
+ * @throws BGPParseException for erroneous type
+ */
+ public static void validateType(byte errorCode, byte subErrCode, int type) throws BGPParseException {
+ byte[] errType = Ints.toByteArray(type);
+ ChannelBuffer buffer = ChannelBuffers.dynamicBuffer();
+ buffer.writeBytes(errType);
+ throw new BGPParseException(errorCode, subErrCode, buffer);
+ }
+
+ /**
+ * Returns first bit in type flags.
+ *
+ * @return first bit in type flags
+ */
+ public boolean getFirstBit() {
+ return this.firstBit;
+ }
+
+ /**
+ * Returns second bit in type flags.
+ *
+ * @return second bit in type flags
+ */
+ public boolean getSecondBit() {
+ return this.secondBit;
+ }
+
+ /**
+ * Returns third bit in type flags.
+ *
+ * @return third bit in type flags
+ */
+ public boolean getThirdBit() {
+ return this.thirdBit;
+ }
+
+ /**
+ * Returns fourth bit in type flags.
+ *
+ * @return fourth bit in type flags
+ */
+ public boolean getFourthBit() {
+ return this.fourthBit;
+ }
+
+ /**
+ * Returns attribute length.
+ *
+ * @return attribute length
+ */
+ public int getLength() {
+ return this.len;
+ }
+
+ /**
+ * Returns whether attribute length read in short or byte.
+ *
+ * @return whether attribute length read in short or byte
+ */
+ public boolean isShort() {
+ return this.isShort;
+ }
+
+ /**
+ * Converts byte array of prefix value to IpPrefix object.
+ *
+ * @param value byte array of prefix value
+ * @param length prefix length in bits
+ * @return object of IpPrefix
+ */
+ public static IpPrefix bytesToPrefix(byte[] value, int length) {
+ if (value.length != IPV4_SIZE) {
+ value = Arrays.copyOf(value, IPV4_SIZE);
+ }
+ IpPrefix ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET, value, length);
+ return ipPrefix;
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/util/package-info.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/util/package-info.java
new file mode 100755
index 00000000..3229d89a
--- /dev/null
+++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/util/package-info.java
@@ -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.
+ */
+
+/**
+ * Implementation of BGP utility functions.
+ */
+package org.onosproject.bgpio.util;
diff --git a/framework/src/onos/bgp/ctl/pom.xml b/framework/src/onos/bgp/ctl/pom.xml
new file mode 100755
index 00000000..5cefd737
--- /dev/null
+++ b/framework/src/onos/bgp/ctl/pom.xml
@@ -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.
+ -->
+<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-bgp</artifactId>
+ <version>1.4.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>onos-bgp-ctl</artifactId>
+ <packaging>bundle</packaging>
+
+ <description>ONOS BGP controller subsystem API</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-bgp-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.netty</groupId>
+ <artifactId>netty</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.scr.annotations</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onlab-misc</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-scr-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPChannelHandler.java b/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPChannelHandler.java
new file mode 100755
index 00000000..942d3658
--- /dev/null
+++ b/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPChannelHandler.java
@@ -0,0 +1,34 @@
+/*
+ * 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.impl;
+
+import org.jboss.netty.handler.timeout.IdleStateAwareChannelHandler;
+
+/**
+ * Channel handler deals with the bgp peer connection and dispatches messages from peer to the appropriate locations.
+ */
+class BGPChannelHandler extends IdleStateAwareChannelHandler {
+
+ // TODO: implement FSM and session handling mechanism
+ /**
+ * Create a new unconnected BGPChannelHandler.
+ *
+ * @param bgpCtrlImpl bgp controller implementation object
+ */
+ BGPChannelHandler(BGPControllerImpl bgpCtrlImpl) {
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPConfig.java b/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPConfig.java
new file mode 100755
index 00000000..56877a16
--- /dev/null
+++ b/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPConfig.java
@@ -0,0 +1,344 @@
+/*
+ * 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.impl;
+
+import java.util.Iterator;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeMap;
+
+import org.onlab.packet.Ip4Address;
+import org.onosproject.bgp.controller.BGPCfg;
+import org.onosproject.bgp.controller.BGPPeerCfg;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Provides BGP configuration of this BGP speaker.
+ */
+public class BGPConfig implements BGPCfg {
+
+ protected static final Logger log = LoggerFactory.getLogger(BGPConfig.class);
+
+ private static final short DEFAULT_HOLD_TIMER = 120;
+ private static final short DEFAULT_CONN_RETRY_TIME = 120;
+ private static final short DEFAULT_CONN_RETRY_COUNT = 5;
+
+ private State state = State.INIT;
+ private int localAs;
+ private int maxSession;
+ private boolean lsCapability;
+ private short holdTime;
+ private boolean largeAs = false;
+ private int maxConnRetryTime;
+ private int maxConnRetryCount;
+
+ private Ip4Address routerId = null;
+ private TreeMap<String, BGPPeerCfg> bgpPeerTree = new TreeMap<>();
+
+ /**
+ * Constructor to initialize the values.
+ */
+ public BGPConfig() {
+
+ this.holdTime = DEFAULT_HOLD_TIMER;
+ this.maxConnRetryTime = DEFAULT_CONN_RETRY_TIME;
+ this.maxConnRetryCount = DEFAULT_CONN_RETRY_COUNT;
+ }
+
+ @Override
+ public State getState() {
+ return state;
+ }
+
+ @Override
+ public void setState(State state) {
+ this.state = state;
+ }
+
+ @Override
+ public int getAsNumber() {
+ return this.localAs;
+ }
+
+ @Override
+ public void setAsNumber(int localAs) {
+
+ State localState = getState();
+ this.localAs = localAs;
+
+ /* Set configuration state */
+ if (localState == State.IP_CONFIGURED) {
+ setState(State.IP_AS_CONFIGURED);
+ } else {
+ setState(State.AS_CONFIGURED);
+ }
+ }
+
+ @Override
+ public int getMaxSession() {
+ return this.maxSession;
+ }
+
+ @Override
+ public void setMaxSession(int maxSession) {
+ this.maxSession = maxSession;
+ }
+
+ @Override
+ public boolean getLsCapability() {
+ return this.lsCapability;
+ }
+
+ @Override
+ public void setLsCapability(boolean lsCapability) {
+ this.lsCapability = lsCapability;
+ }
+
+ @Override
+ public String getRouterId() {
+ if (this.routerId != null) {
+ return this.routerId.toString();
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public void setRouterId(String routerId) {
+ State localState = getState();
+ this.routerId = Ip4Address.valueOf(routerId);
+
+ /* Set configuration state */
+ if (localState == State.AS_CONFIGURED) {
+ setState(State.IP_AS_CONFIGURED);
+ } else {
+ setState(State.IP_CONFIGURED);
+ }
+ }
+
+ @Override
+ public boolean addPeer(String routerid, int remoteAs) {
+ return addPeer(routerid, remoteAs, DEFAULT_HOLD_TIMER);
+ }
+
+ @Override
+ public boolean addPeer(String routerid, short holdTime) {
+ return addPeer(routerid, this.getAsNumber(), holdTime);
+ }
+
+ @Override
+ public boolean addPeer(String routerid, int remoteAs, short holdTime) {
+ BGPPeerConfig lspeer = new BGPPeerConfig();
+ if (this.bgpPeerTree.get(routerid) == null) {
+
+ lspeer.setPeerRouterId(routerid);
+ lspeer.setAsNumber(remoteAs);
+ lspeer.setHoldtime(holdTime);
+ lspeer.setState(BGPPeerCfg.State.IDLE);
+ lspeer.setSelfInnitConnection(false);
+
+ if (this.getAsNumber() == remoteAs) {
+ lspeer.setIsIBgp(true);
+ } else {
+ lspeer.setIsIBgp(false);
+ }
+
+ this.bgpPeerTree.put(routerid, lspeer);
+ log.debug("added successfully");
+ return true;
+ } else {
+ log.debug("already exists");
+ return false;
+ }
+ }
+
+ @Override
+ public boolean connectPeer(String routerid) {
+ BGPPeerCfg lspeer = this.bgpPeerTree.get(routerid);
+
+ if (lspeer != null) {
+ lspeer.setSelfInnitConnection(true);
+ // TODO: initiate peer connection
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ public boolean removePeer(String routerid) {
+ BGPPeerCfg lspeer = this.bgpPeerTree.get(routerid);
+
+ if (lspeer != null) {
+
+ //TODO DISCONNECT PEER
+ disconnectPeer(routerid);
+ lspeer.setSelfInnitConnection(false);
+ lspeer = this.bgpPeerTree.remove(routerid);
+ log.debug("Deleted : " + routerid + " successfully");
+
+ return true;
+ } else {
+ log.debug("Did not find : " + routerid);
+ return false;
+ }
+ }
+
+ @Override
+ public boolean disconnectPeer(String routerid) {
+ BGPPeerCfg lspeer = this.bgpPeerTree.get(routerid);
+
+ if (lspeer != null) {
+
+ //TODO DISCONNECT PEER
+ lspeer.setState(BGPPeerCfg.State.IDLE);
+ lspeer.setSelfInnitConnection(false);
+ log.debug("Disconnected : " + routerid + " successfully");
+
+ return true;
+ } else {
+ log.debug("Did not find : " + routerid);
+ return false;
+ }
+ }
+
+ @Override
+ public void setPeerConnState(String routerid, BGPPeerCfg.State state) {
+ BGPPeerCfg lspeer = this.bgpPeerTree.get(routerid);
+
+ if (lspeer != null) {
+ lspeer.setState(state);
+ log.debug("Peer : " + routerid + " is not available");
+
+ return;
+ } else {
+ log.debug("Did not find : " + routerid);
+ return;
+ }
+ }
+
+ @Override
+ public BGPPeerCfg.State getPeerConnState(String routerid) {
+ BGPPeerCfg lspeer = this.bgpPeerTree.get(routerid);
+
+ if (lspeer != null) {
+ return lspeer.getState();
+ } else {
+ return BGPPeerCfg.State.INVALID; //No instance
+ }
+ }
+
+ @Override
+ public boolean isPeerConnectable(String routerid) {
+ BGPPeerCfg lspeer = this.bgpPeerTree.get(routerid);
+
+ if ((lspeer != null) && lspeer.getState().equals(BGPPeerCfg.State.IDLE)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ public TreeMap<String, BGPPeerCfg> getPeerTree() {
+ return this.bgpPeerTree;
+ }
+
+ @Override
+ public TreeMap<String, BGPPeerCfg> displayPeers() {
+ if (this.bgpPeerTree.isEmpty()) {
+ log.debug("There are no BGP peers");
+ } else {
+ Set<Entry<String, BGPPeerCfg>> set = this.bgpPeerTree.entrySet();
+ Iterator<Entry<String, BGPPeerCfg>> list = set.iterator();
+ BGPPeerCfg lspeer;
+
+ while (list.hasNext()) {
+ Entry<String, BGPPeerCfg> me = list.next();
+ lspeer = me.getValue();
+ log.debug("Peer neighbor IP :" + me.getKey());
+ log.debug(", AS Number : " + lspeer.getAsNumber());
+ log.debug(", Hold Timer : " + lspeer.getHoldtime());
+ log.debug(", Is iBGP : " + lspeer.getIsIBgp());
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public BGPPeerCfg displayPeers(String routerid) {
+
+ if (this.bgpPeerTree.isEmpty()) {
+ log.debug("There are no BGP peers");
+ } else {
+ return this.bgpPeerTree.get(routerid);
+ }
+ return null;
+ }
+
+ @Override
+ public void setHoldTime(short holdTime) {
+ this.holdTime = holdTime;
+ }
+
+ @Override
+ public short getHoldTime() {
+ return this.holdTime;
+ }
+
+ @Override
+ public boolean getLargeASCapability() {
+ return this.largeAs;
+ }
+
+ @Override
+ public void setLargeASCapability(boolean largeAs) {
+ this.largeAs = largeAs;
+ }
+
+ @Override
+ public boolean isPeerConfigured(String routerid) {
+ BGPPeerCfg lspeer = this.bgpPeerTree.get(routerid);
+ return (lspeer != null) ? true : false;
+ }
+
+ @Override
+ public boolean isPeerConnected(String routerid) {
+ // TODO: is peer connected
+ return true;
+ }
+
+ @Override
+ public int getMaxConnRetryCount() {
+ return this.maxConnRetryCount;
+ }
+
+ @Override
+ public void setMaxConnRetryCout(int retryCount) {
+ this.maxConnRetryCount = retryCount;
+ }
+
+ @Override
+ public int getMaxConnRetryTime() {
+ return this.maxConnRetryTime;
+ }
+
+ @Override
+ public void setMaxConnRetryTime(int retryTime) {
+ this.maxConnRetryTime = retryTime;
+ }
+}
diff --git a/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPControllerImpl.java b/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPControllerImpl.java
new file mode 100755
index 00000000..95eafdbc
--- /dev/null
+++ b/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPControllerImpl.java
@@ -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.bgp.controller.impl;
+
+import static org.onlab.util.Tools.groupedThreads;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+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.bgp.controller.BGPCfg;
+import org.onosproject.bgp.controller.BGPController;
+import org.onosproject.bgp.controller.BGPId;
+import org.onosproject.bgpio.protocol.BGPMessage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Component(immediate = true)
+@Service
+public class BGPControllerImpl implements BGPController {
+
+ private static final Logger log = LoggerFactory.getLogger(BGPControllerImpl.class);
+
+ private final ExecutorService executorMsgs = Executors.newFixedThreadPool(32,
+ groupedThreads("onos/bgp",
+ "event-stats-%d"));
+
+ private final ExecutorService executorBarrier = Executors.newFixedThreadPool(4,
+ groupedThreads("onos/bgp",
+ "event-barrier-%d"));
+
+ final Controller ctrl = new Controller(this);
+
+ private BGPConfig bgpconfig = new BGPConfig();
+
+ @Activate
+ public void activate() {
+ this.ctrl.start();
+ log.info("Started");
+ }
+
+ @Deactivate
+ public void deactivate() {
+ // Close all connected peers
+ this.ctrl.stop();
+ log.info("Stopped");
+ }
+
+ @Override
+ public void writeMsg(BGPId bgpId, BGPMessage msg) {
+ // TODO: Send message
+ }
+
+ @Override
+ public void processBGPPacket(BGPId bgpId, BGPMessage msg) {
+
+ switch (msg.getType()) {
+ case OPEN:
+ // TODO: Process Open message
+ break;
+ case KEEP_ALIVE:
+ // TODO: Process keepalive message
+ break;
+ case NOTIFICATION:
+ // TODO: Process notificatoin message
+ break;
+ case UPDATE:
+ // TODO: Process update message
+ break;
+ default:
+ // TODO: Process other message
+ break;
+ }
+ }
+
+ /**
+ * Get controller instance.
+ *
+ * @return ctrl the controller.
+ */
+ public Controller getController() {
+ return ctrl;
+ }
+
+ @Override
+ public BGPCfg getConfig() {
+ return this.bgpconfig;
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPMessageDecoder.java b/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPMessageDecoder.java
new file mode 100755
index 00000000..39f2862d
--- /dev/null
+++ b/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPMessageDecoder.java
@@ -0,0 +1,53 @@
+/*
+ * 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.impl;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.channel.Channel;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.handler.codec.frame.FrameDecoder;
+import org.onosproject.bgpio.protocol.BGPMessage;
+import org.onlab.util.HexDump;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Decode an bgp message from a Channel, for use in a netty pipeline.
+ */
+public class BGPMessageDecoder extends FrameDecoder {
+
+ protected static final Logger log = LoggerFactory.getLogger(BGPMessageDecoder.class);
+
+ @Override
+ protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception {
+
+ List<BGPMessage> msgList = new LinkedList<BGPMessage>();
+
+ log.debug("MESSAGE IS RECEIVED.");
+ if (!channel.isConnected()) {
+ log.info("Channel is not connected.");
+ return null;
+ }
+
+ HexDump.dump(buffer);
+
+ // TODO: decode bgp messages
+ return msgList;
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPMessageEncoder.java b/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPMessageEncoder.java
new file mode 100755
index 00000000..f0d38c3d
--- /dev/null
+++ b/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPMessageEncoder.java
@@ -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.bgp.controller.impl;
+
+import java.util.List;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.jboss.netty.channel.Channel;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.handler.codec.oneone.OneToOneEncoder;
+import org.onosproject.bgpio.protocol.BGPMessage;
+import org.onlab.util.HexDump;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Encode an bgp message for output into a ChannelBuffer, for use in a
+ * netty pipeline.
+ */
+public class BGPMessageEncoder extends OneToOneEncoder {
+ protected static final Logger log = LoggerFactory.getLogger(BGPMessageEncoder.class);
+
+ @Override
+ protected Object encode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception {
+ log.debug("BGPMessageEncoder::encode");
+ if (!(msg instanceof List)) {
+ log.debug("Invalid msg.");
+ return msg;
+ }
+
+ @SuppressWarnings("unchecked")
+ List<BGPMessage> msglist = (List<BGPMessage>) msg;
+
+ ChannelBuffer buf = ChannelBuffers.dynamicBuffer();
+
+ log.debug("SENDING MESSAGE");
+ for (BGPMessage pm : msglist) {
+ pm.writeTo(buf);
+ }
+
+ HexDump.dump(buf);
+
+ return buf;
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPPacketStatsImpl.java b/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPPacketStatsImpl.java
new file mode 100755
index 00000000..41407dc4
--- /dev/null
+++ b/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPPacketStatsImpl.java
@@ -0,0 +1,128 @@
+/*
+ * 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.impl;
+
+import org.onosproject.bgp.controller.BGPPacketStats;
+
+/**
+ * A representation of a packet context which allows any provider
+ * to view a packet in event, but may block the response to the
+ * event if blocked has been called. This packet context can be used
+ * to react to the packet in event with a packet out.
+ */
+public class BGPPacketStatsImpl implements BGPPacketStats {
+
+ private int inPacketCount;
+ private int outPacketCount;
+ private int wrongPacketCount;
+ private long time;
+
+ /**
+ * Resets parameter.
+ */
+ public BGPPacketStatsImpl() {
+ this.inPacketCount = 0;
+ this.outPacketCount = 0;
+ this.wrongPacketCount = 0;
+ this.time = 0;
+ }
+
+ /**
+ * Get the outgoing packet count number.
+ *
+ * @return
+ * packet count
+ */
+ public int outPacketCount() {
+ return outPacketCount;
+ }
+
+ /**
+ * Get the incoming packet count number.
+ *
+ * @return
+ * packet count
+ */
+ public int inPacketCount() {
+ return inPacketCount;
+ }
+
+ /**
+ * Get the wrong packet count number.
+ *
+ * @return
+ * packet count
+ */
+ public int wrongPacketCount() {
+ return wrongPacketCount;
+ }
+
+ /**
+ * Increments the received packet counter.
+ */
+ public void addInPacket() {
+ this.inPacketCount++;
+ }
+
+ /**
+ * Increments the sent packet counter.
+ */
+ public void addOutPacket() {
+ this.outPacketCount++;
+ }
+
+ /**
+ * Increments the sent packet counter by specified value.
+ *
+ * @param value of no of packets sent
+ */
+ public void addOutPacket(int value) {
+ this.outPacketCount = this.outPacketCount + value;
+ }
+
+ /**
+ * Increments the wrong packet counter.
+ */
+ public void addWrongPacket() {
+ this.wrongPacketCount++;
+ }
+
+ /**
+ * Resets wrong packet count.
+ */
+ public void resetWrongPacket() {
+ this.wrongPacketCount = 0;
+ }
+
+ /**
+ * Get the time.
+ *
+ * @return
+ * time
+ */
+ public long getTime() {
+ return this.time;
+ }
+
+ /**
+ * Sets the time.
+ *
+ * @param time value to set
+ */
+ public void setTime(long time) {
+ this.time = time;
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPPeerConfig.java b/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPPeerConfig.java
new file mode 100755
index 00000000..51b95a4b
--- /dev/null
+++ b/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPPeerConfig.java
@@ -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.bgp.controller.impl;
+
+import org.onlab.packet.Ip4Address;
+import org.onosproject.bgp.controller.BGPPeerCfg;
+
+/**
+ * BGP Peer configuration information.
+ */
+public class BGPPeerConfig implements BGPPeerCfg {
+ private int asNumber;
+ private short holdTime;
+ private boolean isIBgp;
+ private Ip4Address peerId = null;
+ private State state;
+ private boolean selfInitiated;
+
+ /**
+ * Constructor to initialize the values.
+ */
+ BGPPeerConfig() {
+ state = State.IDLE;
+ selfInitiated = false;
+ }
+
+ @Override
+ public int getAsNumber() {
+ return this.asNumber;
+ }
+
+ @Override
+ public void setAsNumber(int asNumber) {
+ this.asNumber = asNumber;
+ }
+
+ @Override
+ public short getHoldtime() {
+ return this.holdTime;
+ }
+
+ @Override
+ public void setHoldtime(short holdTime) {
+ this.holdTime = holdTime;
+ }
+
+ @Override
+ public boolean getIsIBgp() {
+ return this.isIBgp;
+ }
+
+ @Override
+ public void setIsIBgp(boolean isIBgp) {
+ this.isIBgp = isIBgp;
+ }
+
+ @Override
+ public String getPeerRouterId() {
+ if (this.peerId != null) {
+ return this.peerId.toString();
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public void setPeerRouterId(String peerId) {
+ this.peerId = Ip4Address.valueOf(peerId);
+ }
+
+ @Override
+ public void setPeerRouterId(String peerId, int asNumber) {
+ this.peerId = Ip4Address.valueOf(peerId);
+ this.asNumber = asNumber;
+ }
+
+ @Override
+ public State getState() {
+ return this.state;
+ }
+
+ @Override
+ public void setState(State state) {
+ this.state = state;
+ }
+
+ @Override
+ public boolean getSelfInnitConnection() {
+ return this.selfInitiated;
+ }
+
+ @Override
+ public void setSelfInnitConnection(boolean selfInit) {
+ this.selfInitiated = selfInit;
+ }
+}
diff --git a/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPPipelineFactory.java b/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPPipelineFactory.java
new file mode 100755
index 00000000..b2ca5077
--- /dev/null
+++ b/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPPipelineFactory.java
@@ -0,0 +1,67 @@
+/*
+ * 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.impl;
+
+import org.jboss.netty.channel.ChannelPipeline;
+import org.jboss.netty.channel.ChannelPipelineFactory;
+import org.jboss.netty.channel.Channels;
+import org.jboss.netty.handler.timeout.ReadTimeoutHandler;
+import org.jboss.netty.util.ExternalResourceReleasable;
+import org.jboss.netty.util.HashedWheelTimer;
+import org.jboss.netty.util.Timer;
+
+/**
+ * Creates a ChannelPipeline for a server-side bgp channel.
+ */
+public class BGPPipelineFactory
+ implements ChannelPipelineFactory, ExternalResourceReleasable {
+
+ static final Timer TIMER = new HashedWheelTimer();
+ protected ReadTimeoutHandler readTimeoutHandler;
+ BGPControllerImpl bgpCtrlImpl;
+
+ /**
+ * Constructor to initialize the values.
+ *
+ * @param ctrlImpl parent ctrlImpl
+ * @param isServBgp if it is a server or not
+ */
+ public BGPPipelineFactory(BGPControllerImpl ctrlImpl, boolean isServBgp) {
+ super();
+ bgpCtrlImpl = ctrlImpl;
+ /* hold time*/
+ readTimeoutHandler = new ReadTimeoutHandler(TIMER, bgpCtrlImpl.getConfig().getHoldTime());
+ }
+
+ @Override
+ public ChannelPipeline getPipeline() throws Exception {
+ BGPChannelHandler handler = new BGPChannelHandler(bgpCtrlImpl);
+
+ ChannelPipeline pipeline = Channels.pipeline();
+ pipeline.addLast("bgpmessagedecoder", new BGPMessageDecoder());
+ pipeline.addLast("bgpmessageencoder", new BGPMessageEncoder());
+ pipeline.addLast("holdTime", readTimeoutHandler);
+ pipeline.addLast("PassiveHandler", handler);
+
+ return pipeline;
+ }
+
+ @Override
+ public void releaseExternalResources() {
+ TIMER.stop();
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/Controller.java b/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/Controller.java
new file mode 100755
index 00000000..402e8c94
--- /dev/null
+++ b/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/Controller.java
@@ -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.bgp.controller.impl;
+
+import static org.onlab.util.Tools.groupedThreads;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.RuntimeMXBean;
+import java.net.InetSocketAddress;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Executors;
+
+import org.jboss.netty.bootstrap.ServerBootstrap;
+import org.jboss.netty.channel.ChannelPipelineFactory;
+import org.jboss.netty.channel.group.ChannelGroup;
+import org.jboss.netty.channel.group.DefaultChannelGroup;
+import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The main controller class. Handles all setup and network listeners - Distributed ownership control of bgp peer
+ * through IControllerRegistryService
+ */
+public class Controller {
+
+ protected static final Logger log = LoggerFactory.getLogger(Controller.class);
+
+ private ChannelGroup cg;
+
+ // Configuration options
+ private static final short BGP_PORT_NUM = 179;
+ private int workerThreads = 16;
+
+ // Start time of the controller
+ protected long systemStartTime;
+
+ private NioServerSocketChannelFactory serverExecFactory;
+
+ // Perf. related configuration
+ protected static final int SEND_BUFFER_SIZE = 4 * 1024 * 1024;
+
+ BGPControllerImpl bgpCtrlImpl;
+
+ /**
+ * Constructor to initialize parameter.
+ *
+ * @param bgpCtrlImpl BGP controller Impl instance
+ */
+ public Controller(BGPControllerImpl bgpCtrlImpl) {
+ this.bgpCtrlImpl = bgpCtrlImpl;
+ }
+
+ // ***************
+ // Getters/Setters
+ // ***************
+
+ /**
+ * To get system start time.
+ *
+ * @return system start time in milliseconds
+ */
+ public long getSystemStartTime() {
+ return (this.systemStartTime);
+ }
+
+ // **************
+ // Initialization
+ // **************
+
+ /**
+ * Tell controller that we're ready to accept bgp peer connections.
+ */
+ public void run() {
+
+ try {
+ final ServerBootstrap bootstrap = createServerBootStrap();
+
+ bootstrap.setOption("reuseAddr", true);
+ bootstrap.setOption("child.keepAlive", true);
+ bootstrap.setOption("child.tcpNoDelay", true);
+ bootstrap.setOption("child.sendBufferSize", Controller.SEND_BUFFER_SIZE);
+
+ ChannelPipelineFactory pfact = new BGPPipelineFactory(bgpCtrlImpl, true);
+
+ bootstrap.setPipelineFactory(pfact);
+ InetSocketAddress sa = new InetSocketAddress(getBgpPortNum());
+ cg = new DefaultChannelGroup();
+ cg.add(bootstrap.bind(sa));
+ log.info("Listening for Peer connection on {}", sa);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Creates server boot strap.
+ *
+ * @return ServerBootStrap
+ */
+ private ServerBootstrap createServerBootStrap() {
+
+ if (workerThreads == 0) {
+ serverExecFactory = new NioServerSocketChannelFactory(
+ Executors.newCachedThreadPool(groupedThreads("onos/bgp", "boss-%d")),
+ Executors.newCachedThreadPool(groupedThreads("onos/bgp", "worker-%d")));
+ return new ServerBootstrap(serverExecFactory);
+ } else {
+ serverExecFactory = new NioServerSocketChannelFactory(
+ Executors.newCachedThreadPool(groupedThreads("onos/bgp", "boss-%d")),
+ Executors.newCachedThreadPool(groupedThreads("onos/bgp", "worker-%d")),
+ workerThreads);
+ return new ServerBootstrap(serverExecFactory);
+ }
+ }
+
+ /**
+ * Initialize internal data structures.
+ */
+ public void init() {
+ // These data structures are initialized here because other
+ // module's startUp() might be called before ours
+ this.systemStartTime = System.currentTimeMillis();
+ }
+
+ // **************
+ // Utility methods
+ // **************
+
+ public Map<String, Long> getMemory() {
+ Map<String, Long> m = new HashMap<>();
+ Runtime runtime = Runtime.getRuntime();
+ m.put("total", runtime.totalMemory());
+ m.put("free", runtime.freeMemory());
+ return m;
+ }
+
+ public Long getUptime() {
+ RuntimeMXBean rb = ManagementFactory.getRuntimeMXBean();
+ return rb.getUptime();
+ }
+
+ /**
+ * Starts the BGP controller.
+ */
+ public void start() {
+ log.info("Started");
+ this.init();
+ this.run();
+ }
+
+ /**
+ * Stops the BGP controller.
+ */
+ public void stop() {
+ log.info("Stopped");
+ serverExecFactory.shutdown();
+ cg.close();
+ }
+
+ /**
+ * Returns port number.
+ *
+ * @return port number
+ */
+ public static short getBgpPortNum() {
+ return BGP_PORT_NUM;
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/package-info.java b/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/package-info.java
new file mode 100755
index 00000000..fd4e9506
--- /dev/null
+++ b/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/package-info.java
@@ -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.
+ */
+
+/**
+ * Implementation of the BGP controller IO subsystem.
+ */
+package org.onosproject.bgp.controller.impl;
diff --git a/framework/src/onos/bgp/pom.xml b/framework/src/onos/bgp/pom.xml
new file mode 100755
index 00000000..941168ba
--- /dev/null
+++ b/framework/src/onos/bgp/pom.xml
@@ -0,0 +1,60 @@
+<?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</artifactId>
+ <version>1.4.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>onos-bgp</artifactId>
+ <packaging>pom</packaging>
+
+ <description>ONOS BGP Protocol subsystem</description>
+
+ <modules>
+ <module>api</module>
+ <module>ctl</module>
+ <module>bgpio</module>
+ </modules>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onlab-misc</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onlab-junit</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/Comparators.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/Comparators.java
index b0cbbdd6..1df2f049 100644
--- a/framework/src/onos/cli/src/main/java/org/onosproject/cli/Comparators.java
+++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/Comparators.java
@@ -25,6 +25,8 @@ import org.onosproject.net.ElementId;
import org.onosproject.net.Port;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.group.Group;
+
+import org.onosproject.net.statistic.TypedFlowEntryWithLoad;
import org.onosproject.net.topology.TopologyCluster;
import java.util.Comparator;
@@ -115,4 +117,12 @@ public final class Comparators {
public static final Comparator<Interface> INTERFACES_COMPARATOR = (intf1, intf2) ->
CONNECT_POINT_COMPARATOR.compare(intf1.connectPoint(), intf2.connectPoint());
+ public static final Comparator<TypedFlowEntryWithLoad> TYPEFLOWENTRY_WITHLOAD_COMPARATOR =
+ new Comparator<TypedFlowEntryWithLoad>() {
+ @Override
+ public int compare(TypedFlowEntryWithLoad fe1, TypedFlowEntryWithLoad fe2) {
+ long delta = fe1.load().rate() - fe2.load().rate();
+ return delta == 0 ? 0 : (delta > 0 ? -1 : +1);
+ }
+ };
}
diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/cfg/NetworkConfigCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/cfg/NetworkConfigCommand.java
index d99a1839..7ce56692 100644
--- a/framework/src/onos/cli/src/main/java/org/onosproject/cli/cfg/NetworkConfigCommand.java
+++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/cfg/NetworkConfigCommand.java
@@ -35,13 +35,13 @@ import static com.google.common.base.Strings.isNullOrEmpty;
description = "Manages network configuration")
public class NetworkConfigCommand extends AbstractShellCommand {
- @Argument(index = 0, name = "subjectKey", description = "Subject key",
+ @Argument(index = 0, name = "subjectClassKey", description = "Subject class key",
required = false, multiValued = false)
- String subjectKey = null;
+ String subjectClassKey = null;
- @Argument(index = 1, name = "subject", description = "Subject",
+ @Argument(index = 1, name = "subjectKey", description = "Subject key",
required = false, multiValued = false)
- String subject = null;
+ String subjectKey = null;
@Argument(index = 2, name = "configKey", description = "Config key",
required = false, multiValued = false)
@@ -54,18 +54,18 @@ public class NetworkConfigCommand extends AbstractShellCommand {
protected void execute() {
service = get(NetworkConfigService.class);
JsonNode root = mapper.createObjectNode();
- if (isNullOrEmpty(subjectKey)) {
+ if (isNullOrEmpty(subjectClassKey)) {
addAll((ObjectNode) root);
} else {
- SubjectFactory subjectFactory = service.getSubjectFactory(subjectKey);
- if (isNullOrEmpty(subject)) {
+ SubjectFactory subjectFactory = service.getSubjectFactory(subjectClassKey);
+ if (isNullOrEmpty(subjectKey)) {
addSubjectClass((ObjectNode) root, subjectFactory);
} else {
- Object s = subjectFactory.createSubject(subject);
+ Object s = subjectFactory.createSubject(subjectKey);
if (isNullOrEmpty(configKey)) {
addSubject((ObjectNode) root, s);
} else {
- root = getSubjectConfig(getConfig(s, subjectKey, configKey));
+ root = getSubjectConfig(getConfig(s, subjectClassKey, configKey));
}
}
}
@@ -82,14 +82,14 @@ public class NetworkConfigCommand extends AbstractShellCommand {
service.getSubjectClasses()
.forEach(sc -> {
SubjectFactory sf = service.getSubjectFactory(sc);
- addSubjectClass(newObject(root, sf.subjectKey()), sf);
+ addSubjectClass(newObject(root, sf.subjectClassKey()), sf);
});
}
@SuppressWarnings("unchecked")
private void addSubjectClass(ObjectNode root, SubjectFactory sf) {
service.getSubjects(sf.subjectClass())
- .forEach(s -> addSubject(newObject(root, s.toString()), s));
+ .forEach(s -> addSubject(newObject(root, sf.subjectKey(s)), s));
}
private void addSubject(ObjectNode root, Object s) {
diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/cfg/NetworkConfigRegistryCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/cfg/NetworkConfigRegistryCommand.java
index f94967e1..cf588770 100644
--- a/framework/src/onos/cli/src/main/java/org/onosproject/cli/cfg/NetworkConfigRegistryCommand.java
+++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/cfg/NetworkConfigRegistryCommand.java
@@ -42,7 +42,7 @@ public class NetworkConfigRegistryCommand extends AbstractShellCommand {
private void print(ConfigFactory configFactory) {
print(shortOnly ? SHORT_FMT : FMT,
- configFactory.subjectFactory().subjectKey(),
+ configFactory.subjectFactory().subjectClassKey(),
configFactory.configKey(),
configFactory.subjectFactory().subjectClass().getName(),
configFactory.configClass().getName());
diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/DeviceControllersCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/DeviceControllersCommand.java
new file mode 100644
index 00000000..328d4700
--- /dev/null
+++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/DeviceControllersCommand.java
@@ -0,0 +1,47 @@
+/*
+ * 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.cli.net;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.behaviour.ControllerConfig;
+import org.onosproject.net.driver.DriverHandler;
+import org.onosproject.net.driver.DriverService;
+
+/**
+ * Sets role of the controller node for the given infrastructure device.
+ */
+@Command(scope = "onos", name = "device-controllers",
+ description = "gets the list of controllers for the given infrastructure device")
+public class DeviceControllersCommand extends AbstractShellCommand {
+
+ @Argument(index = 0, name = "uri", description = "Device ID",
+ required = true, multiValued = false)
+ String uri = null;
+ private DeviceId deviceId;
+
+ @Override
+ protected void execute() {
+ DriverService service = get(DriverService.class);
+ deviceId = DeviceId.deviceId(uri);
+ DriverHandler h = service.createHandler(deviceId);
+ ControllerConfig config = h.behaviour(ControllerConfig.class);
+ config.getControllers().forEach(c -> print(c.target()));
+ }
+
+}
diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/DevicePortsListCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/DevicePortsListCommand.java
index 494273cc..e2d3e6d6 100644
--- a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/DevicePortsListCommand.java
+++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/DevicePortsListCommand.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 Open Networking Laboratory
+ * 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.
@@ -22,8 +22,12 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
import org.apache.karaf.shell.commands.Option;
+import org.onlab.util.Frequency;
import org.onosproject.cli.Comparators;
import org.onosproject.net.Device;
+import org.onosproject.net.OchPort;
+import org.onosproject.net.OduCltPort;
+import org.onosproject.net.OmsPort;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import org.onosproject.net.device.DeviceService;
@@ -41,7 +45,10 @@ import static org.onosproject.net.DeviceId.deviceId;
description = "Lists all ports or all ports of a device")
public class DevicePortsListCommand extends DevicesListCommand {
- private static final String FMT = " port=%s, state=%s, type=%s, speed=%s%s";
+ private static final String FMT = " port=%s, state=%s, type=%s, speed=%s %s";
+ private static final String FMT_OCH = " port=%s, state=%s, type=%s, signalType=%s, isTunable=%s %s";
+ private static final String FMT_ODUCLT = " port=%s, state=%s, type=%s, signalType=%s %s";
+ private static final String FMT_OMS = " port=%s, state=%s, type=%s, Freqs= %s / %s / %s GHz, totalChannels=%s %s";
@Option(name = "-e", aliases = "--enabled", description = "Show only enabled ports",
required = false, multiValued = false)
@@ -137,13 +144,34 @@ public class DevicePortsListCommand extends DevicesListCommand {
List<Port> ports = new ArrayList<>(service.getPorts(device.id()));
Collections.sort(ports, Comparators.PORT_COMPARATOR);
for (Port port : ports) {
- if (isIncluded(port)) {
- print(FMT, portName(port.number()),
- port.isEnabled() ? "enabled" : "disabled",
- port.type().toString().toLowerCase(), port.portSpeed(),
- annotations(port.annotations()));
+ if (!isIncluded(port)) {
+ continue;
+ }
+ String portName = portName(port.number());
+ Object portIsEnabled = port.isEnabled() ? "enabled" : "disabled";
+ String portType = port.type().toString().toLowerCase();
+ String annotations = annotations(port.annotations());
+ switch (port.type()) {
+ case OCH:
+ print(FMT_OCH, portName, portIsEnabled, portType,
+ ((OchPort) port).signalType().toString(),
+ ((OchPort) port).isTunable() ? "yes" : "no", annotations);
+ break;
+ case ODUCLT:
+ print(FMT_ODUCLT, portName, portIsEnabled, portType,
+ ((OduCltPort) port).signalType().toString(), annotations);
+ break;
+ case OMS:
+ print(FMT_OMS, portName, portIsEnabled, portType,
+ ((OmsPort) port).minFrequency().asHz() / Frequency.ofGHz(1).asHz(),
+ ((OmsPort) port).maxFrequency().asHz() / Frequency.ofGHz(1).asHz(),
+ ((OmsPort) port).grid().asHz() / Frequency.ofGHz(1).asHz(),
+ ((OmsPort) port).totalChannels(), annotations);
+ break;
+ default:
+ print(FMT, portName, portIsEnabled, portType, port.portSpeed(), annotations);
+ break;
}
}
}
-
}
diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/DeviceSetControllersCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/DeviceSetControllersCommand.java
new file mode 100644
index 00000000..c3693799
--- /dev/null
+++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/DeviceSetControllersCommand.java
@@ -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.cli.net;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.behaviour.ControllerConfig;
+import org.onosproject.net.behaviour.ControllerInfo;
+import org.onosproject.net.driver.DriverHandler;
+import org.onosproject.net.driver.DriverService;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Sets role of the controller node for the given infrastructure device.
+ */
+@Command(scope = "onos", name = "device-setcontrollers",
+ description = "sets the list of controllers for the given infrastructure device")
+public class DeviceSetControllersCommand extends AbstractShellCommand {
+
+ @Argument(index = 0, name = "uri", description = "Device ID",
+ required = true, multiValued = false)
+ String uri = null;
+
+ @Argument(index = 1, name = "controllersListStrings", description = "list of " +
+ "controllers to set for the specified device",
+ required = true, multiValued = true)
+ String[] controllersListStrings = null;
+
+ private DeviceId deviceId;
+ private List<ControllerInfo> newControllers = new ArrayList<>();
+
+ @Override
+ protected void execute() {
+
+ Arrays.asList(controllersListStrings).forEach(
+ cInfoString -> newControllers.add(new ControllerInfo(cInfoString)));
+ DriverService service = get(DriverService.class);
+ deviceId = DeviceId.deviceId(uri);
+ DriverHandler h = service.createHandler(deviceId);
+ ControllerConfig config = h.behaviour(ControllerConfig.class);
+ print("before:");
+ config.getControllers().forEach(c -> print(c.target()));
+
+ config.setControllers(newControllers);
+ print("after:");
+ config.getControllers().forEach(c -> print(c.target()));
+ print("size %d", config.getControllers().size());
+ }
+
+}
diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/GetFlowStatistics.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/GetFlowStatistics.java
new file mode 100644
index 00000000..cafe87f9
--- /dev/null
+++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/GetFlowStatistics.java
@@ -0,0 +1,323 @@
+/*
+ * 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.cli.net;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.shell.commands.Option;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.flow.TypedStoredFlowEntry;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.statistic.FlowStatisticService;
+import org.onosproject.net.statistic.SummaryFlowEntryWithLoad;
+import org.onosproject.net.statistic.TypedFlowEntryWithLoad;
+
+import java.util.List;
+import java.util.Map;
+
+import static org.onosproject.net.DeviceId.deviceId;
+import static org.onosproject.net.PortNumber.portNumber;
+
+/**
+ * Fetches flow statistics with a flow type and instruction type.
+ */
+@Command(scope = "onos", name = "get-flow-stats",
+ description = "Fetches flow stats for a connection point with given flow type and instruction type")
+public class GetFlowStatistics extends AbstractShellCommand {
+ @Argument(index = 0, name = "devicePort",
+ description = "Device[/Port] connectPoint Description",
+ required = true, multiValued = false)
+ String devicePort = null;
+
+ @Option(name = "-s", aliases = "--summary",
+ description = "Show flow stats summary",
+ required = false, multiValued = false)
+ boolean showSummary = true; // default summary
+
+ @Option(name = "-a", aliases = "--all",
+ description = "Show flow stats all",
+ required = false, multiValued = false)
+ boolean showAll = false;
+
+ @Option(name = "-t", aliases = "--topn",
+ description = "Show flow stats topn",
+ required = false, multiValued = false)
+ String showTopn = null;
+
+ @Option(name = "-f", aliases = "--flowType",
+ description = "Flow live type, It includes IMMEDIATE, SHORT, MID, LONG, UNKNOWN"
+ + ", and is valid with -a or -t option only",
+ required = false, multiValued = false)
+ String flowLiveType = null;
+
+ @Option(name = "-i", aliases = "--instructionType",
+ description = "Flow instruction type, It includes DROP, OUTPUT, GROUP, L0MODIFICATION, L2MODIFICATION,"
+ + " TABLE, L3MODIFICATION, METADATA"
+ + ", and is valid with -a or -t option only",
+ required = false, multiValued = false)
+ String instructionType = null;
+
+ @Override
+ protected void execute() {
+ DeviceService deviceService = get(DeviceService.class);
+ FlowStatisticService flowStatsService = get(FlowStatisticService.class);
+
+ String deviceURI = getDeviceId(devicePort);
+ String portURI = getPortNumber(devicePort);
+
+ DeviceId ingressDeviceId = deviceId(deviceURI);
+ PortNumber ingressPortNumber;
+ if (portURI.length() == 0) {
+ ingressPortNumber = null;
+ } else {
+ ingressPortNumber = portNumber(portURI);
+ }
+
+ Device device = deviceService.getDevice(ingressDeviceId);
+ if (device == null) {
+ error("No such device %s", ingressDeviceId.uri());
+ return;
+ }
+
+ if (ingressPortNumber != null) {
+ Port port = deviceService.getPort(ingressDeviceId, ingressPortNumber);
+ if (port == null) {
+ error("No such port %s on device %s", portURI, ingressDeviceId.uri());
+ return;
+ }
+ }
+
+ if (flowLiveType != null) {
+ flowLiveType = flowLiveType.toUpperCase();
+ }
+ if (instructionType != null) {
+ instructionType = instructionType.toUpperCase();
+ }
+
+ // convert String to FlowLiveType and check validity
+ TypedStoredFlowEntry.FlowLiveType inLiveType;
+ if (flowLiveType == null) {
+ inLiveType = null;
+ } else {
+ inLiveType = getFlowLiveType(flowLiveType);
+ if (inLiveType == null) {
+ error("Invalid flow live type [%s] error", flowLiveType);
+ return;
+ }
+ }
+ // convert String to InstructionType and check validity
+ Instruction.Type inInstructionType;
+ if (instructionType == null) {
+ inInstructionType = null;
+ } else {
+ inInstructionType = getInstructionType(instructionType);
+ if (inInstructionType == null) {
+ error("Invalid instruction type [%s] error", instructionType);
+ return;
+ }
+ }
+
+ if (showTopn != null) {
+ int topn = Integer.parseInt(showTopn);
+
+ if (topn <= 0) {
+ topn = 100; //default value
+ } else if (topn > 1000) {
+ topn = 1000; //max value
+ }
+
+ // print show topn head line with type
+ print("deviceId=%s, show TOPN=%s flows, live type=%s, instruction type=%s",
+ deviceURI,
+ Integer.toString(topn),
+ flowLiveType == null ? "ALL" : flowLiveType,
+ instructionType == null ? "ALL" : instructionType);
+ if (ingressPortNumber == null) {
+ Map<ConnectPoint, List<TypedFlowEntryWithLoad>> typedFlowLoadMap =
+ flowStatsService.loadTopnByType(device, inLiveType, inInstructionType, topn);
+ // print all ports topn flows load for a given device
+ for (ConnectPoint cp : typedFlowLoadMap.keySet()) {
+ printPortFlowsLoad(cp, typedFlowLoadMap.get(cp));
+ }
+ } else {
+ List<TypedFlowEntryWithLoad> typedFlowLoad =
+ flowStatsService.loadTopnByType(device, ingressPortNumber, inLiveType, inInstructionType, topn);
+ // print device/port topn flows load
+ ConnectPoint cp = new ConnectPoint(ingressDeviceId, ingressPortNumber);
+ printPortFlowsLoad(cp, typedFlowLoad);
+ }
+ } else if (showAll) { // is true?
+ // print show all head line with type
+ print("deviceId=%s, show ALL flows, live type=%s, instruction type=%s",
+ deviceURI,
+ flowLiveType == null ? "ALL" : flowLiveType,
+ instructionType == null ? "ALL" : instructionType);
+ if (ingressPortNumber == null) {
+ Map<ConnectPoint, List<TypedFlowEntryWithLoad>> typedFlowLoadMap =
+ flowStatsService.loadAllByType(device, inLiveType, inInstructionType);
+ // print all ports all flows load for a given device
+ for (ConnectPoint cp : typedFlowLoadMap.keySet()) {
+ printPortFlowsLoad(cp, typedFlowLoadMap.get(cp));
+ }
+ } else {
+ List<TypedFlowEntryWithLoad> typedFlowLoad =
+ flowStatsService.loadAllByType(device, ingressPortNumber, inLiveType, inInstructionType);
+ // print device/port all flows load
+ ConnectPoint cp = new ConnectPoint(ingressDeviceId, ingressPortNumber);
+ printPortFlowsLoad(cp, typedFlowLoad);
+ }
+ } else { // if (showSummary == true) //always is true
+ // print show summary head line
+ print("deviceId=%s, show SUMMARY flows", deviceURI);
+ if (ingressPortNumber == null) {
+ Map<ConnectPoint, SummaryFlowEntryWithLoad> summaryFlowLoadMap =
+ flowStatsService.loadSummary(device);
+ // print all ports flow load summary for a given device
+ for (ConnectPoint cp : summaryFlowLoadMap.keySet()) {
+ printPortSummaryLoad(cp, summaryFlowLoadMap.get(cp));
+ }
+ } else {
+ SummaryFlowEntryWithLoad summaryFlowLoad =
+ flowStatsService.loadSummary(device, ingressPortNumber);
+ // print device/port flow load summary
+ ConnectPoint cp = new ConnectPoint(ingressDeviceId, ingressPortNumber);
+ printPortSummaryLoad(cp, summaryFlowLoad);
+ }
+ }
+ }
+
+ /**
+ * Extracts the port number portion of the ConnectPoint.
+ *
+ * @param deviceString string representing the device/port
+ * @return port number as a string, empty string if the port is not found
+ */
+ private String getPortNumber(String deviceString) {
+ if (deviceString == null) {
+ return "";
+ }
+
+ int slash = deviceString.indexOf('/');
+ if (slash <= 0) {
+ return ""; // return when no port number
+ }
+ return deviceString.substring(slash + 1, deviceString.length());
+ }
+
+ /**
+ * Extracts the device ID portion of the ConnectPoint.
+ *
+ * @param deviceString string representing the device/port
+ * @return device ID string
+ */
+ private String getDeviceId(String deviceString) {
+ if (deviceString == null) {
+ return "";
+ }
+
+ int slash = deviceString.indexOf('/');
+ if (slash <= 0) {
+ return deviceString; // return only included device ID
+ }
+ return deviceString.substring(0, slash);
+ }
+
+ /**
+ * converts string of flow live type to FloeLiveType enum.
+ *
+ * @param liveType string representing the flow live type
+ * @return TypedStoredFlowEntry.FlowLiveType
+ */
+ private TypedStoredFlowEntry.FlowLiveType getFlowLiveType(String liveType) {
+ String liveTypeUC = liveType.toUpperCase();
+
+ if (liveTypeUC.equals("IMMEDIATE")) {
+ return TypedStoredFlowEntry.FlowLiveType.IMMEDIATE_FLOW;
+ } else if (liveTypeUC.equals("SHORT")) {
+ return TypedStoredFlowEntry.FlowLiveType.SHORT_FLOW;
+ } else if (liveTypeUC.equals("MID")) {
+ return TypedStoredFlowEntry.FlowLiveType.MID_FLOW;
+ } else if (liveTypeUC.equals("LONG")) {
+ return TypedStoredFlowEntry.FlowLiveType.LONG_FLOW;
+ } else if (liveTypeUC.equals("UNKNOWN")) {
+ return TypedStoredFlowEntry.FlowLiveType.UNKNOWN_FLOW;
+ } else {
+ return null; // flow live type error
+ }
+ }
+
+ /**
+ * converts string of instruction type to Instruction type enum.
+ *
+ * @param instType string representing the instruction type
+ * @return Instruction.Type
+ */
+ private Instruction.Type getInstructionType(String instType) {
+ String instTypeUC = instType.toUpperCase();
+
+ if (instTypeUC.equals("DROP")) {
+ return Instruction.Type.DROP;
+ } else if (instTypeUC.equals("OUTPUT")) {
+ return Instruction.Type.OUTPUT;
+ } else if (instTypeUC.equals("GROUP")) {
+ return Instruction.Type.GROUP;
+ } else if (instTypeUC.equals("L0MODIFICATION")) {
+ return Instruction.Type.L0MODIFICATION;
+ } else if (instTypeUC.equals("L2MODIFICATION")) {
+ return Instruction.Type.L2MODIFICATION;
+ } else if (instTypeUC.equals("TABLE")) {
+ return Instruction.Type.TABLE;
+ } else if (instTypeUC.equals("L3MODIFICATION")) {
+ return Instruction.Type.L3MODIFICATION;
+ } else if (instTypeUC.equals("METADATA")) {
+ return Instruction.Type.METADATA;
+ } else {
+ return null; // instruction type error
+ }
+ }
+
+ private void printPortFlowsLoad(ConnectPoint cp, List<TypedFlowEntryWithLoad> typedFlowLoad) {
+ print(" deviceId/Port=%s/%s, %s flows", cp.elementId(), cp.port(), typedFlowLoad.size());
+ for (TypedFlowEntryWithLoad tfel: typedFlowLoad) {
+ TypedStoredFlowEntry tfe = tfel.typedStoredFlowEntry();
+ print(" flowId=%s, state=%s, liveType=%s, life=%s -> %s",
+ Long.toHexString(tfe.id().value()),
+ tfe.state(),
+ tfe.flowLiveType(),
+ tfe.life(),
+ tfel.load().isValid() ? tfel.load() : "Load{rate=0, NOT VALID}");
+ }
+ }
+
+ private void printPortSummaryLoad(ConnectPoint cp, SummaryFlowEntryWithLoad summaryFlowLoad) {
+ print(" deviceId/Port=%s/%s, Total=%s, Immediate=%s, Short=%s, Mid=%s, Long=%s, Unknown=%s",
+ cp.elementId(),
+ cp.port(),
+ summaryFlowLoad.totalLoad().isValid() ? summaryFlowLoad.totalLoad() : "Load{rate=0, NOT VALID}",
+ summaryFlowLoad.immediateLoad().isValid() ? summaryFlowLoad.immediateLoad() : "Load{rate=0, NOT VALID}",
+ summaryFlowLoad.shortLoad().isValid() ? summaryFlowLoad.shortLoad() : "Load{rate=0, NOT VALID}",
+ summaryFlowLoad.midLoad().isValid() ? summaryFlowLoad.midLoad() : "Load{rate=0, NOT VALID}",
+ summaryFlowLoad.longLoad().isValid() ? summaryFlowLoad.longLoad() : "Load{rate=0, NOT VALID}",
+ summaryFlowLoad.unknownLoad().isValid() ? summaryFlowLoad.unknownLoad() : "Load{rate=0, NOT VALID}");
+ }
+}
diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/InterfaceAddCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/InterfaceAddCommand.java
new file mode 100644
index 00000000..eefb711a
--- /dev/null
+++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/InterfaceAddCommand.java
@@ -0,0 +1,79 @@
+/*
+ * 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.cli.net;
+
+import com.google.common.collect.Sets;
+import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.shell.commands.Option;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.incubator.net.intf.Interface;
+import org.onosproject.incubator.net.intf.InterfaceAdminService;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.host.InterfaceIpAddress;
+
+import java.util.Set;
+
+/**
+ * Adds a new interface configuration.
+ */
+@Command(scope = "onos", name = "add-interface",
+ description = "Adds a new configured interface")
+public class InterfaceAddCommand extends AbstractShellCommand {
+
+ @Option(name = "-c", aliases = "--connectPoint",
+ description = "Device port that the interface is associated with",
+ required = true, multiValued = false)
+ private String connectPoint = null;
+
+ @Option(name = "-m", aliases = "--mac",
+ description = "MAC address of the interface",
+ required = true, multiValued = false)
+ private String mac = null;
+
+ @Option(name = "-i", aliases = "--ip",
+ description = "IP address configured on the interface\n" +
+ "(e.g. 10.0.1.1/24). Can be specified multiple times.",
+ required = false, multiValued = true)
+ private String[] ips = null;
+
+ @Option(name = "-v", aliases = "--vlan",
+ description = "VLAN configured on the interface",
+ required = false, multiValued = false)
+ private String vlan = null;
+
+ @Override
+ protected void execute() {
+ InterfaceAdminService interfaceService = get(InterfaceAdminService.class);
+
+ Set<InterfaceIpAddress> ipAddresses = Sets.newHashSet();
+ if (ips != null) {
+ for (String strIp : ips) {
+ ipAddresses.add(InterfaceIpAddress.valueOf(strIp));
+ }
+ }
+
+ VlanId vlanId = vlan == null ? VlanId.NONE : VlanId.vlanId(Short.parseShort(vlan));
+
+ Interface intf = new Interface(ConnectPoint.deviceConnectPoint(connectPoint),
+ ipAddresses, MacAddress.valueOf(mac), vlanId);
+
+ interfaceService.add(intf);
+ }
+
+}
diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/InterfaceRemoveCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/InterfaceRemoveCommand.java
new file mode 100644
index 00000000..941a65db
--- /dev/null
+++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/InterfaceRemoveCommand.java
@@ -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.cli.net;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onlab.packet.VlanId;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.incubator.net.intf.InterfaceAdminService;
+import org.onosproject.net.ConnectPoint;
+
+/**
+ * Removes an interface configuration.
+ */
+@Command(scope = "onos", name = "remove-interface",
+ description = "Removes a configured interface")
+public class InterfaceRemoveCommand extends AbstractShellCommand {
+
+ @Argument(index = 0, name = "connectPoint",
+ description = "Connect point of the interface",
+ required = true, multiValued = false)
+ private String connectPoint = null;
+
+ @Argument(index = 1, name = "vlan",
+ description = "Interface vlan",
+ required = true, multiValued = false)
+ private String vlan = null;
+
+ @Override
+ protected void execute() {
+ InterfaceAdminService interfaceService = get(InterfaceAdminService.class);
+
+ interfaceService.remove(ConnectPoint.deviceConnectPoint(connectPoint),
+ VlanId.vlanId(Short.parseShort(vlan)));
+ }
+
+}
diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/PacketProcessorsListCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/PacketProcessorsListCommand.java
index ff66b803..6b7d9336 100644
--- a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/PacketProcessorsListCommand.java
+++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/PacketProcessorsListCommand.java
@@ -17,7 +17,7 @@ package org.onosproject.cli.net;
import org.apache.karaf.shell.commands.Command;
import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.net.packet.PacketProcessor;
+import org.onosproject.net.packet.PacketProcessorEntry;
import org.onosproject.net.packet.PacketService;
import static org.onosproject.net.packet.PacketProcessor.ADVISOR_MAX;
@@ -30,7 +30,7 @@ import static org.onosproject.net.packet.PacketProcessor.DIRECTOR_MAX;
description = "Lists packet processors")
public class PacketProcessorsListCommand extends AbstractShellCommand {
- private static final String FMT = "priority=%s, class=%s";
+ private static final String FMT = "priority=%s, class=%s, packets=%d, avgNanos=%d";
@Override
protected void execute() {
@@ -43,8 +43,10 @@ public class PacketProcessorsListCommand extends AbstractShellCommand {
}
}
- private void print(int priority, PacketProcessor processor) {
- print(FMT, priorityFormat(priority), processor.getClass().getName());
+ private void print(PacketProcessorEntry entry) {
+ print(FMT, priorityFormat(entry.priority()),
+ entry.processor().getClass().getName(),
+ entry.invocations(), entry.averageNanos());
}
private String priorityFormat(int priority) {
diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/TableStatisticsCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/TableStatisticsCommand.java
new file mode 100644
index 00000000..e0cd72fc
--- /dev/null
+++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/TableStatisticsCommand.java
@@ -0,0 +1,145 @@
+/*
+ * 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.cli.net;
+
+import static com.google.common.collect.Lists.newArrayList;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.shell.commands.Option;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.cli.Comparators;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.flow.FlowRuleService;
+import org.onosproject.net.flow.TableStatisticsEntry;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * Lists port statistic of all ports in the system.
+ */
+@Command(scope = "onos", name = "tablestats",
+ description = "Lists statistics of all tables in the device")
+public class TableStatisticsCommand extends AbstractShellCommand {
+
+ @Option(name = "-t", aliases = "--table", description = "Show human readable table format for statistics",
+ required = false, multiValued = false)
+ private boolean table = false;
+
+ @Argument(index = 0, name = "uri", description = "Device ID",
+ required = false, multiValued = false)
+ String uri = null;
+
+ private static final String FORMAT =
+ " table=%s, active=%s, lookedup=%s, matched=%s";
+
+ @Override
+ protected void execute() {
+ FlowRuleService flowService = get(FlowRuleService.class);
+ DeviceService deviceService = get(DeviceService.class);
+
+ SortedMap<Device, List<TableStatisticsEntry>> deviceTableStats =
+ getSortedTableStats(deviceService, flowService);
+
+ if (outputJson()) {
+ print("%s", json(deviceTableStats.keySet(), deviceTableStats));
+ } else {
+ deviceTableStats.forEach((device, tableStats) -> printTableStats(device, tableStats));
+ }
+ }
+
+ /**
+ * Produces a JSON array of table statistics grouped by the each device.
+ *
+ * @param devices collection of devices
+ * @param deviceTableStats collection of table statistics per each device
+ * @return JSON array
+ */
+ private JsonNode json(Iterable<Device> devices,
+ Map<Device, List<TableStatisticsEntry>> deviceTableStats) {
+ ObjectMapper mapper = new ObjectMapper();
+ ArrayNode result = mapper.createArrayNode();
+ for (Device device : devices) {
+ result.add(json(mapper, device, deviceTableStats.get(device)));
+ }
+ return result;
+ }
+
+ // Produces JSON object with the table statistics of the given device.
+ private ObjectNode json(ObjectMapper mapper,
+ Device device, List<TableStatisticsEntry> tableStats) {
+ ObjectNode result = mapper.createObjectNode();
+ ArrayNode array = mapper.createArrayNode();
+
+ tableStats.forEach(tableStat -> array.add(jsonForEntity(tableStat, TableStatisticsEntry.class)));
+
+ result.put("device", device.id().toString())
+ .put("tableCount", tableStats.size())
+ .set("tables", array);
+ return result;
+ }
+
+ /**
+ * Prints flow table statistics.
+ *
+ * @param d the device
+ * @param tableStats the set of flow table statistics for that device
+ */
+ protected void printTableStats(Device d,
+ List<TableStatisticsEntry> tableStats) {
+ boolean empty = tableStats == null || tableStats.isEmpty();
+ print("deviceId=%s, tableCount=%d", d.id(), empty ? 0 : tableStats.size());
+ if (!empty) {
+ for (TableStatisticsEntry t : tableStats) {
+ print(FORMAT, t.tableId(), t.activeFlowEntries(),
+ t.packetsLookedup(), t.packetsMatched());
+ }
+ }
+ }
+
+ /**
+ * Returns the list of table statistics sorted using the device ID URIs and table IDs.
+ *
+ * @param deviceService device service
+ * @param flowService flow rule service
+ * @return sorted table statistics list
+ */
+ protected SortedMap<Device, List<TableStatisticsEntry>> getSortedTableStats(DeviceService deviceService,
+ FlowRuleService flowService) {
+ SortedMap<Device, List<TableStatisticsEntry>> deviceTableStats = new TreeMap<>(Comparators.ELEMENT_COMPARATOR);
+ List<TableStatisticsEntry> tableStatsList;
+ Iterable<Device> devices = uri == null ? deviceService.getDevices() :
+ Collections.singletonList(deviceService.getDevice(DeviceId.deviceId(uri)));
+ for (Device d : devices) {
+ tableStatsList = newArrayList(flowService.getFlowTableStatistics(d.id()));
+ tableStatsList.sort((p1, p2) -> Integer.valueOf(p1.tableId()).compareTo(Integer.valueOf(p2.tableId())));
+ deviceTableStats.put(d, tableStatsList);
+ }
+ return deviceTableStats;
+ }
+
+}
diff --git a/framework/src/onos/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/framework/src/onos/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
index 459ffa96..28461e27 100644
--- a/framework/src/onos/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
+++ b/framework/src/onos/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -105,6 +105,18 @@
</completers>
</command>
<command>
+ <action class="org.onosproject.cli.net.DeviceControllersCommand"/>
+ <completers>
+ <ref component-id="deviceIdCompleter"/>
+ </completers>
+ </command>
+ <command>
+ <action class="org.onosproject.cli.net.DeviceSetControllersCommand"/>
+ <completers>
+ <ref component-id="deviceIdCompleter"/>
+ </completers>
+ </command>
+ <command>
<action class="org.onosproject.cli.net.DeviceRemoveCommand"/>
<completers>
<ref component-id="deviceIdCompleter"/>
@@ -222,6 +234,12 @@
</completers>
</command>
<command>
+ <action class="org.onosproject.cli.net.GetFlowStatistics"/>
+ <completers>
+ <ref component-id="deviceIdCompleter"/>
+ </completers>
+ </command>
+ <command>
<action class="org.onosproject.cli.net.AddMultiPointToSinglePointIntentCommand"/>
<completers>
<ref component-id="connectPointCompleter"/>
@@ -333,7 +351,19 @@
<command>
<action class="org.onosproject.cli.net.InterfacesListCommand"/>
</command>
-
+ <command>
+ <action class="org.onosproject.cli.net.InterfaceAddCommand"/>
+ <optional-completers>
+ <entry key="-c" value-ref="connectPointCompleter"/>
+ <entry key="--connectPoint" value-ref="connectPointCompleter"/>
+ </optional-completers>
+ </command>
+ <command>
+ <action class="org.onosproject.cli.net.InterfaceRemoveCommand"/>
+ <completers>
+ <ref component-id="connectPointCompleter"/>
+ </completers>
+ </command>
<command>
<action class="org.onosproject.cli.net.GroupsListCommand"/>
</command>
@@ -343,6 +373,10 @@
</command>
<command>
+ <action class="org.onosproject.cli.net.TableStatisticsCommand"/>
+ </command>
+
+ <command>
<action class="org.onosproject.cli.net.FlowsListCommand"/>
<completers>
<ref component-id="flowRuleStatusCompleter"/>
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cfg/ComponentConfigService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cfg/ComponentConfigService.java
index a311002f..408a8933 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/cfg/ComponentConfigService.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cfg/ComponentConfigService.java
@@ -63,6 +63,16 @@ public interface ComponentConfigService {
void setProperty(String componentName, String name, String value);
/**
+ * Presets the value of the specified configuration property, regardless
+ * of the component's state.
+ *
+ * @param componentName component name
+ * @param name property name
+ * @param value new property value
+ */
+ void preSetProperty(String componentName, String name, String value);
+
+ /**
* Clears the value of the specified configuration property thus making
* the property take on its default value.
*
@@ -72,3 +82,4 @@ public interface ComponentConfigService {
void unsetProperty(String componentName, String name);
}
+
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/AnnotationKeys.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/AnnotationKeys.java
index 4949bc40..8c5fb790 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/AnnotationKeys.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/AnnotationKeys.java
@@ -25,8 +25,10 @@ package org.onosproject.net;
*/
public final class AnnotationKeys {
+
// Prohibit instantiation
- private AnnotationKeys() {}
+ private AnnotationKeys() {
+ }
/**
* Annotation key for instance name.
@@ -125,12 +127,22 @@ public final class AnnotationKeys {
public static final String OWNER = "owner";
/**
+ * Annotation key for the channel id.
+ */
+ public static final String CHANNEL_ID = "channelId";
+
+ /**
+ * Annotation key for the management address.
+ */
+ public static final String MANAGEMENT_ADDRESS = "managementAddress";
+
+ /**
* Returns the value annotated object for the specified annotation key.
* The annotated value is expected to be String that can be parsed as double.
* If parsing fails, the returned value will be 1.0.
*
* @param annotated annotated object whose annotated value is obtained
- * @param key key of annotation
+ * @param key key of annotation
* @return double value of annotated object for the specified key
*/
public static double getAnnotatedValue(Annotated annotated, String key) {
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultDisjointPath.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultDisjointPath.java
new file mode 100644
index 00000000..4895964f
--- /dev/null
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultDisjointPath.java
@@ -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;
+
+import org.onosproject.net.provider.ProviderId;
+
+import java.util.List;
+import java.util.Objects;
+import static com.google.common.collect.ImmutableSet.of;
+
+/**
+ * Default implementation of a network disjoint path pair.
+ */
+public class DefaultDisjointPath extends DefaultPath implements DisjointPath {
+
+ private final DefaultPath path1;
+ private final DefaultPath path2;
+
+ boolean usingPath1 = true;
+
+ /**
+ * Creates a disjoint path pair from two default paths.
+ *
+ * @param providerId provider identity
+ * @param path1 primary path
+ * @param path2 backup path
+ */
+ public DefaultDisjointPath(ProviderId providerId, DefaultPath path1, DefaultPath path2) {
+ super(providerId, path1.links(), path1.cost() + path2.cost());
+ this.path1 = path1;
+ this.path2 = path2;
+ }
+
+ @Override
+ public List<Link> links() {
+ if (usingPath1) {
+ return path1.links();
+ } else {
+ return path2.links();
+ }
+ }
+
+ @Override
+ public double cost() {
+ if (usingPath1) {
+ return path1.cost();
+ }
+ return path2.cost();
+ }
+
+ @Override
+ public Path primary() {
+ return path1;
+ }
+
+ @Override
+ public Path backup() {
+ return path2;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(of(path1, path2), src(), dst());
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof DefaultDisjointPath) {
+ final DefaultDisjointPath other = (DefaultDisjointPath) obj;
+ return Objects.equals(this.path1, other.path1) && Objects.equals(this.path2, other.path2);
+ }
+ return false;
+ }
+
+ @Override
+ public boolean useBackup() {
+ if (path2 == null || path2.links() == null) {
+ return false;
+ }
+ usingPath1 = !usingPath1;
+ return true;
+ }
+}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/DisjointPath.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/DisjointPath.java
new file mode 100644
index 00000000..3d54cbfc
--- /dev/null
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/DisjointPath.java
@@ -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.net;
+
+
+/**
+ * Representation of a contiguous directed path in a network. Path comprises
+ * of a sequence of links, where adjacent links must share the same device,
+ * meaning that destination of the source of one link must coincide with the
+ * destination of the previous link.
+ */
+public interface DisjointPath extends Path {
+
+ /**
+ * Uses backup path.
+ *
+ * @return boolean corresponding to whether request to use
+ * backup was successful.
+ */
+ boolean useBackup();
+
+ /**
+ * Gets primary path.
+ *
+ * @return primary path
+ */
+ Path primary();
+
+ /**
+ * Gets secondary path.
+ *
+ * @return secondary path
+ */
+ Path backup();
+}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ControllerConfig.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ControllerConfig.java
index bb8a788b..cd7cb977 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ControllerConfig.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ControllerConfig.java
@@ -15,23 +15,27 @@
*/
package org.onosproject.net.behaviour;
+import org.onosproject.net.driver.HandlerBehaviour;
+
import java.util.List;
/**
* Device behaviour to obtain and set controllers at the device.
*/
-public interface ControllerConfig {
+public interface ControllerConfig extends HandlerBehaviour {
//TODO: add other controller parameters as needed.
/**
* Obtain the list of controller which are currently configured.
+ *
* @return a list for controller descriptions
*/
List<ControllerInfo> getControllers();
/**
* Set a list of controllers on a device.
+ *
* @param controllers a list of controller descriptions
*/
void setControllers(List<ControllerInfo> controllers);
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ControllerInfo.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ControllerInfo.java
index 9ff808a9..ded3b3ae 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ControllerInfo.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ControllerInfo.java
@@ -15,24 +15,112 @@
*/
package org.onosproject.net.behaviour;
+import com.google.common.base.Preconditions;
import org.onlab.packet.IpAddress;
+import java.util.Objects;
+
/**
* Represents information for a device to connect to a controller.
*/
public class ControllerInfo {
- public final IpAddress ip;
- public final int tcpPort;
+ private IpAddress ip = IpAddress.valueOf("0.0.0.0");
+ private int port = 6653;
+ private String type = "error";
/**
* Information for contacting the controller.
*
- * @param ip the ip address
- * @param tcpPort the tcp port
+ * @param ip the ip address
+ * @param port the tcp port
*/
- public ControllerInfo(IpAddress ip, int tcpPort) {
+ public ControllerInfo(IpAddress ip, int port, String type) {
this.ip = ip;
- this.tcpPort = tcpPort;
+ this.port = port;
+ this.type = type;
+ }
+
+ /**
+ * Information for contacting the controller, if some information
+ * is not contained in the target string because it's optional
+ * it's leaved as in the field declaration (default values).
+ *
+ * @param target column returned from ovsdb query
+ */
+ public ControllerInfo(String target) {
+ String[] data = target.split(":");
+ this.type = data[0];
+ Preconditions.checkArgument(!data[0].contains("unix"),
+ "Unable to create controller info " +
+ "from {} because it's based " +
+ "on unix sockets", target);
+ if (data[0].startsWith("p")) {
+ if (data.length >= 2) {
+ this.port = Integer.parseInt(data[1]);
+ }
+ if (data.length == 3) {
+ this.ip = IpAddress.valueOf(data[2]);
+ }
+ } else {
+ this.ip = IpAddress.valueOf(data[1]);
+ if (data.length == 3) {
+ this.port = Integer.parseInt(data[2]);
+ }
+ }
+ }
+
+ /**
+ * Exposes the ip address of the controller.
+ *
+ * @return IpAddress ip address
+ */
+ public IpAddress ip() {
+ return ip;
+ }
+
+ /**
+ * Exposes the tcp port of the controller.
+ *
+ * @return int tcp port
+ */
+ public int port() {
+ return port;
+ }
+
+ /**
+ * Exposes the type of the controller connection.
+ *
+ * @return String type
+ */
+ public String type() {
+ return type;
+ }
+
+ public String target() {
+ if (type.startsWith("p")) {
+ return type + ":" + port + ":" + ip;
+ } else {
+ return type + ":" + ip + ":" + port;
+ }
+ }
+
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(ip, port, type);
+ }
+
+ @Override
+ public boolean equals(Object toBeCompared) {
+ if (toBeCompared instanceof ControllerInfo) {
+ ControllerInfo controllerInfo = (ControllerInfo) toBeCompared;
+ if (controllerInfo.type().equals(this.type)
+ && controllerInfo.ip().equals(this.ip())
+ && controllerInfo.port() == this.port) {
+ return true;
+ }
+ }
+ return false;
}
}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/NetworkConfigService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/NetworkConfigService.java
index c1eed980..8eb69a45 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/NetworkConfigService.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/NetworkConfigService.java
@@ -41,27 +41,27 @@ public interface NetworkConfigService
/**
* Returns the subject factory with the specified key.
*
- * @param subjectKey subject class key
+ * @param subjectClassKey subject class key
* @return subject class
*/
- SubjectFactory getSubjectFactory(String subjectKey);
+ SubjectFactory getSubjectFactory(String subjectClassKey);
/**
* Returns the subject factory for the specified class.
*
* @param subjectClass subject class
- * @return subject class key
+ * @return subject class factory
*/
SubjectFactory getSubjectFactory(Class subjectClass);
/**
* Returns the configuration class with the specified key.
*
- * @param subjectKey subject class key
- * @param configKey subject class name
+ * @param subjectClassKey subject class key
+ * @param configKey subject class name
* @return subject class
*/
- Class<? extends Config> getConfigClass(String subjectKey, String configKey);
+ Class<? extends Config> getConfigClass(String subjectClassKey, String configKey);
/**
* Returns the set of subjects for which some configuration is available.
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/SubjectFactory.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/SubjectFactory.java
index cd2db344..f992d727 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/SubjectFactory.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/SubjectFactory.java
@@ -28,7 +28,7 @@ import com.google.common.annotations.Beta;
public abstract class SubjectFactory<S> {
private final Class<S> subjectClass;
- private final String subjectKey;
+ private final String subjectClassKey;
/**
* Creates a new configuration factory for the specified class of subjects
@@ -36,12 +36,12 @@ public abstract class SubjectFactory<S> {
* subject and configuration class keys are used merely as keys for use in
* composite JSON trees.
*
- * @param subjectClass subject class
- * @param subjectKey subject class key
+ * @param subjectClass subject class
+ * @param subjectClassKey subject class key
*/
- protected SubjectFactory(Class<S> subjectClass, String subjectKey) {
+ protected SubjectFactory(Class<S> subjectClass, String subjectClassKey) {
this.subjectClass = subjectClass;
- this.subjectKey = subjectKey;
+ this.subjectClassKey = subjectClassKey;
}
/**
@@ -60,8 +60,20 @@ public abstract class SubjectFactory<S> {
*
* @return configuration key
*/
- public String subjectKey() {
- return subjectKey;
+ public String subjectClassKey() {
+ return subjectClassKey;
+ }
+
+ /**
+ * Returns the unique key of the specified configuration subject.
+ * This is primarily aimed for use in composite JSON trees in external
+ * representations and has no bearing on the internal behaviours.
+ *
+ * @param subject specific subject
+ * @return subject key
+ */
+ public String subjectKey(S subject) {
+ return subject.toString();
}
/**
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/BasicDeviceConfig.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/BasicDeviceConfig.java
index fd8bfa3e..afde9a9e 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/BasicDeviceConfig.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/BasicDeviceConfig.java
@@ -25,6 +25,7 @@ public class BasicDeviceConfig extends BasicElementConfig<DeviceId> {
public static final String TYPE = "type";
public static final String DRIVER = "driver";
+ public static final String MANAGEMENT_ADDRESS = "managementAddress";
/**
* Returns the device type.
@@ -64,6 +65,25 @@ public class BasicDeviceConfig extends BasicElementConfig<DeviceId> {
return (BasicElementConfig) setOrClear(DRIVER, driverName);
}
+ /**
+ * Returns the device management ip (ip:port).
+ *
+ * @return device management address (ip:port) or null if not set
+ */
+ public String managementAddress() {
+ return get(MANAGEMENT_ADDRESS, null);
+ }
+
+ /**
+ * Sets the driver name.
+ *
+ * @param managementAddress new device management address (ip:port); null to clear
+ * @return self
+ */
+ public BasicElementConfig managementAddress(String managementAddress) {
+ return (BasicElementConfig) setOrClear(MANAGEMENT_ADDRESS, managementAddress);
+ }
+
// TODO: device port meta-data to be configured via BasicPortsConfig
// TODO: device credentials/keys
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/SubjectFactories.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/SubjectFactories.java
index 884f2e20..311566b3 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/SubjectFactories.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/SubjectFactories.java
@@ -43,6 +43,10 @@ public final class SubjectFactories {
public ApplicationId createSubject(String key) {
return coreService.registerApplication(key);
}
+ @Override
+ public String subjectKey(ApplicationId subject) {
+ return subject.name();
+ }
};
public static final SubjectFactory<DeviceId> DEVICE_SUBJECT_FACTORY =
@@ -59,6 +63,10 @@ public final class SubjectFactories {
public ConnectPoint createSubject(String key) {
return ConnectPoint.deviceConnectPoint(key);
}
+ @Override
+ public String subjectKey(ConnectPoint subject) {
+ return key(subject);
+ }
};
public static final SubjectFactory<HostId> HOST_SUBJECT_FACTORY =
@@ -78,6 +86,10 @@ public final class SubjectFactories {
return LinkKey.linkKey(ConnectPoint.deviceConnectPoint(cps[0]),
ConnectPoint.deviceConnectPoint(cps[1]));
}
+ @Override
+ public String subjectKey(LinkKey subject) {
+ return key(subject.src()) + "-" + key(subject.dst());
+ }
};
/**
@@ -90,4 +102,8 @@ public final class SubjectFactories {
coreService = service;
}
+ private static String key(ConnectPoint subject) {
+ return subject.deviceId() + "/" + subject.port();
+ }
+
}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTableStatisticsEntry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTableStatisticsEntry.java
new file mode 100644
index 00000000..929b285d
--- /dev/null
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTableStatisticsEntry.java
@@ -0,0 +1,89 @@
+/*
+ * 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;
+
+import org.onosproject.net.DeviceId;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Default implementation of table statistics entry interface.
+ */
+public final class DefaultTableStatisticsEntry implements TableStatisticsEntry {
+
+ private final DeviceId deviceId;
+ private final int tableId;
+ private final long activeFlowEntries;
+ private final long packetsLookedupCount;
+ private final long packetsMatchedCount;
+
+ /**
+ * Default table statistics constructor.
+ *
+ * @param deviceId device identifier
+ * @param tableId table identifier
+ * @param activeFlowEntries number of active flow entries in the table
+ * @param packetsLookedupCount number of packets looked up in table
+ * @param packetsMatchedCount number of packets that hit table
+ */
+ public DefaultTableStatisticsEntry(DeviceId deviceId,
+ int tableId,
+ long activeFlowEntries,
+ long packetsLookedupCount,
+ long packetsMatchedCount) {
+ this.deviceId = checkNotNull(deviceId);
+ this.tableId = tableId;
+ this.activeFlowEntries = activeFlowEntries;
+ this.packetsLookedupCount = packetsLookedupCount;
+ this.packetsMatchedCount = packetsMatchedCount;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("device: " + deviceId + ", ");
+
+ sb.append("tableId: " + this.tableId + ", ");
+ sb.append("activeEntries: " + this.activeFlowEntries + ", ");
+ sb.append("packetsLookedUp: " + this.packetsLookedupCount + ", ");
+ sb.append("packetsMatched: " + this.packetsMatchedCount);
+
+ return sb.toString();
+ }
+
+ @Override
+ public int tableId() {
+ return tableId;
+ }
+
+ @Override
+ public long activeFlowEntries() {
+ return activeFlowEntries;
+ }
+
+ @Override
+ public long packetsLookedup() {
+ return packetsLookedupCount;
+ }
+
+ @Override
+ public long packetsMatched() {
+ return packetsMatchedCount;
+ }
+
+ @Override
+ public DeviceId deviceId() {
+ return deviceId;
+ }
+}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficSelector.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficSelector.java
index f88c6bc3..4416456c 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficSelector.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficSelector.java
@@ -23,22 +23,26 @@ import org.onlab.packet.MacAddress;
import org.onlab.packet.MplsLabel;
import org.onlab.packet.TpPort;
import org.onlab.packet.VlanId;
-import org.onosproject.net.IndexedLambda;
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;
/**
* Default traffic selector implementation.
*/
public final class DefaultTrafficSelector implements TrafficSelector {
+ private static final Comparator<? super Criterion> TYPE_COMPARATOR =
+ (c1, c2) -> c1.type().compareTo(c2.type());
+
private final Set<Criterion> criteria;
private static final TrafficSelector EMPTY
@@ -50,7 +54,9 @@ public final class DefaultTrafficSelector implements TrafficSelector {
* @param criteria criteria
*/
private DefaultTrafficSelector(Set<Criterion> criteria) {
- this.criteria = ImmutableSet.copyOf(criteria);
+ TreeSet<Criterion> elements = new TreeSet<>(TYPE_COMPARATOR);
+ elements.addAll(criteria);
+ this.criteria = ImmutableSet.copyOf(elements);
}
@Override
@@ -345,18 +351,6 @@ public final class DefaultTrafficSelector implements TrafficSelector {
return add(Criteria.matchIPv6ExthdrFlags(exthdrFlags));
}
- @Deprecated
- @Override
- public Builder matchLambda(short lambda) {
- return add(Criteria.matchLambda(new IndexedLambda(lambda)));
- }
-
- @Deprecated
- @Override
- public Builder matchOpticalSignalType(short signalType) {
- return add(Criteria.matchOpticalSignalType(signalType));
- }
-
@Override
public TrafficSelector build() {
return new DefaultTrafficSelector(ImmutableSet.copyOf(selector.values()));
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java
index 5d18a9ad..a628725c 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java
@@ -31,7 +31,6 @@ import org.onosproject.net.flow.instructions.Instruction;
import org.onosproject.net.flow.instructions.Instructions;
import org.onosproject.net.meter.MeterId;
-import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -51,7 +50,7 @@ public final class DefaultTrafficTreatment implements TrafficTreatment {
private final boolean hasClear;
private static final DefaultTrafficTreatment EMPTY
- = new DefaultTrafficTreatment(Collections.emptyList());
+ = new DefaultTrafficTreatment(ImmutableList.of(Instructions.createNoAction()));
private final Instructions.MeterInstruction meter;
/**
@@ -212,8 +211,6 @@ public final class DefaultTrafficTreatment implements TrafficTreatment {
List<Instruction> current = immediate;
-
-
// Creates a new builder
private Builder() {
}
@@ -224,7 +221,10 @@ public final class DefaultTrafficTreatment implements TrafficTreatment {
treatment.deferred().forEach(i -> add(i));
immediate();
- treatment.immediate().forEach(i -> add(i));
+ treatment.immediate().stream()
+ // NOACTION will get re-added if there are no other actions
+ .filter(i -> i.type() != Instruction.Type.NOACTION)
+ .forEach(i -> add(i));
clear = treatment.clearedDeferred();
}
@@ -234,6 +234,7 @@ public final class DefaultTrafficTreatment implements TrafficTreatment {
switch (instruction.type()) {
case DROP:
+ case NOACTION:
case OUTPUT:
case GROUP:
case L0MODIFICATION:
@@ -250,6 +251,7 @@ public final class DefaultTrafficTreatment implements TrafficTreatment {
break;
case METER:
meter = (Instructions.MeterInstruction) instruction;
+ break;
default:
throw new IllegalArgumentException("Unknown instruction type: " +
instruction.type());
@@ -258,9 +260,23 @@ public final class DefaultTrafficTreatment implements TrafficTreatment {
return this;
}
+ /**
+ * Add a NOACTION when DROP instruction is explicitly specified.
+ *
+ * @return the traffic treatment builder
+ */
@Override
public Builder drop() {
- return add(Instructions.createDrop());
+ return add(Instructions.createNoAction());
+ }
+
+ /**
+ * Add a NOACTION when no instruction is specified.
+ *
+ * @return the traffic treatment builder
+ */
+ private Builder noAction() {
+ return add(Instructions.createNoAction());
}
@Override
@@ -380,11 +396,6 @@ public final class DefaultTrafficTreatment implements TrafficTreatment {
}
@Override
- public Builder transition(FlowRule.Type type) {
- return add(Instructions.transition(type.ordinal()));
- }
-
- @Override
public Builder transition(Integer tableId) {
return add(Instructions.transition(tableId));
}
@@ -463,14 +474,11 @@ public final class DefaultTrafficTreatment implements TrafficTreatment {
@Override
public TrafficTreatment build() {
- //Don't add DROP instruction by default when instruction
- //set is empty. This will be handled in DefaultSingleTablePipeline
- //driver.
-
- //if (deferred.size() == 0 && immediate.size() == 0
- // && table == null && !clear) {
- // drop();
- //}
+ if (deferred.size() == 0 && immediate.size() == 0
+ && table == null && !clear) {
+ immediate();
+ noAction();
+ }
return new DefaultTrafficTreatment(deferred, immediate, table, clear, meta, meter);
}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTypedFlowEntry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTypedFlowEntry.java
new file mode 100644
index 00000000..afceb14e
--- /dev/null
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTypedFlowEntry.java
@@ -0,0 +1,122 @@
+/*
+ * 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;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Default flow entry class with FlowLiveType value, IMMEDIATE_FLOW, SHORT_FLOW, MID_FLOW, LONG_FLOW.
+ */
+public class DefaultTypedFlowEntry extends DefaultFlowEntry
+ implements TypedStoredFlowEntry {
+ private FlowLiveType liveType;
+
+ /**
+ * Creates a typed flow entry from flow rule and its statistics, with default flow live type(IMMEDIATE_FLOW).
+ *
+ * @param rule the flow rule
+ * @param state the flow state
+ * @param life the flow duration since creation
+ * @param packets the flow packets count
+ * @param bytes the flow bytes count
+ *
+ */
+ public DefaultTypedFlowEntry(FlowRule rule, FlowEntryState state,
+ long life, long packets, long bytes) {
+ super(rule, state, life, packets, bytes);
+ this.liveType = FlowLiveType.IMMEDIATE_FLOW;
+ }
+
+ /**
+ * Creates a typed flow entry from flow rule, with default flow live type(IMMEDIATE_FLOW).
+ *
+ * @param rule the flow rule
+ *
+ */
+ public DefaultTypedFlowEntry(FlowRule rule) {
+ super(rule);
+ this.liveType = FlowLiveType.IMMEDIATE_FLOW;
+ }
+
+ /**
+ * Creates a typed flow entry from flow entry, with default flow live type(IMMEDIATE_FLOW).
+ *
+ * @param fe the flow entry
+ *
+ */
+ public DefaultTypedFlowEntry(FlowEntry fe) {
+ super(fe, fe.state(), fe.life(), fe.packets(), fe.bytes());
+ this.liveType = FlowLiveType.IMMEDIATE_FLOW;
+ }
+
+ /**
+ * Creates a typed flow entry from flow rule and flow live type.
+ *
+ * @param rule the flow rule
+ * @param liveType the flow live type
+ *
+ */
+ public DefaultTypedFlowEntry(FlowRule rule, FlowLiveType liveType) {
+ super(rule);
+ this.liveType = liveType;
+ }
+
+ /**
+ * Creates a typed flow entry from flow entry and flow live type.
+ *
+ * @param fe the flow rule
+ * @param liveType the flow live type
+ *
+ */
+ public DefaultTypedFlowEntry(FlowEntry fe, FlowLiveType liveType) {
+ super(fe, fe.state(), fe.life(), fe.packets(), fe.bytes());
+ this.liveType = liveType;
+ }
+
+ /**
+ * Creates a typed flow entry from flow rule, error code and flow live type.
+ *
+ * @param rule the flow rule
+ * @param errType the flow error type
+ * @param errCode the flow error code
+ * @param liveType the flow live type
+ *
+ */
+ public DefaultTypedFlowEntry(FlowRule rule, int errType, int errCode, FlowLiveType liveType) {
+ super(rule, errType, errCode);
+ this.liveType = liveType;
+ }
+
+ @Override
+ public FlowLiveType flowLiveType() {
+ return this.liveType;
+ }
+
+ @Override
+ public void setFlowLiveType(FlowLiveType liveType) {
+ this.liveType = liveType;
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(this)
+ .add("entry", super.toString())
+ .add("type", liveType)
+ .toString();
+ }
+}
+
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRule.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRule.java
index a487cbc4..35d45fbd 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRule.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRule.java
@@ -29,43 +29,6 @@ public interface FlowRule {
int MIN_PRIORITY = 0;
/**
- * The FlowRule type is used to determine in which table the flow rule needs
- * to be put for multi-table support switch. For single table switch,
- * Default is used.
- *
- * @deprecated in Cardinal Release
- */
- @Deprecated
- enum Type {
- /*
- * Default type - used in flow rule for single table switch NOTE: this
- * setting should not be used as Table 0 in a multi-table pipeline
- */
- DEFAULT,
- /* Used in flow entry for IP table */
- IP,
- /* Used in flow entry for MPLS table */
- MPLS,
- /* Used in flow entry for ACL table */
- ACL,
-
- /* VLAN-to-MPLS table */
- VLAN_MPLS,
-
- /* VLAN table */
- VLAN,
-
- /* Ethtype table */
- ETHER,
-
- /* Class of Service table */
- COS,
-
- /* Table 0 in a multi-table pipeline */
- FIRST,
- }
-
- /**
* Returns the ID of this flow.
*
* @return the flow ID
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleProviderService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleProviderService.java
index 8a36a921..aefa96b4 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleProviderService.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleProviderService.java
@@ -15,6 +15,8 @@
*/
package org.onosproject.net.flow;
+import java.util.List;
+
import org.onosproject.net.DeviceId;
import org.onosproject.net.provider.ProviderService;
@@ -41,6 +43,24 @@ public interface FlowRuleProviderService extends ProviderService<FlowRuleProvide
void pushFlowMetrics(DeviceId deviceId, Iterable<FlowEntry> flowEntries);
/**
+ * Pushes the collection of flow entries currently applied on the given
+ * device without flowMissing process.
+ *
+ * @param deviceId device identifier
+ * @param flowEntries collection of flow rules
+ */
+ void pushFlowMetricsWithoutFlowMissing(DeviceId deviceId, Iterable<FlowEntry> flowEntries);
+
+ /**
+ * Pushes the collection of table statistics entries currently extracted
+ * from the given device.
+ *
+ * @param deviceId device identifier
+ * @param tableStatsEntries collection of flow table statistics entries
+ */
+ void pushTableStatistics(DeviceId deviceId, List<TableStatisticsEntry> tableStatsEntries);
+
+ /**
* Indicates to the core that the requested batch operation has
* been completed.
*
@@ -48,5 +68,4 @@ public interface FlowRuleProviderService extends ProviderService<FlowRuleProvide
* @param operation the resulting outcome of the operation
*/
void batchOperationCompleted(long batchId, CompletedBatchOperation operation);
-
}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java
index d4f959c3..ee8d5a98 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java
@@ -104,4 +104,11 @@ public interface FlowRuleService
*/
void apply(FlowRuleOperations ops);
+ /**
+ * Returns the collection of flow table statistics of the specified device.
+ *
+ * @param deviceId device identifier
+ * @return collection of flow table statistics
+ */
+ Iterable<TableStatisticsEntry> getFlowTableStatistics(DeviceId deviceId);
}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleStore.java
index cece9893..d81c73c9 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleStore.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleStore.java
@@ -15,6 +15,8 @@
*/
package org.onosproject.net.flow;
+import java.util.List;
+
import org.onosproject.net.DeviceId;
import org.onosproject.store.Store;
@@ -93,4 +95,23 @@ public interface FlowRuleStore extends Store<FlowRuleBatchEvent, FlowRuleStoreDe
* @return flow_removed event, or null if nothing removed
*/
FlowRuleEvent removeFlowRule(FlowEntry rule);
+
+ /**
+ * Updates the flow table statistics of the specified device using
+ * the given statistics.
+ *
+ * @param deviceId device identifier
+ * @param tableStats list of table statistics
+ * @return ready to send event describing what occurred;
+ */
+ FlowRuleEvent updateTableStatistics(DeviceId deviceId,
+ List<TableStatisticsEntry> tableStats);
+
+ /**
+ * Returns the flow table statistics associated with a device.
+ *
+ * @param deviceId the device ID
+ * @return the flow table statistics
+ */
+ Iterable<TableStatisticsEntry> getTableStatistics(DeviceId deviceId);
}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TableStatisticsEntry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TableStatisticsEntry.java
new file mode 100644
index 00000000..563f31ce
--- /dev/null
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TableStatisticsEntry.java
@@ -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.flow;
+
+import org.onosproject.net.DeviceId;
+
+/**
+ * Interface for flow table statistics of a device.
+ */
+public interface TableStatisticsEntry {
+
+ /**
+ * Returns the device Id.
+ *
+ * @return device id
+ */
+ DeviceId deviceId();
+
+ /**
+ * Returns the table number.
+ *
+ * @return table number
+ */
+ int tableId();
+
+ /**
+ * Returns the number of active flow entries in this table.
+ *
+ * @return the number of active flow entries
+ */
+ long activeFlowEntries();
+
+ /**
+ * Returns the number of packets looked up in the table.
+ *
+ * @return the number of packets looked up in the table
+ */
+ long packetsLookedup();
+
+ /**
+ * Returns the number of packets that successfully matched in the table.
+ *
+ * @return the number of packets that successfully matched in the table
+ */
+ long packetsMatched();
+}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficSelector.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficSelector.java
index 534f6b9e..1286ffc1 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficSelector.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficSelector.java
@@ -386,30 +386,6 @@ public interface TrafficSelector {
Builder matchIPv6ExthdrFlags(short exthdrFlags);
/**
- * Matches an optical signal ID or lambda.
- *
- * @param lambda lambda
- * @return a selection builder
- * @deprecated in Cardinal Release.
- * Use {@link #add(Criterion)} with an instance created
- * by {@link org.onosproject.net.flow.criteria.Criteria#matchLambda(org.onosproject.net.Lambda)}.
- */
- @Deprecated
- Builder matchLambda(short lambda);
-
- /**
- * Matches an optical Signal Type.
- *
- * @param signalType signalType
- * @return a selection builder
- * @deprecated in Cardinal Release.
- * Use {@link #add(Criterion)}} with an instance created
- * by {@link org.onosproject.net.flow.criteria.Criteria#matchOchSignalType(org.onosproject.net.OchSignalType)}.
- */
- @Deprecated
- Builder matchOpticalSignalType(short signalType);
-
- /**
* Builds an immutable traffic selector.
*
* @return traffic selector
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java
index 1ce669c2..33753afa 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java
@@ -269,16 +269,6 @@ public interface TrafficTreatment {
Builder meter(MeterId meterId);
/**
- * Sets the next table type to transition to.
- *
- * @param type the table type
- * @return a treatement builder
- * @deprecated in Cardinal Release
- */
- @Deprecated
- Builder transition(FlowRule.Type type);
-
- /**
* Sets the next table id to transition to.
*
* @param tableId the table table
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TypedStoredFlowEntry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TypedStoredFlowEntry.java
new file mode 100644
index 00000000..a93dc071
--- /dev/null
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TypedStoredFlowEntry.java
@@ -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.net.flow;
+
+/**
+ * Represents a flow live type for a given flow entry.
+ */
+public interface TypedStoredFlowEntry extends StoredFlowEntry {
+ enum FlowLiveType {
+ /**
+ * Indicates that this rule has been submitted for addition immediately.
+ * Not necessarily collecting flow stats.
+ */
+ IMMEDIATE_FLOW,
+
+ /**
+ * Indicates that this rule has been submitted for a short time.
+ * Necessarily collecting flow stats every calAndPollInterval.
+ */
+ SHORT_FLOW,
+
+ /**
+ * Indicates that this rule has been submitted for a mid time.
+ * Necessarily collecting flow stats every midPollInterval.
+ */
+ MID_FLOW,
+
+ /**
+ * Indicates that this rule has been submitted for a long time.
+ * Necessarily collecting flow stats every longPollInterval.
+ */
+ LONG_FLOW,
+
+ /**
+ * Indicates that this rule has been submitted for UNKNOWN or ERROR.
+ * Not necessarily collecting flow stats.
+ */
+ UNKNOWN_FLOW
+ }
+
+ /**
+ * Gets the flow live type for this entry.
+ */
+ FlowLiveType flowLiveType();
+
+ /**
+ * Sets the new flow live type for this entry.
+ * @param liveType new flow live type.
+ */
+ void setFlowLiveType(FlowLiveType liveType);
+}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/Criteria.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/Criteria.java
index 0252cfbc..7e1d43a5 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/Criteria.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/Criteria.java
@@ -461,18 +461,6 @@ public final class Criteria {
}
/**
- * Creates a match on lambda field using the specified value.
- *
- * @param lambda lambda to match on (16 bits unsigned integer)
- * @return match criterion
- * @deprecated in Cardinal Release. Use {@link #matchLambda(Lambda)} instead.
- */
- @Deprecated
- public static Criterion matchLambda(int lambda) {
- return new LambdaCriterion(lambda, Type.OCH_SIGID);
- }
-
- /**
* Creates a match on lambda using the specified value.
*
* @param lambda lambda
@@ -489,18 +477,6 @@ public final class Criteria {
}
/**
- * Creates a match on optical signal type using the specified value.
- *
- * @param sigType optical signal type (8 bits unsigned integer)
- * @return match criterion
- * @deprecated in Cardinal Release
- */
- @Deprecated
- public static Criterion matchOpticalSignalType(short sigType) {
- return new OpticalSignalTypeCriterion(sigType, Type.OCH_SIGTYPE);
- }
-
- /**
* Create a match on OCh (Optical Channel) signal type.
*
* @param signalType OCh signal type
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instruction.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instruction.java
index 6f2cac6b..d01ea298 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instruction.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instruction.java
@@ -27,9 +27,18 @@ public interface Instruction {
/**
* Signifies that the traffic should be dropped.
*/
+ @Deprecated
DROP,
/**
+ * Signifies that the traffic requires no action.
+ *
+ * In OF10, the behavior of NOACTION is DROP.
+ * In OF13, the behavior depends on current Action Set.
+ */
+ NOACTION,
+
+ /**
* Signifies that the traffic should be output to a port.
*/
OUTPUT,
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java
index c5358a29..c9f10685 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java
@@ -68,11 +68,21 @@ public final class Instructions {
*
* @return drop instruction
*/
+ @Deprecated
public static DropInstruction createDrop() {
return new DropInstruction();
}
/**
+ * Creates a no action instruction.
+ *
+ * @return no action instruction
+ */
+ public static NoActionInstruction createNoAction() {
+ return new NoActionInstruction();
+ }
+
+ /**
* Creates a group instruction.
*
* @param groupId Group Id
@@ -89,19 +99,6 @@ public final class Instructions {
}
/**
- * Creates a l0 modification.
- *
- * @param lambda the lambda to modify to
- * @return a l0 modification
- * @deprecated in Cardinal Release. Use {@link #modL0Lambda(Lambda)} instead.
- */
- @Deprecated
- public static L0ModificationInstruction modL0Lambda(short lambda) {
- checkNotNull(lambda, "L0 lambda cannot be null");
- return new ModLambdaInstruction(L0SubType.LAMBDA, lambda);
- }
-
- /**
* Creates an L0 modification with the specified OCh signal.
*
* @param lambda OCh signal
@@ -303,21 +300,6 @@ public final class Instructions {
*
* @param etherType Ethernet type to set
* @return a L2 modification.
- * @deprecated in Cardinal Release
- */
- @Deprecated
- public static Instruction popMpls(int etherType) {
- checkNotNull(etherType, "Ethernet type cannot be null");
- return new L2ModificationInstruction.PushHeaderInstructions(
- L2ModificationInstruction.L2SubType.MPLS_POP, new EthType(etherType));
- }
-
-
- /**
- * Creates a pop MPLS header instruction with a particular ethertype.
- *
- * @param etherType Ethernet type to set
- * @return a L2 modification.
*/
public static Instruction popMpls(EthType etherType) {
checkNotNull(etherType, "Ethernet type cannot be null");
@@ -478,6 +460,7 @@ public final class Instructions {
/**
* Drop instruction.
*/
+ @Deprecated
public static final class DropInstruction implements Instruction {
private DropInstruction() {}
@@ -510,6 +493,40 @@ public final class Instructions {
}
/**
+ * No Action instruction.
+ */
+ public static final class NoActionInstruction implements Instruction {
+
+ private NoActionInstruction() {}
+
+ @Override
+ public Type type() {
+ return Type.NOACTION;
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(type().toString()).toString();
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(type().ordinal());
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof NoActionInstruction) {
+ return true;
+ }
+ return false;
+ }
+ }
+
+ /**
* Output Instruction.
*/
public static final class OutputInstruction implements Instruction {
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostProviderService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostProviderService.java
index f7b7c499..068663bd 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostProviderService.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostProviderService.java
@@ -15,6 +15,7 @@
*/
package org.onosproject.net.host;
+import org.onlab.packet.IpAddress;
import org.onosproject.net.HostId;
import org.onosproject.net.provider.ProviderService;
@@ -29,6 +30,7 @@ public interface HostProviderService extends ProviderService<HostProvider> {
*
* @param hostId id of the host that been detected
* @param hostDescription description of host and its location
+ * @deprecated in Drake release
*/
@Deprecated
default void hostDetected(HostId hostId, HostDescription hostDescription) {
@@ -52,4 +54,11 @@ public interface HostProviderService extends ProviderService<HostProvider> {
*/
void hostVanished(HostId hostId);
+ /**
+ * Notifies the core when a host is no longer detected on a network.
+ *
+ * @param hostId id of the host that vanished
+ */
+ void removeIpFromHost(HostId hostId, IpAddress ipAddress);
+
}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostStore.java
index 5894fe92..918ced45 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostStore.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostStore.java
@@ -55,6 +55,15 @@ public interface HostStore extends Store<HostEvent, HostStoreDelegate> {
HostEvent removeHost(HostId hostId);
/**
+ * Removes the specified ip from the host entry.
+ *
+ * @param hostId host identification
+ * @param ipAddress ipAddress to be removed
+ * @return remove event or null if host was not found
+ */
+ HostEvent removeIp(HostId hostId, IpAddress ipAddress);
+
+ /**
* Returns the number of hosts in the store.
*
* @return host count
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/FlowRuleIntent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/FlowRuleIntent.java
index 0646a003..2a2d7c78 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/FlowRuleIntent.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/FlowRuleIntent.java
@@ -23,7 +23,6 @@ import org.onosproject.net.NetworkResource;
import org.onosproject.net.flow.FlowRule;
import java.util.Collection;
-import java.util.Collections;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -38,18 +37,6 @@ public class FlowRuleIntent extends Intent {
private final Collection<FlowRule> flowRules;
/**
- * Creates an flow rule intent with the specified flow rules to be set.
- *
- * @param appId application id
- * @param flowRules flow rules to be set.
- * @deprecated in Cardinal Release
- */
- @Deprecated
- public FlowRuleIntent(ApplicationId appId, List<FlowRule> flowRules) {
- this(appId, null, flowRules, Collections.emptyList());
- }
-
- /**
* Creates a flow rule intent with the specified flow rules and resources.
*
* @param appId application id
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/McastEvent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/McastEvent.java
new file mode 100644
index 00000000..979194c3
--- /dev/null
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/McastEvent.java
@@ -0,0 +1,118 @@
+/*
+ * 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.mcast;
+
+import com.google.common.annotations.Beta;
+import org.onosproject.event.AbstractEvent;
+import org.onosproject.net.ConnectPoint;
+
+import java.util.Optional;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * An entity representing a multicast event. Event either add or remove
+ * sinks or sources.
+ */
+@Beta
+public class McastEvent extends AbstractEvent<McastEvent.Type, McastRoute> {
+
+ private final Optional<ConnectPoint> sink;
+ private final Optional<ConnectPoint> source;
+
+ public enum Type {
+ /**
+ * A new mcast route has been added.
+ */
+ ROUTE_ADDED,
+
+ /**
+ * A mcast route has been removed.
+ */
+ ROUTE_REMOVED,
+
+ /**
+ * A source for a mcast route (ie. the subject) has been added.
+ */
+ SOURCE_ADDED,
+
+ /**
+ * A sink for a mcast route (ie. the subject) has been added.
+ */
+ SINK_ADDED,
+
+ /**
+ * A source for a mcast route (ie. the subject) has been removed.
+ */
+ SINK_REMOVED
+ }
+
+ private McastEvent(McastEvent.Type type, McastRoute subject) {
+ super(type, subject);
+ sink = Optional.empty();
+ source = Optional.empty();
+ }
+
+ private McastEvent(McastEvent.Type type, McastRoute subject, long time) {
+ super(type, subject, time);
+ sink = Optional.empty();
+ source = Optional.empty();
+ }
+
+ public McastEvent(McastEvent.Type type, McastRoute subject,
+ ConnectPoint sink,
+ ConnectPoint source) {
+ super(type, subject);
+ this.sink = Optional.ofNullable(sink);
+ this.source = Optional.ofNullable(source);
+ }
+
+ public McastEvent(McastEvent.Type type, McastRoute subject, long time,
+ ConnectPoint sink,
+ ConnectPoint source) {
+ super(type, subject, time);
+ this.sink = Optional.ofNullable(sink);
+ this.source = Optional.ofNullable(source);
+ }
+
+ /**
+ * The sink which has been removed or added. The field may not be set
+ * if the sink has not been detected yet or has been removed.
+ *
+ * @return an optional connect point
+ */
+ public Optional<ConnectPoint> sink() {
+ return sink;
+ }
+
+ /**
+ * The source which has been removed or added.
+
+ * @return an optional connect point
+ */
+ public Optional<ConnectPoint> source() {
+ return source;
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(this)
+ .add("type", type())
+ .add("route", subject())
+ .add("source", source)
+ .add("sinks", sink).toString();
+ }
+}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/McastListener.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/McastListener.java
new file mode 100644
index 00000000..06449b99
--- /dev/null
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/McastListener.java
@@ -0,0 +1,26 @@
+/*
+ * 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.mcast;
+
+import com.google.common.annotations.Beta;
+import org.onosproject.event.EventListener;
+
+/**
+ * A listener interface for multicast events.
+ */
+@Beta
+public interface McastListener extends EventListener<McastEvent> {
+}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/McastRoute.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/McastRoute.java
new file mode 100644
index 00000000..ff1292bf
--- /dev/null
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/McastRoute.java
@@ -0,0 +1,117 @@
+/*
+ * 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.mcast;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Objects;
+import org.onlab.packet.IpPrefix;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * An entity representing a multicast route consisting of a source
+ * and a multicast group address.
+ */
+@Beta
+public class McastRoute {
+
+ public enum Type {
+ /**
+ * Route originates from PIM.
+ */
+ PIM,
+
+ /**
+ * Route originates from IGMP.
+ */
+ IGMP,
+
+ /**
+ * Route originates from other config (ie. REST, CLI).
+ */
+ STATIC
+ }
+
+ private final IpPrefix source;
+ private final IpPrefix group;
+ private final Type type;
+
+ public McastRoute(IpPrefix source, IpPrefix group, Type type) {
+ checkNotNull(source, "Multicast route must have a source");
+ checkNotNull(group, "Multicast route must specify a group address");
+ checkNotNull(type, "Must indicate what type of route");
+ this.source = source;
+ this.group = group;
+ this.type = type;
+ }
+
+ /**
+ * Fetches the source address of this route.
+ *
+ * @return an ip address
+ */
+ public IpPrefix source() {
+ return source;
+ }
+
+ /**
+ * Fetches the group address of this route.
+ *
+ * @return an ip address
+ */
+ public IpPrefix group() {
+ return group;
+ }
+
+ /**
+ * Obtains how this route was created.
+ * @return a type of route
+
+ */
+ public Type type() {
+ return type;
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(this)
+ .add("source", source)
+ .add("group", group)
+ .add("origin", type)
+ .toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ McastRoute that = (McastRoute) o;
+ return Objects.equal(source, that.source) &&
+ Objects.equal(group, that.group) &&
+ Objects.equal(type, that.type);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(source, group, type);
+ }
+
+}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/MulticastRouteService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/MulticastRouteService.java
new file mode 100644
index 00000000..56e87c55
--- /dev/null
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/MulticastRouteService.java
@@ -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.net.mcast;
+
+import com.google.common.annotations.Beta;
+import org.onosproject.net.ConnectPoint;
+
+import java.util.List;
+
+/**
+ * A service interface for maintaining multicast information.
+ */
+@Beta
+public interface MulticastRouteService {
+
+ /**
+ * Adds a route to the information base.
+ *
+ * @param route a multicast route
+ */
+ void add(McastRoute route);
+
+ /**
+ * Removes a route from the information base.
+ *
+ * @param route a multicast route
+ */
+ void remove(McastRoute route);
+
+ /**
+ * Adds a source connection to the route from where the
+ * data stream is originating.
+ *
+ * @param route the multicast route
+ * @param connectPoint a source connect point
+ */
+ void addSource(McastRoute route, ConnectPoint connectPoint);
+
+ /**
+ * Adds a sink to the route to which a data stream should be
+ * sent to.
+ *
+ * @param route a multicast route
+ * @param connectPoint a sink connect point
+ */
+ void addSink(McastRoute route, ConnectPoint connectPoint);
+
+ /**
+ * Removes a sink from the route.
+ *
+ * @param route the multicast route
+ * @param connectPoint a sink connect point
+ */
+ void removeSink(McastRoute route, ConnectPoint connectPoint);
+
+ /**
+ * Find the data source association for this multicast route.
+ *
+ * @param route a multicast route
+ * @return a connect point
+ */
+ ConnectPoint fetchSource(McastRoute route);
+
+ /**
+ * Find the list of sinks for this route.
+ *
+ * @param route a multicast route
+ * @return a list of connect points
+ */
+ List<ConnectPoint> fetchSinks(McastRoute route);
+}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/package-info.java
new file mode 100644
index 00000000..e8dcc7b8
--- /dev/null
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/package-info.java
@@ -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.
+ */
+
+/**
+ * External model entities of the multicast RIB.
+ */
+package org.onosproject.net.mcast; \ No newline at end of file
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/DefaultMeterRequest.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/DefaultMeterRequest.java
index 94cada47..51394c30 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/DefaultMeterRequest.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/DefaultMeterRequest.java
@@ -43,7 +43,8 @@ public final class DefaultMeterRequest implements MeterRequest {
private DefaultMeterRequest(DeviceId deviceId, ApplicationId appId,
Meter.Unit unit, boolean burst,
- Collection<Band> bands, MeterContext context, Type op) {
+ Collection<Band> bands, MeterContext context,
+ Type op) {
this.deviceId = deviceId;
this.appId = appId;
this.unit = unit;
@@ -58,6 +59,7 @@ public final class DefaultMeterRequest implements MeterRequest {
return deviceId;
}
+
@Override
public ApplicationId appId() {
return appId;
@@ -107,6 +109,7 @@ public final class DefaultMeterRequest implements MeterRequest {
private Collection<Band> bands;
private DeviceId deviceId;
private MeterContext context;
+ private Optional<MeterId> desiredId = Optional.empty();
@Override
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterKey.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterKey.java
new file mode 100644
index 00000000..5bc01b02
--- /dev/null
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterKey.java
@@ -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.net.meter;
+
+import com.google.common.base.Objects;
+import org.onosproject.net.DeviceId;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * A meter key represents a meter uniquely.
+ */
+public final class MeterKey {
+
+ private final DeviceId deviceId;
+ private final MeterId id;
+
+ private MeterKey(DeviceId deviceId, MeterId id) {
+ this.deviceId = deviceId;
+ this.id = id;
+ }
+
+ public DeviceId deviceId() {
+ return deviceId;
+ }
+
+ public MeterId meterId() {
+ return id;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ MeterKey meterKey = (MeterKey) o;
+ return Objects.equal(deviceId, meterKey.deviceId) &&
+ Objects.equal(id, meterKey.id);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(deviceId, id);
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(this)
+ .add("deviceId", deviceId)
+ .add("meterId", id).toString();
+ }
+
+ public static MeterKey key(DeviceId deviceId, MeterId id) {
+ return new MeterKey(deviceId, id);
+ }
+}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterService.java
index bdc90eb7..2e07cb67 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterService.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterService.java
@@ -16,6 +16,7 @@
package org.onosproject.net.meter;
import org.onosproject.event.ListenerService;
+import org.onosproject.net.DeviceId;
import java.util.Collection;
@@ -46,10 +47,11 @@ public interface MeterService
/**
* Fetch the meter by the meter id.
*
+ * @param deviceId a device id
* @param id a meter id
* @return a meter
*/
- Meter getMeter(MeterId id);
+ Meter getMeter(DeviceId deviceId, MeterId id);
/**
* Fetches all the meters.
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterStore.java
index 5112a4a3..f429e95a 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterStore.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterStore.java
@@ -57,12 +57,12 @@ public interface MeterStore extends Store<MeterEvent, MeterStoreDelegate> {
void updateMeterState(Meter meter);
/**
- * Obtains a meter matching the given meter id.
+ * Obtains a meter matching the given meter key.
*
- * @param meterId a meter id
+ * @param key a meter key
* @return a meter
*/
- Meter getMeter(MeterId meterId);
+ Meter getMeter(MeterKey key);
/**
* Returns all meters stored in the store.
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceService.java
index 618042a3..82d84743 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceService.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceService.java
@@ -125,6 +125,15 @@ public interface ResourceService {
boolean release(ResourceConsumer consumer);
/**
+ * Returns resource allocation of the specified resource.
+ *
+ * @param resource resource to check the allocation
+ * @return allocation information enclosed by Optional.
+ * If the resource is not allocated, the return value is empty.
+ */
+ Optional<ResourceAllocation> getResourceAllocation(ResourcePath resource);
+
+ /**
* Returns allocated resources being as children of the specified parent and being the specified resource type.
*
* @param parent parent resource path
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketProcessorEntry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketProcessorEntry.java
new file mode 100644
index 00000000..40386fb7
--- /dev/null
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketProcessorEntry.java
@@ -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.net.packet;
+
+/**
+ * Packet processor entry tracking the processor, its priority and
+ * time consumption.
+ */
+public interface PacketProcessorEntry {
+
+ /**
+ * Returns the packet processor.
+ *
+ * @return packet processor
+ */
+ PacketProcessor processor();
+
+ /**
+ * Returns the packet processor priority.
+ *
+ * @return processor priority
+ */
+ int priority();
+
+ /**
+ * Returns the number of invocations.
+ *
+ * @return number of invocations
+ */
+ long invocations();
+
+ /**
+ * Returns the total time, in nanoseconds, spent processing packets.
+ *
+ * @return total time in nanos
+ */
+ long totalNanos();
+
+ /**
+ * Returns the average time, in nanoseconds, spent processing packets.
+ *
+ * @return average time in nanos
+ */
+ long averageNanos();
+}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketService.java
index 98f4d8e0..2e7a1b91 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketService.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketService.java
@@ -20,7 +20,6 @@ import org.onosproject.core.ApplicationId;
import org.onosproject.net.flow.TrafficSelector;
import java.util.List;
-import java.util.Map;
/**
* Service for intercepting data plane packets and for emitting synthetic
@@ -52,13 +51,12 @@ public interface PacketService {
void removeProcessor(PacketProcessor processor);
/**
- * Returns priority bindings of all registered packet processors.
+ * Returns priority bindings of all registered packet processor entries.
*
- * @return list of existing packet processors
+ * @return list of existing packet processor entries
*/
@Beta
- // TODO: Consider returning list of PacketProcessorEntry with processor, priority and stats
- Map<Integer, PacketProcessor> getProcessors();
+ List<PacketProcessorEntry> getProcessors();
/**
* Requests that packets matching the given selector are punted from the
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketStore.java
index 97f7cb55..d83fc9a2 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketStore.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketStore.java
@@ -37,17 +37,15 @@ public interface PacketStore extends Store<PacketEvent, PacketStoreDelegate> {
* Requests intercept of packets that match the given selector.
*
* @param request a packet request
- * @return true if the first time the given selector was requested
*/
- boolean requestPackets(PacketRequest request);
+ void requestPackets(PacketRequest request);
/**
* Cancels intercept of packets that match the given selector.
*
* @param request a packet request
- * @return true if there is no other application requesting the given selector
*/
- boolean cancelPackets(PacketRequest request);
+ void cancelPackets(PacketRequest request);
/**
* Obtains all existing requests in the system.
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketStoreDelegate.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketStoreDelegate.java
index bf5c3cc0..2e59b19d 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketStoreDelegate.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketStoreDelegate.java
@@ -21,4 +21,20 @@ import org.onosproject.store.StoreDelegate;
* Packet store delegate abstraction.
*/
public interface PacketStoreDelegate extends StoreDelegate<PacketEvent> {
+
+ /**
+ * Requests that packets matching to following request be collected
+ * from all switches.
+ *
+ * @param request packet request
+ */
+ void requestPackets(PacketRequest request);
+
+ /**
+ * Requests that packets matching to following request no longer be
+ * collected from any switches.
+ *
+ * @param request packet request
+ */
+ void cancelPackets(PacketRequest request);
}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/device/IntentSetMultimap.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/device/IntentSetMultimap.java
new file mode 100644
index 00000000..67c539df
--- /dev/null
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/device/IntentSetMultimap.java
@@ -0,0 +1,47 @@
+/*
+ * 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.resource.device;
+
+import org.onosproject.net.intent.IntentId;
+
+import java.util.Set;
+
+public interface IntentSetMultimap {
+
+ /**
+ * Allocates the mapping between the given intents.
+ *
+ * @param keyIntentId key intent ID
+ * @param valIntentId value intent ID
+ * @return true if mapping was successful, false otherwise
+ */
+ boolean allocateMapping(IntentId keyIntentId, IntentId valIntentId);
+
+ /**
+ * Returns the set of intents mapped to a lower intent.
+ *
+ * @param intentId intent ID
+ * @return set of intent IDs
+ */
+ Set<IntentId> getMapping(IntentId intentId);
+
+ /**
+ * Releases the mapping of the given intent.
+ *
+ * @param intentId intent ID
+ */
+ void releaseMapping(IntentId intentId);
+}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/BandwidthResourceRequest.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/BandwidthResourceRequest.java
index 91cc3d19..e07309cb 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/BandwidthResourceRequest.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/BandwidthResourceRequest.java
@@ -64,7 +64,7 @@ public class BandwidthResourceRequest implements ResourceRequest {
if (obj == null || getClass() != obj.getClass()) {
return false;
}
- final BandwidthResourceAllocation other = (BandwidthResourceAllocation) obj;
+ final BandwidthResourceRequest other = (BandwidthResourceRequest) obj;
return Objects.equals(this.bandwidth, other.bandwidth());
}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/FlowStatisticService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/FlowStatisticService.java
new file mode 100644
index 00000000..f59670bc
--- /dev/null
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/FlowStatisticService.java
@@ -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.net.statistic;
+
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.Device;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.TypedStoredFlowEntry;
+import org.onosproject.net.flow.instructions.Instruction;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Service for obtaining individual flow statistic information about device and link in the system.
+ * Basic statistics are obtained from the StatisticService
+ */
+public interface FlowStatisticService {
+
+ /**
+ * Obtain the summary load list for the device with the given link.
+ *
+ * @param device the Device to query.
+ * @return map of summary flow entry load
+ */
+ Map<ConnectPoint, SummaryFlowEntryWithLoad> loadSummary(Device device);
+
+ /**
+ * Obtain the summary load for the device with the given link or port.
+ *
+ * @param device the Device to query.
+ * @param pNumber the port number to query.
+ * @return summary flow entry load
+ */
+ SummaryFlowEntryWithLoad loadSummary(Device device, PortNumber pNumber);
+
+ /**
+ * Obtain the set of the flow type and load list for the device with the given link.
+ *
+ * @param device the Device to query.
+ * @param liveType the FlowLiveType to filter, null means no filtering .
+ * @param instType the InstructionType to filter, null means no filtering.
+ * @return map of flow entry load
+ */
+ Map<ConnectPoint, List<TypedFlowEntryWithLoad>> loadAllByType(Device device,
+ TypedStoredFlowEntry.FlowLiveType liveType,
+ Instruction.Type instType);
+
+ /**
+ * Obtain the flow type and load list for the device with the given link or port.
+ *
+ * @param device the Device to query.
+ * @param pNumber the port number of the Device to query
+ * @param liveType the FlowLiveType to filter, null means no filtering .
+ * @param instType the InstructionType to filter, null means no filtering.
+ * @return list of flow entry load
+ */
+ List<TypedFlowEntryWithLoad> loadAllByType(Device device, PortNumber pNumber,
+ TypedStoredFlowEntry.FlowLiveType liveType,
+ Instruction.Type instType);
+
+ /**
+ * Obtain the set of the flow type and load topn list for the device with the given link.
+ *
+ * @param device the Device to query.
+ * @param liveType the FlowLiveType to filter, null means no filtering .
+ * @param instType the InstructionType to filter, null means no filtering.
+ * @param topn the top number to filter, null means no filtering.
+ * @return map of flow entry load
+ */
+ Map<ConnectPoint, List<TypedFlowEntryWithLoad>> loadTopnByType(Device device,
+ TypedStoredFlowEntry.FlowLiveType liveType,
+ Instruction.Type instType,
+ int topn);
+
+ /**
+ * Obtain the flow type and load topn list for the device with the given link or port.
+ *
+ * @param device the Device to query.
+ * @param pNumber the port number of the Device to query
+ * @param liveType the FlowLiveType to filter, null means no filtering .
+ * @param instType the InstructionType to filter, null means no filtering.
+ * @return list of flow entry load
+ */
+ List<TypedFlowEntryWithLoad> loadTopnByType(Device device, PortNumber pNumber,
+ TypedStoredFlowEntry.FlowLiveType liveType,
+ Instruction.Type instType,
+ int topn);
+}
+
+
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/FlowStatisticStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/FlowStatisticStore.java
new file mode 100644
index 00000000..3c2aa89b
--- /dev/null
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/FlowStatisticStore.java
@@ -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.net.statistic;
+
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.flow.FlowEntry;
+import org.onosproject.net.flow.FlowRule;
+
+import java.util.Set;
+
+/**
+ * Flow Store to house the computed statistics.
+ */
+public interface FlowStatisticStore {
+ /**
+ * Remove entries associated with this rule.
+ *
+ * @param rule {@link org.onosproject.net.flow.FlowRule}
+ */
+ void removeFlowStatistic(FlowRule rule);
+
+ /**
+ * Adds a flow stats observation for a flow rule. The previous flow will be removed.
+ *
+ * @param rule a {@link org.onosproject.net.flow.FlowEntry}
+ */
+ void addFlowStatistic(FlowEntry rule);
+
+ /**
+ * Updates a stats observation for a flow rule. The old flow stats will be moved to previous stats.
+ *
+ * @param rule a {@link org.onosproject.net.flow.FlowEntry}
+ */
+ void updateFlowStatistic(FlowEntry rule);
+
+ /**
+ * Fetches the current observed flow stats values.
+ *
+ * @param connectPoint the port to fetch information for
+ * @return set of current flow rules
+ */
+ Set<FlowEntry> getCurrentFlowStatistic(ConnectPoint connectPoint);
+
+ /**
+ * Fetches the current observed flow stats values.
+ *
+ * @param connectPoint the port to fetch information for
+ * @return set of current values
+ */
+ Set<FlowEntry> getPreviousFlowStatistic(ConnectPoint connectPoint);
+}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/SummaryFlowEntryWithLoad.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/SummaryFlowEntryWithLoad.java
new file mode 100644
index 00000000..60da636a
--- /dev/null
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/SummaryFlowEntryWithLoad.java
@@ -0,0 +1,143 @@
+/*
+ * 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.statistic;
+
+import org.onosproject.net.ConnectPoint;
+
+/**
+ * Summary Load classified by flow live type.
+ */
+public class SummaryFlowEntryWithLoad {
+ private ConnectPoint cp;
+ private Load totalLoad;
+ private Load immediateLoad;
+ private Load shortLoad;
+ private Load midLoad;
+ private Load longLoad;
+ private Load unknownLoad;
+
+ /**
+ * Creates a new summary flow entry having load for the given connect point and total load.
+ *
+ * @param cp connect point
+ * @param totalLoad total load
+ */
+ public SummaryFlowEntryWithLoad(ConnectPoint cp, Load totalLoad) {
+ this.cp = cp;
+ this.totalLoad = totalLoad;
+ this.immediateLoad = new DefaultLoad();
+ this.shortLoad = new DefaultLoad();
+ this.midLoad = new DefaultLoad();
+ this.longLoad = new DefaultLoad();
+ this.unknownLoad = new DefaultLoad();
+ }
+
+ /**
+ * Creates a new summary flow entry having load for the given connect point
+ * and total, immediate, short, mid, and long load.
+ *
+ * @param cp connect point
+ * @param totalLoad total load
+ * @param immediateLoad immediate load
+ * @param shortLoad short load
+ * @param midLoad mid load
+ * @param longLoad long load
+ */
+ public SummaryFlowEntryWithLoad(ConnectPoint cp,
+ Load totalLoad, Load immediateLoad, Load shortLoad, Load midLoad, Load longLoad) {
+ this.cp = cp;
+ this.totalLoad = totalLoad;
+ this.immediateLoad = immediateLoad;
+ this.shortLoad = shortLoad;
+ this.midLoad = midLoad;
+ this.longLoad = longLoad;
+ this.unknownLoad = new DefaultLoad();
+ }
+
+ /**
+ * Creates a new summary flow entry having load for the given connect point
+ * and total, immediate, short, mid, long, and unknown load.
+ *
+ * @param cp connect point
+ * @param totalLoad total load
+ * @param immediateLoad immediate load
+ * @param shortLoad short load
+ * @param midLoad mid load
+ * @param longLoad long load
+ * @param unknownLoad long load
+ */
+ public SummaryFlowEntryWithLoad(ConnectPoint cp,
+ Load totalLoad, Load immediateLoad,
+ Load shortLoad, Load midLoad, Load longLoad, Load unknownLoad) {
+ this.cp = cp;
+ this.totalLoad = totalLoad;
+ this.immediateLoad = immediateLoad;
+ this.shortLoad = shortLoad;
+ this.midLoad = midLoad;
+ this.longLoad = longLoad;
+ this.unknownLoad = unknownLoad;
+ }
+
+ /**
+ * Returns connect point.
+ */
+ public ConnectPoint connectPoint() {
+ return cp;
+ }
+
+ /**
+ * Returns total load of connect point.
+ */
+ public Load totalLoad() {
+ return totalLoad;
+ }
+
+ /**
+ * Returns immediate load of connect point.
+ */
+ public Load immediateLoad() {
+ return immediateLoad;
+ }
+
+ /**
+ * Returns short load of connect point.
+ */
+ public Load shortLoad() {
+ return shortLoad;
+ }
+
+ /**
+ * Returns mid load of connect point.
+ */
+ public Load midLoad() {
+ return midLoad;
+ }
+
+ /**
+ * Returns long load of connect point.
+ */
+ public Load longLoad() {
+ return longLoad;
+ }
+
+ /**
+ * Returns unknown load of connect point.
+ */
+ public Load unknownLoad() {
+ return unknownLoad;
+ }
+}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/TypedFlowEntryWithLoad.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/TypedFlowEntryWithLoad.java
new file mode 100644
index 00000000..3e2dbdf8
--- /dev/null
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/TypedFlowEntryWithLoad.java
@@ -0,0 +1,143 @@
+/*
+ * 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.statistic;
+
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.flow.FlowEntry;
+import org.onosproject.net.flow.TypedStoredFlowEntry;
+import org.onosproject.net.flow.DefaultTypedFlowEntry;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Load of flow entry of flow live type.
+ */
+public class TypedFlowEntryWithLoad {
+ private ConnectPoint cp;
+ private TypedStoredFlowEntry tfe;
+ private Load load;
+
+ //TODO: make this variables class, and share with NewAdaptivceFlowStatsCollector class
+ private static final int CAL_AND_POLL_INTERVAL = 5; // means SHORT_POLL_INTERVAL
+ private static final int MID_POLL_INTERVAL = 10;
+ private static final int LONG_POLL_INTERVAL = 15;
+
+
+ public TypedFlowEntryWithLoad(ConnectPoint cp, TypedStoredFlowEntry tfe, Load load) {
+ this.cp = cp;
+ this.tfe = tfe;
+ this.load = load;
+ }
+
+ public TypedFlowEntryWithLoad(ConnectPoint cp, TypedStoredFlowEntry tfe) {
+ this.cp = cp;
+ this.tfe = tfe;
+ this.load = new DefaultLoad(tfe.bytes(), 0, typedPollInterval(tfe));
+ }
+
+ public TypedFlowEntryWithLoad(ConnectPoint cp, FlowEntry fe) {
+ this.cp = cp;
+ this.tfe = newTypedStoredFlowEntry(fe);
+ this.load = new DefaultLoad(fe.bytes(), 0, typedPollInterval(this.tfe));
+ }
+
+ public ConnectPoint connectPoint() {
+ return cp;
+ }
+ public TypedStoredFlowEntry typedStoredFlowEntry() {
+ return tfe;
+ }
+ public Load load() {
+ return load;
+ }
+ public void setLoad(Load load) {
+ this.load = load;
+ }
+
+ /**
+ * Returns short polling interval.
+ */
+ public static int shortPollInterval() {
+ return CAL_AND_POLL_INTERVAL;
+ }
+
+ /**
+ * Returns mid polling interval.
+ */
+ public static int midPollInterval() {
+ return MID_POLL_INTERVAL;
+ }
+
+ /**
+ * Returns long polling interval.
+ */
+ public static int longPollInterval() {
+ return LONG_POLL_INTERVAL;
+ }
+
+ /**
+ * Returns average polling interval.
+ */
+ public static int avgPollInterval() {
+ return (CAL_AND_POLL_INTERVAL + MID_POLL_INTERVAL + LONG_POLL_INTERVAL) / 3;
+ }
+
+ /**
+ * Returns current typed flow entry's polling interval.
+ *
+ * @param tfe typed flow entry
+ */
+ public static long typedPollInterval(TypedStoredFlowEntry tfe) {
+ checkNotNull(tfe, "TypedStoredFlowEntry cannot be null");
+
+ switch (tfe.flowLiveType()) {
+ case LONG_FLOW:
+ return LONG_POLL_INTERVAL;
+ case MID_FLOW:
+ return MID_POLL_INTERVAL;
+ case SHORT_FLOW:
+ case IMMEDIATE_FLOW:
+ default:
+ return CAL_AND_POLL_INTERVAL;
+ }
+ }
+
+ /**
+ * Creates a new typed flow entry with the given flow entry fe.
+ *
+ * @param fe flow entry
+ */
+ public static TypedStoredFlowEntry newTypedStoredFlowEntry(FlowEntry fe) {
+ if (fe == null) {
+ return null;
+ }
+
+ long life = fe.life();
+
+ if (life >= LONG_POLL_INTERVAL) {
+ return new DefaultTypedFlowEntry(fe, TypedStoredFlowEntry.FlowLiveType.LONG_FLOW);
+ } else if (life >= MID_POLL_INTERVAL) {
+ return new DefaultTypedFlowEntry(fe, TypedStoredFlowEntry.FlowLiveType.MID_FLOW);
+ } else if (life >= CAL_AND_POLL_INTERVAL) {
+ return new DefaultTypedFlowEntry(fe, TypedStoredFlowEntry.FlowLiveType.SHORT_FLOW);
+ } else if (life >= 0) {
+ return new DefaultTypedFlowEntry(fe, TypedStoredFlowEntry.FlowLiveType.IMMEDIATE_FLOW);
+ } else { // life < 0
+ return new DefaultTypedFlowEntry(fe, TypedStoredFlowEntry.FlowLiveType.UNKNOWN_FLOW);
+ }
+ }
+}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/DefaultGraphDescription.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/DefaultGraphDescription.java
index f1e20dac..965c05d4 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/DefaultGraphDescription.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/DefaultGraphDescription.java
@@ -50,23 +50,6 @@ public class DefaultGraphDescription extends AbstractDescription
* and process the topology graph.
*
* @param nanos time in nanos of when the topology description was created
- * @param devices collection of infrastructure devices
- * @param links collection of infrastructure links
- * @param annotations optional key/value annotations map
- * @deprecated in Cardinal Release
- */
- @Deprecated
- public DefaultGraphDescription(long nanos, Iterable<Device> devices,
- Iterable<Link> links,
- SparseAnnotations... annotations) {
- this(nanos, System.currentTimeMillis(), devices, links, annotations);
- }
-
- /**
- * Creates a minimal topology graph description to allow core to construct
- * and process the topology graph.
- *
- * @param nanos time in nanos of when the topology description was created
* @param millis time in millis of when the topology description was created
* @param devices collection of infrastructure devices
* @param links collection of infrastructure links
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/PathService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/PathService.java
index be8c7cfc..0bd4d75d 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/PathService.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/PathService.java
@@ -15,9 +15,12 @@
*/
package org.onosproject.net.topology;
+import org.onosproject.net.DisjointPath;
import org.onosproject.net.ElementId;
+import org.onosproject.net.Link;
import org.onosproject.net.Path;
+import java.util.Map;
import java.util.Set;
/**
@@ -41,11 +44,58 @@ public interface PathService {
* edge-weight entity, between the specified source and destination
* network elements.
*
- * @param src source element
- * @param dst destination element
+ * @param src source element
+ * @param dst destination element
* @param weight edge-weight entity
* @return set of all shortest paths between the two element
*/
Set<Path> getPaths(ElementId src, ElementId dst, LinkWeight weight);
+ /**
+ * Returns the set of all disjoint shortest path pairs, precomputed in terms of hop-count,
+ * between the specified source and destination devices.
+ *
+ * @param src source device
+ * @param dst destination device
+ * @return set of all shortest paths between the two devices
+ */
+ Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst);
+
+ /**
+ * Returns the set of all disjoint shortest path pairs, computed using the supplied
+ * edge-weight entity, between the specified source and destination devices.
+ *
+ * @param src source device
+ * @param dst destination device
+ * @param weight edge-weight entity
+ * @return set of all shortest paths between the two devices
+ */
+ Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst,
+ LinkWeight weight);
+
+ /**
+ * Returns the set of all disjoint shortest path pairs, precomputed in terms of hop-count,
+ * between the specified source and destination devices.
+ *
+ * @param src source device
+ * @param dst destination device
+ * @param riskProfile map of edges to risk profiles
+ * @return set of all shortest paths between the two devices
+ */
+ Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst,
+ Map<Link, Object> riskProfile);
+
+ /**
+ * Returns the set of all disjoint shortest path pairs, precomputed in terms of hop-count,
+ * between the specified source and destination devices.
+ *
+ * @param src source device
+ * @param dst destination device
+ * @param weight edge-weight entity
+ * @param riskProfile map of edges to risk profiles
+ * @return set of all shortest paths between the two devices
+ */
+ Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst,
+ LinkWeight weight, Map<Link, Object> riskProfile);
+
}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyService.java
index 41eac2c4..466e4f9b 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyService.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyService.java
@@ -18,16 +18,18 @@ package org.onosproject.net.topology;
import org.onosproject.event.ListenerService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
+import org.onosproject.net.DisjointPath;
import org.onosproject.net.Link;
import org.onosproject.net.Path;
+import java.util.Map;
import java.util.Set;
/**
* Service for providing network topology information.
*/
public interface TopologyService
- extends ListenerService<TopologyEvent, TopologyListener> {
+ extends ListenerService<TopologyEvent, TopologyListener> {
/**
* Returns the current topology descriptor.
@@ -72,8 +74,8 @@ public interface TopologyService
/**
* Returns the set of devices that belong to the specified cluster.
*
- * @param topology topology descriptor
- * @param cluster topology cluster
+ * @param topology topology descriptor
+ * @param cluster topology cluster
* @return set of cluster devices
*/
Set<DeviceId> getClusterDevices(Topology topology, TopologyCluster cluster);
@@ -81,8 +83,8 @@ public interface TopologyService
/**
* Returns the set of links that form the specified cluster.
*
- * @param topology topology descriptor
- * @param cluster topology cluster
+ * @param topology topology descriptor
+ * @param cluster topology cluster
* @return set of cluster links
*/
Set<Link> getClusterLinks(Topology topology, TopologyCluster cluster);
@@ -112,6 +114,57 @@ public interface TopologyService
LinkWeight weight);
/**
+ * Returns the set of all disjoint shortest path pairs, precomputed in terms of hop-count,
+ * between the specified source and destination devices.
+ *
+ * @param topology topology descriptor
+ * @param src source device
+ * @param dst destination device
+ * @return set of all shortest paths between the two devices
+ */
+ Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst);
+
+ /**
+ * Returns the set of all disjoint shortest path pairs, computed using the supplied
+ * edge-weight entity, between the specified source and destination devices.
+ *
+ * @param topology topology descriptor
+ * @param src source device
+ * @param dst destination device
+ * @param weight edge-weight entity
+ * @return set of all shortest paths between the two devices
+ */
+ Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst,
+ LinkWeight weight);
+
+ /**
+ * Returns the set of all disjoint shortest path pairs, precomputed in terms of hop-count,
+ * between the specified source and destination devices.
+ *
+ * @param topology topology descriptor
+ * @param src source device
+ * @param dst destination device
+ * @param riskProfile map of edges to risk profiles
+ * @return set of all shortest paths between the two devices
+ */
+ Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst,
+ Map<Link, Object> riskProfile);
+
+ /**
+ * Returns the set of all disjoint shortest path pairs, precomputed in terms of hop-count,
+ * between the specified source and destination devices.
+ *
+ * @param topology topology descriptor
+ * @param src source device
+ * @param dst destination device
+ * @param weight edge-weight entity
+ * @param riskProfile map of edges to risk profiles
+ * @return set of all shortest paths between the two devices
+ */
+ Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst,
+ LinkWeight weight, Map<Link, Object> riskProfile);
+
+ /**
* Indicates whether the specified connection point is part of the network
* infrastructure or part of network edge.
*
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyStore.java
index 983e616e..039a205c 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyStore.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyStore.java
@@ -20,11 +20,13 @@ import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Link;
import org.onosproject.net.Path;
+import org.onosproject.net.DisjointPath;
import org.onosproject.net.provider.ProviderId;
import org.onosproject.store.Store;
import java.util.List;
import java.util.Set;
+import java.util.Map;
/**
* Manages inventory of topology snapshots; not intended for direct use.
@@ -112,6 +114,59 @@ public interface TopologyStore extends Store<TopologyEvent, TopologyStoreDelegat
LinkWeight weight);
/**
+ * Computes and returns the set of disjoint shortest path pairs
+ * between src and dst.
+ *
+ * @param topology topology descriptor
+ * @param src source device
+ * @param dst destination device
+ * @param weight link weight function
+ * @return set of shortest paths
+ */
+ Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst,
+ LinkWeight weight);
+
+ /**
+ * Computes and returns the set of disjoint shortest path pairs
+ * between src and dst.
+ *
+ * @param topology topology descriptor
+ * @param src source device
+ * @param dst destination device
+ * @return set of shortest paths
+ */
+ Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst);
+
+ /**
+ * Computes and returns the set of SRLG disjoint shortest path pairs between source
+ * and dst, given a mapping of edges to SRLG risk groups.
+ *
+ * @param topology topology descriptor
+ * @param src source device
+ * @param dst destination device
+ * @param weight link weight function
+ * @param riskProfile map of edges to objects. Edges that map to the same object will
+ * be treated as if they were in the same risk group.
+ * @return set of shortest paths
+ */
+ Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst,
+ LinkWeight weight, Map<Link, Object> riskProfile);
+
+ /**
+ * Returns the set of pre-computed SRLG shortest paths between src and dest.
+ *
+ * @param topology topology descriptor
+ * @param src source device
+ * @param dst destination device
+ * @param riskProfile map of edges to objects. Edges that map to the same object will
+ * be treated as if they were in the same risk group.
+ * @return set of shortest paths
+ */
+ Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst,
+ Map<Link, Object> riskProfile);
+
+
+ /**
* Indicates whether the given connect point is part of the network fabric.
*
* @param topology topology descriptor
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AsyncAtomicCounter.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AsyncAtomicCounter.java
index a879cc59..c0df7134 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AsyncAtomicCounter.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AsyncAtomicCounter.java
@@ -58,4 +58,21 @@ public interface AsyncAtomicCounter {
* @return current value
*/
CompletableFuture<Long> get();
+
+
+ /**
+ * Atomically sets the given value to the current value.
+ *
+ * @return future void
+ */
+ CompletableFuture<Void> set(long value);
+
+ /**
+ * Atomically sets the given counter to the updated value if the current value is the expected value, otherwise
+ * no change occurs.
+ * @param expectedValue the expected current value of the counter
+ * @param updateValue the new value to be set
+ * @return true if the update occurred and the expected value was equal to the current value, false otherwise
+ */
+ CompletableFuture<Boolean> compareAndSet(long expectedValue, long updateValue);
}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AtomicCounter.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AtomicCounter.java
index f620e082..3c9e02c8 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AtomicCounter.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AtomicCounter.java
@@ -51,6 +51,22 @@ public interface AtomicCounter {
long addAndGet(long delta);
/**
+ * Atomically sets the given value to the current value.
+ *
+ * @param value the value to set
+ */
+ void set(long value);
+
+ /**
+ * Atomically sets the given counter to the updated value if the current value is the expected value, otherwise
+ * no change occurs.
+ * @param expectedValue the expected current value of the counter
+ * @param updateValue the new value to be set
+ * @return true if the update occurred and the expected value was equal to the current value, false otherwise
+ */
+ boolean compareAndSet(long expectedValue, long updateValue);
+
+ /**
* Returns the current value of the counter without modifying it.
*
* @return current value
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/MutexExecutionService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/MutexExecutionService.java
new file mode 100644
index 00000000..d05f3b91
--- /dev/null
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/MutexExecutionService.java
@@ -0,0 +1,34 @@
+/*
+ * 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.service;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executor;
+
+/**
+ * Service for mutually exclusive job execution.
+ */
+public interface MutexExecutionService {
+
+ /**
+ * Runs the specified task in a mutually exclusive fashion.
+ * @param task task to run
+ * @param exclusionPath path on which different instances synchronize
+ * @param executor executor to use for running the task
+ * @return future that is completed when the task execution completes.
+ */
+ CompletableFuture<Void> execute(MutexTask task, String exclusionPath, Executor executor);
+} \ No newline at end of file
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/MutexTask.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/MutexTask.java
new file mode 100644
index 00000000..ba5ee47f
--- /dev/null
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/MutexTask.java
@@ -0,0 +1,39 @@
+/*
+ * 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.service;
+
+/**
+ * The MutexTask interface should be implemented by any class whose
+ * instances distributed across controllers are intended to be executed
+ * in a mutually exclusive fashion.
+ */
+public interface MutexTask {
+
+ /**
+ * Begins the execution of a mutually exclusive task.
+ * The start method will be called once the "lock" is acquired.
+ * After the start method returns the lock is released and some other
+ * instance can take over execution.
+ */
+ void start();
+
+ /**
+ * This method will be called when exclusivity of task execution
+ * can no longer be guaranteed. The implementation should take necessary steps
+ * to halt task execution in order to ensure correctness.
+ */
+ void stop();
+}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/NumberFormatter.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/NumberFormatter.java
new file mode 100644
index 00000000..76f42466
--- /dev/null
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/NumberFormatter.java
@@ -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.ui.table.cell;
+
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+
+/**
+ * Formats number using the specified format string".
+ */
+public final class NumberFormatter extends AbstractCellFormatter {
+
+ private final NumberFormat format;
+
+ /**
+ * Creates a formatter using a default decimal format.
+ */
+ public NumberFormatter() {
+ this(new DecimalFormat("#,##0.00000"));
+ }
+
+ /**
+ * Creates a formatter using the specified format.
+ *
+ * @param format number format
+ */
+ public NumberFormatter(NumberFormat format) {
+ this.format = format;
+ }
+
+ @Override
+ protected String nonNullFormat(Object value) {
+ return format.format(value);
+ }
+
+}
diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/cfg/ComponentConfigAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/cfg/ComponentConfigAdapter.java
index a1abd188..0fccef81 100644
--- a/framework/src/onos/core/api/src/test/java/org/onosproject/cfg/ComponentConfigAdapter.java
+++ b/framework/src/onos/core/api/src/test/java/org/onosproject/cfg/ComponentConfigAdapter.java
@@ -17,10 +17,13 @@ package org.onosproject.cfg;
import java.util.Set;
+import com.google.common.collect.ImmutableSet;
+
/**
* Adapter for testing against component configuration service.
*/
public class ComponentConfigAdapter implements ComponentConfigService {
+
@Override
public Set<String> getComponentNames() {
return null;
@@ -38,7 +41,7 @@ public class ComponentConfigAdapter implements ComponentConfigService {
@Override
public Set<ConfigProperty> getProperties(String componentName) {
- return null;
+ return ImmutableSet.of();
}
@Override
@@ -47,6 +50,10 @@ public class ComponentConfigAdapter implements ComponentConfigService {
}
@Override
+ public void preSetProperty(String componentName, String name, String value) {
+ }
+
+ @Override
public void unsetProperty(String componentName, String name) {
}
diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/behaviour/ControllerInfoTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/behaviour/ControllerInfoTest.java
new file mode 100644
index 00000000..ece7f199
--- /dev/null
+++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/behaviour/ControllerInfoTest.java
@@ -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.net.behaviour;
+
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.onlab.packet.IpAddress;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.Assert.*;
+
+/**
+ * Test for ControllerInfo class.
+ */
+public class ControllerInfoTest {
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void tcpSslFormat() {
+ String target = "tcp:192.168.1.1:6653";
+ ControllerInfo controllerInfo = new ControllerInfo(target);
+ assertEquals("wrong type", controllerInfo.type(), "tcp");
+ assertEquals("wrong ip", controllerInfo.ip(), IpAddress.valueOf("192.168.1.1"));
+ assertEquals("wrong port", controllerInfo.port(), 6653);
+
+ }
+
+ @Test
+ public void ptcpPsslFormat() {
+ String target = "ptcp:6653:192.168.1.1";
+ ControllerInfo controllerInfo = new ControllerInfo(target);
+ assertEquals("wrong type", controllerInfo.type(), "ptcp");
+ assertEquals("wrong ip", controllerInfo.ip(), IpAddress.valueOf("192.168.1.1"));
+ assertEquals("wrong port", controllerInfo.port(), 6653);
+
+ }
+
+ @Test
+ public void unixFormat() {
+ String target = "unix:file";
+ thrown.expect(IllegalArgumentException.class);
+ ControllerInfo controllerInfo = new ControllerInfo(target);
+ assertTrue("wrong type", controllerInfo.type().contains("unix"));
+ assertNull("wrong ip", controllerInfo.ip());
+ assertEquals("wrong port", controllerInfo.port(), -1);
+
+ }
+
+ @Test
+ public void defaultValues() {
+ String target = "tcp:192.168.1.1";
+ ControllerInfo controllerInfo = new ControllerInfo(target);
+ assertEquals("wrong type", controllerInfo.type(), "tcp");
+ assertEquals("wrong ip", controllerInfo.ip(), IpAddress.valueOf("192.168.1.1"));
+ assertEquals("wrong port", controllerInfo.port(), 6653);
+ String target1 = "ptcp:5000:";
+ ControllerInfo controllerInfo2 = new ControllerInfo(target1);
+ assertEquals("wrong type", controllerInfo2.type(), "ptcp");
+ assertEquals("wrong ip", controllerInfo2.ip(), IpAddress.valueOf("0.0.0.0"));
+ assertEquals("wrong port", controllerInfo2.port(), 5000);
+ String target2 = "ptcp:";
+ ControllerInfo controllerInfo3 = new ControllerInfo(target2);
+ assertEquals("wrong type", controllerInfo3.type(), "ptcp");
+ assertEquals("wrong ip", controllerInfo3.ip(), IpAddress.valueOf("0.0.0.0"));
+ assertEquals("wrong port", controllerInfo3.port(), 6653);
+ }
+
+
+ @Test
+ public void testEquals() {
+ String target1 = "ptcp:6653:192.168.1.1";
+ ControllerInfo controllerInfo1 = new ControllerInfo(target1);
+ String target2 = "ptcp:6653:192.168.1.1";
+ ControllerInfo controllerInfo2 = new ControllerInfo(target2);
+ assertTrue("wrong equals method", controllerInfo1.equals(controllerInfo2));
+ }
+
+ @Test
+ public void testListEquals() {
+ String target1 = "ptcp:6653:192.168.1.1";
+ ControllerInfo controllerInfo1 = new ControllerInfo(target1);
+ String target2 = "ptcp:6653:192.168.1.1";
+ ControllerInfo controllerInfo2 = new ControllerInfo(target2);
+ String target3 = "tcp:192.168.1.1:6653";
+ ControllerInfo controllerInfo3 = new ControllerInfo(target3);
+ String target4 = "tcp:192.168.1.1:6653";
+ ControllerInfo controllerInfo4 = new ControllerInfo(target4);
+ List<ControllerInfo> list1 = new ArrayList<>(Arrays.asList(controllerInfo1, controllerInfo3));
+ List<ControllerInfo> list2 = new ArrayList<>(Arrays.asList(controllerInfo2, controllerInfo4));
+ assertTrue("wrong equals list method", list1.equals(list2));
+ }
+}
diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/config/NetworkConfigServiceAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/config/NetworkConfigServiceAdapter.java
index b70d14e8..73072583 100644
--- a/framework/src/onos/core/api/src/test/java/org/onosproject/net/config/NetworkConfigServiceAdapter.java
+++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/config/NetworkConfigServiceAdapter.java
@@ -29,7 +29,7 @@ public class NetworkConfigServiceAdapter implements NetworkConfigService {
}
@Override
- public SubjectFactory getSubjectFactory(String subjectKey) {
+ public SubjectFactory getSubjectFactory(String subjectClassKey) {
return null;
}
@@ -39,7 +39,7 @@ public class NetworkConfigServiceAdapter implements NetworkConfigService {
}
@Override
- public Class<? extends Config> getConfigClass(String subjectKey, String configKey) {
+ public Class<? extends Config> getConfigClass(String subjectClassKey, String configKey) {
return null;
}
diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/DefaultTrafficSelectorTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/DefaultTrafficSelectorTest.java
index b871397b..10c5a637 100644
--- a/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/DefaultTrafficSelectorTest.java
+++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/DefaultTrafficSelectorTest.java
@@ -267,29 +267,5 @@ public class DefaultTrafficSelectorTest {
selector = DefaultTrafficSelector.builder()
.add(Criteria.matchLambda(new IndexedLambda(shortValue))).build();
assertThat(selector, hasCriterionWithType(Type.OCH_SIGID));
-
- selector = DefaultTrafficSelector.builder()
- .add(Criteria.matchOpticalSignalType(shortValue)).build();
- assertThat(selector, hasCriterionWithType(Type.OCH_SIGTYPE));
- }
-
- /**
- * Tests the traffic selector builder.
- */
- @Test
- public void testTrafficSelectorBuilder() {
- TrafficSelector selector;
- final short shortValue = 33;
-
- final TrafficSelector baseSelector = DefaultTrafficSelector.builder()
- .add(Criteria.matchLambda(new IndexedLambda(shortValue))).build();
- selector = DefaultTrafficSelector.builder(baseSelector)
- .build();
- assertThat(selector, hasCriterionWithType(Type.OCH_SIGID));
-
- final Criterion criterion = Criteria.matchLambda(shortValue);
- selector = DefaultTrafficSelector.builder()
- .add(criterion).build();
- assertThat(selector, hasCriterionWithType(Type.OCH_SIGID));
}
}
diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/FlowRuleServiceAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/FlowRuleServiceAdapter.java
index c7b78791..56e59118 100644
--- a/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/FlowRuleServiceAdapter.java
+++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/FlowRuleServiceAdapter.java
@@ -35,17 +35,14 @@ public class FlowRuleServiceAdapter implements FlowRuleService {
@Override
public void applyFlowRules(FlowRule... flowRules) {
-
}
@Override
public void removeFlowRules(FlowRule... flowRules) {
-
}
@Override
public void removeFlowRulesById(ApplicationId appId) {
-
}
@Override
@@ -60,16 +57,18 @@ public class FlowRuleServiceAdapter implements FlowRuleService {
@Override
public void apply(FlowRuleOperations ops) {
-
}
@Override
public void addListener(FlowRuleListener listener) {
-
}
@Override
public void removeListener(FlowRuleListener listener) {
+ }
+ @Override
+ public Iterable<TableStatisticsEntry> getFlowTableStatistics(DeviceId deviceId) {
+ return null;
}
}
diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/criteria/CriteriaTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/criteria/CriteriaTest.java
index ee294f6f..95d605c6 100644
--- a/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/criteria/CriteriaTest.java
+++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/criteria/CriteriaTest.java
@@ -225,12 +225,6 @@ public class CriteriaTest {
Criterion matchIpv6ExthdrFlags2 =
Criteria.matchIPv6ExthdrFlags(ipv6ExthdrFlags2);
- int lambda1 = 1;
- int lambda2 = 2;
- Criterion matchLambda1 = Criteria.matchLambda(lambda1);
- Criterion sameAsMatchLambda1 = Criteria.matchLambda(lambda1);
- Criterion matchLambda2 = Criteria.matchLambda(lambda2);
-
Criterion matchOchSignalType1 = Criteria.matchOchSignalType(OchSignalType.FIXED_GRID);
Criterion sameAsMatchOchSignalType1 = Criteria.matchOchSignalType(OchSignalType.FIXED_GRID);
Criterion matchOchSignalType2 = Criteria.matchOchSignalType(OchSignalType.FLEX_GRID);
@@ -239,12 +233,6 @@ public class CriteriaTest {
Criterion sameAsMatchIndexedLambda1 = Criteria.matchLambda(Lambda.indexedLambda(1));
Criterion matchIndexedLambda2 = Criteria.matchLambda(Lambda.indexedLambda(2));
- short signalLambda1 = 1;
- short signalLambda2 = 2;
- Criterion matchSignalLambda1 = Criteria.matchOpticalSignalType(signalLambda1);
- Criterion sameAsMatchSignalLambda1 = Criteria.matchOpticalSignalType(signalLambda1);
- Criterion matchSignalLambda2 = Criteria.matchOpticalSignalType(signalLambda2);
-
Criterion matchOchSignal1 =
Criteria.matchLambda(Lambda.ochSignal(GridType.DWDM, ChannelSpacing.CHL_100GHZ, 4, 8));
Criterion sameAsMatchOchSignal1 =
@@ -306,7 +294,6 @@ public class CriteriaTest {
assertThatClassIsImmutable(MplsCriterion.class);
assertThatClassIsImmutable(IPv6ExthdrFlagsCriterion.class);
assertThatClassIsImmutable(LambdaCriterion.class);
- assertThatClassIsImmutable(OpticalSignalTypeCriterion.class);
}
// PortCriterion class
@@ -1057,32 +1044,6 @@ public class CriteriaTest {
.testEquals();
}
- // LambdaCriterion class
-
- /**
- * Test the matchLambda method.
- */
- @Test
- public void testMatchLambdaMethod() {
- Criterion matchLambda = Criteria.matchLambda(lambda1);
- LambdaCriterion lambdaCriterion =
- checkAndConvert(matchLambda,
- Criterion.Type.OCH_SIGID,
- LambdaCriterion.class);
- assertThat(lambdaCriterion.lambda(), is(equalTo(lambda1)));
- }
-
- /**
- * Test the equals() method of the LambdaCriterion class.
- */
- @Test
- public void testLambdaCriterionEquals() {
- new EqualsTester()
- .addEqualityGroup(matchLambda1, sameAsMatchLambda1)
- .addEqualityGroup(matchLambda2)
- .testEquals();
- }
-
@Test
public void testIndexedLambdaCriterionEquals() {
new EqualsTester()
@@ -1109,30 +1070,4 @@ public class CriteriaTest {
.addEqualityGroup(matchOchSignalType2)
.testEquals();
}
-
- // OpticalSignalTypeCriterion class
-
- /**
- * Test the matchOpticalSignalType method.
- */
- @Test
- public void testMatchOpticalSignalTypeMethod() {
- Criterion matchLambda = Criteria.matchOpticalSignalType(signalLambda1);
- OpticalSignalTypeCriterion opticalSignalTypeCriterion =
- checkAndConvert(matchLambda,
- Criterion.Type.OCH_SIGTYPE,
- OpticalSignalTypeCriterion.class);
- assertThat(opticalSignalTypeCriterion.signalType(), is(equalTo(signalLambda1)));
- }
-
- /**
- * Test the equals() method of the OpticalSignalTypeCriterion class.
- */
- @Test
- public void testOpticalSignalTypeCriterionEquals() {
- new EqualsTester()
- .addEqualityGroup(matchSignalLambda1, sameAsMatchSignalLambda1)
- .addEqualityGroup(matchSignalLambda2)
- .testEquals();
- }
}
diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java
index ac4ecff3..d42e22fa 100644
--- a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java
+++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java
@@ -17,7 +17,6 @@ package org.onosproject.net.intent;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableSet;
-
import org.onlab.util.Bandwidth;
import org.onosproject.core.DefaultGroupId;
import org.onosproject.core.GroupId;
@@ -37,6 +36,9 @@ import org.onosproject.net.flow.criteria.Criterion.Type;
import org.onosproject.net.flow.instructions.Instruction;
import org.onosproject.net.flow.instructions.Instructions;
import org.onosproject.net.flow.instructions.Instructions.MetadataInstruction;
+import org.onosproject.net.resource.ResourceAllocation;
+import org.onosproject.net.resource.ResourceRequest;
+import org.onosproject.net.resource.ResourceType;
import org.onosproject.net.resource.link.BandwidthResource;
import org.onosproject.net.resource.link.BandwidthResourceRequest;
import org.onosproject.net.resource.link.LambdaResource;
@@ -48,13 +50,10 @@ 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.ResourceRequest;
-import org.onosproject.net.resource.ResourceType;
import org.onosproject.net.topology.DefaultTopologyEdge;
import org.onosproject.net.topology.DefaultTopologyVertex;
import org.onosproject.net.topology.LinkWeight;
-import org.onosproject.net.topology.PathService;
+import org.onosproject.net.topology.PathServiceAdapter;
import org.onosproject.net.topology.TopologyVertex;
import org.onosproject.store.Timestamp;
@@ -68,9 +67,7 @@ import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
-import static org.onosproject.net.NetTestTools.createPath;
-import static org.onosproject.net.NetTestTools.did;
-import static org.onosproject.net.NetTestTools.link;
+import static org.onosproject.net.NetTestTools.*;
/**
* Common mocks used by the intent framework tests.
@@ -134,7 +131,7 @@ public class IntentTestsMocks {
/**
* Mock path service for creating paths within the test.
*/
- public static class MockPathService implements PathService {
+ public static class MockPathService extends PathServiceAdapter {
final String[] pathHops;
final String[] reversePathHops;
@@ -424,7 +421,7 @@ public class IntentTestsMocks {
}
final MockFlowRule other = (MockFlowRule) obj;
return Objects.equals(this.timestamp, other.timestamp) &&
- this.id == other.id;
+ this.id == other.id;
}
@Override
@@ -450,7 +447,7 @@ public class IntentTestsMocks {
public MockIntent(Long number) {
super(NetTestTools.APP_ID, null, Collections.emptyList(),
- Intent.DEFAULT_INTENT_PRIORITY);
+ Intent.DEFAULT_INTENT_PRIORITY);
this.number = number;
}
diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/PacketServiceAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/PacketServiceAdapter.java
index c4386593..2993ce6b 100644
--- a/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/PacketServiceAdapter.java
+++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/PacketServiceAdapter.java
@@ -19,7 +19,6 @@ import org.onosproject.core.ApplicationId;
import org.onosproject.net.flow.TrafficSelector;
import java.util.List;
-import java.util.Map;
/**
* Test adapter for packet service.
@@ -34,7 +33,7 @@ public class PacketServiceAdapter implements PacketService {
}
@Override
- public Map<Integer, PacketProcessor> getProcessors() {
+ public List<PacketProcessorEntry> getProcessors() {
return null;
}
diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/DefaultGraphDescriptionTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/DefaultGraphDescriptionTest.java
index 8b0f8f05..f3958491 100644
--- a/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/DefaultGraphDescriptionTest.java
+++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/DefaultGraphDescriptionTest.java
@@ -41,7 +41,7 @@ public class DefaultGraphDescriptionTest {
@Test
public void basics() {
DefaultGraphDescription desc =
- new DefaultGraphDescription(4321L, ImmutableSet.of(DEV1, DEV2, DEV3),
+ new DefaultGraphDescription(4321L, System.currentTimeMillis(), ImmutableSet.of(DEV1, DEV2, DEV3),
ImmutableSet.of(L1, L2));
assertEquals("incorrect time", 4321L, desc.timestamp());
assertEquals("incorrect vertex count", 3, desc.vertexes().size());
@@ -50,7 +50,7 @@ public class DefaultGraphDescriptionTest {
@Test
public void missingVertex() {
- GraphDescription desc = new DefaultGraphDescription(4321L,
+ GraphDescription desc = new DefaultGraphDescription(4321L, System.currentTimeMillis(),
ImmutableSet.of(DEV1, DEV3),
ImmutableSet.of(L1, L2));
assertEquals("incorrect time", 4321L, desc.timestamp());
diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/PathServiceAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/PathServiceAdapter.java
new file mode 100644
index 00000000..6a8e586f
--- /dev/null
+++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/PathServiceAdapter.java
@@ -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.net.topology;
+
+import org.onosproject.net.DisjointPath;
+import org.onosproject.net.ElementId;
+import org.onosproject.net.Link;
+import org.onosproject.net.Path;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Test adapter for path service.
+ */
+public class PathServiceAdapter implements PathService {
+ @Override
+ public Set<Path> getPaths(ElementId src, ElementId dst) {
+ return null;
+ }
+
+ @Override
+ public Set<Path> getPaths(ElementId src, ElementId dst, LinkWeight weight) {
+ return null;
+ }
+
+ @Override
+ public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst) {
+ return null;
+ }
+
+ @Override
+ public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst, LinkWeight weight) {
+ return null;
+ }
+
+ @Override
+ public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst,
+ Map<Link, Object> riskProfile) {
+ return null;
+ }
+
+ @Override
+ public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst,
+ LinkWeight weight,
+ Map<Link, Object> riskProfile) {
+ return null;
+ }
+}
diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/TopologyServiceAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/TopologyServiceAdapter.java
index 07e67842..72cc67d7 100644
--- a/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/TopologyServiceAdapter.java
+++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/TopologyServiceAdapter.java
@@ -17,9 +17,11 @@ package org.onosproject.net.topology;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
+import org.onosproject.net.DisjointPath;
import org.onosproject.net.Link;
import org.onosproject.net.Path;
+import java.util.Map;
import java.util.Set;
/**
@@ -89,4 +91,28 @@ public class TopologyServiceAdapter implements TopologyService {
public void removeListener(TopologyListener listener) {
}
+ @Override
+ public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst) {
+ return null;
+ }
+
+ @Override
+ public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src,
+ DeviceId dst, LinkWeight weight) {
+ return null;
+ }
+
+ @Override
+ public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst,
+ Map<Link, Object> riskProfile) {
+ return null;
+ }
+
+ @Override
+ public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src,
+ DeviceId dst, LinkWeight weight,
+ Map<Link, Object> riskProfile) {
+ return null;
+ }
+
}
diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/TestAtomicCounter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/TestAtomicCounter.java
index 01209be2..8c577df9 100644
--- a/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/TestAtomicCounter.java
+++ b/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/TestAtomicCounter.java
@@ -48,6 +48,16 @@ public final class TestAtomicCounter implements AtomicCounter {
}
@Override
+ public void set(long value) {
+ this.value.set(value);
+ }
+
+ @Override
+ public boolean compareAndSet(long expectedValue, long updateValue) {
+ return value.compareAndSet(expectedValue, updateValue);
+ }
+
+ @Override
public long get() {
return value.get();
}
diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/CodecManager.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/CodecManager.java
index eb53152e..3433b3b7 100644
--- a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/CodecManager.java
+++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/CodecManager.java
@@ -16,6 +16,7 @@
package org.onosproject.codec.impl;
import com.google.common.collect.ImmutableSet;
+
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
@@ -36,6 +37,7 @@ import org.onosproject.net.Port;
import org.onosproject.net.driver.Driver;
import org.onosproject.net.flow.FlowEntry;
import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.TableStatisticsEntry;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.criteria.Criterion;
@@ -99,6 +101,7 @@ public class CodecManager implements CodecService {
registerCodec(Driver.class, new DriverCodec());
registerCodec(GroupBucket.class, new GroupBucketCodec());
registerCodec(Load.class, new LoadCodec());
+ registerCodec(TableStatisticsEntry.class, new TableStatisticsEntryCodec());
log.info("Started");
}
diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java
index d61cf38b..d12e4ad8 100644
--- a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java
+++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java
@@ -215,6 +215,7 @@ public final class EncodeInstructionCodecHelper {
break;
case DROP:
+ case NOACTION:
break;
case L0MODIFICATION:
diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/TableStatisticsEntryCodec.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/TableStatisticsEntryCodec.java
new file mode 100644
index 00000000..7834ceb1
--- /dev/null
+++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/TableStatisticsEntryCodec.java
@@ -0,0 +1,46 @@
+/*
+ * 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.codec.impl;
+
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.net.flow.TableStatisticsEntry;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Table statistics entry JSON codec.
+ */
+public final class TableStatisticsEntryCodec extends JsonCodec<TableStatisticsEntry> {
+
+ @Override
+ public ObjectNode encode(TableStatisticsEntry entry, CodecContext context) {
+ checkNotNull(entry, "Table Statistics entry cannot be null");
+
+ final ObjectNode result = context.mapper().createObjectNode()
+ .put("tableId", entry.tableId())
+ .put("deviceId", entry.deviceId().toString())
+ .put("activeEntries", entry.activeFlowEntries())
+ .put("packetsLookedUp", entry.packetsLookedup())
+ .put("packetsMatched", entry.packetsMatched());
+
+ return result;
+ }
+
+}
+
diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/common/DefaultTopology.java b/framework/src/onos/core/common/src/main/java/org/onosproject/common/DefaultTopology.java
index bdf7d732..3c5c540d 100644
--- a/framework/src/onos/core/common/src/main/java/org/onosproject/common/DefaultTopology.java
+++ b/framework/src/onos/core/common/src/main/java/org/onosproject/common/DefaultTopology.java
@@ -23,14 +23,19 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.ImmutableSetMultimap.Builder;
import org.onlab.graph.DijkstraGraphSearch;
+import org.onlab.graph.DisjointPathPair;
import org.onlab.graph.GraphPathSearch;
import org.onlab.graph.GraphPathSearch.Result;
+import org.onlab.graph.SRLGGraphSearch;
+import org.onlab.graph.SuurballeGraphSearch;
import org.onlab.graph.TarjanGraphSearch;
import org.onlab.graph.TarjanGraphSearch.SCCResult;
import org.onosproject.net.AbstractModel;
import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DefaultDisjointPath;
import org.onosproject.net.DefaultPath;
import org.onosproject.net.DeviceId;
+import org.onosproject.net.DisjointPath;
import org.onosproject.net.Link;
import org.onosproject.net.Path;
import org.onosproject.net.provider.ProviderId;
@@ -45,10 +50,11 @@ import org.onosproject.net.topology.TopologyEdge;
import org.onosproject.net.topology.TopologyGraph;
import org.onosproject.net.topology.TopologyVertex;
-import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.stream.Collectors;
import static com.google.common.base.MoreObjects.toStringHelper;
import static com.google.common.base.Preconditions.checkArgument;
@@ -67,6 +73,9 @@ public class DefaultTopology extends AbstractModel implements Topology {
private static final DijkstraGraphSearch<TopologyVertex, TopologyEdge> DIJKSTRA = new DijkstraGraphSearch<>();
private static final TarjanGraphSearch<TopologyVertex, TopologyEdge> TARJAN = new TarjanGraphSearch<>();
+ private static final SuurballeGraphSearch<TopologyVertex, TopologyEdge> SUURBALLE =
+ new SuurballeGraphSearch<>();
+
private final long time;
private final long creationTime;
@@ -315,15 +324,135 @@ public class DefaultTopology extends AbstractModel implements Topology {
return builder.build();
}
+ /**
+ * /**
+ * Returns the set of pre-computed shortest disjoint path pairs between source and
+ * destination devices.
+ *
+ * @param src source device
+ * @param dst destination device
+ * @return set of shortest disjoint path pairs
+ */
+ public Set<DisjointPath> getDisjointPaths(DeviceId src, DeviceId dst) {
+ return getDisjointPaths(src, dst, (LinkWeight) null);
+ }
+
+ /**
+ * Computes on-demand the set of shortest disjoint path pairs between source and
+ * destination devices.
+ *
+ * @param src source device
+ * @param dst destination device
+ * @param weight link weight function
+ * @return set of disjoint shortest path pairs
+ */
+ public Set<DisjointPath> getDisjointPaths(DeviceId src, DeviceId dst, LinkWeight weight) {
+ final DefaultTopologyVertex srcV = new DefaultTopologyVertex(src);
+ final DefaultTopologyVertex dstV = new DefaultTopologyVertex(dst);
+ Set<TopologyVertex> vertices = graph.getVertexes();
+ if (!vertices.contains(srcV) || !vertices.contains(dstV)) {
+ // src or dst not part of the current graph
+ return ImmutableSet.of();
+ }
+
+ GraphPathSearch.Result<TopologyVertex, TopologyEdge> result =
+ SUURBALLE.search(graph, srcV, dstV, weight, ALL_PATHS);
+ ImmutableSet.Builder<DisjointPath> builder = ImmutableSet.builder();
+ for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) {
+ builder.add(networkDisjointPath((org.onlab.graph.DisjointPathPair<TopologyVertex, TopologyEdge>) path));
+ }
+ return builder.build();
+ }
+
+ /**
+ * Computes on-demand the set of shortest disjoint risk groups path pairs between source and
+ * destination devices.
+ *
+ * @param src source device
+ * @param dst destination device
+ * @param weight edge weight object
+ * @param riskProfile map representing risk groups for each edge
+ * @return set of shortest disjoint paths
+ */
+ private Set<DisjointPath> disjointPaths(DeviceId src, DeviceId dst, LinkWeight weight,
+ Map<TopologyEdge, Object> riskProfile) {
+ DefaultTopologyVertex srcV = new DefaultTopologyVertex(src);
+ DefaultTopologyVertex dstV = new DefaultTopologyVertex(dst);
+
+ Set<TopologyVertex> vertices = graph.getVertexes();
+ if (!vertices.contains(srcV) || !vertices.contains(dstV)) {
+ // src or dst not part of the current graph
+ return ImmutableSet.of();
+ }
+
+ SRLGGraphSearch<TopologyVertex, TopologyEdge> srlg = new SRLGGraphSearch<>(riskProfile);
+ GraphPathSearch.Result<TopologyVertex, TopologyEdge> result =
+ srlg.search(graph, srcV, dstV, weight, ALL_PATHS);
+ ImmutableSet.Builder<DisjointPath> builder = ImmutableSet.builder();
+ for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) {
+ builder.add(networkDisjointPath((org.onlab.graph.DisjointPathPair<TopologyVertex, TopologyEdge>) path));
+ }
+ return builder.build();
+ }
+
+ /**
+ * Computes on-demand the set of shortest disjoint risk groups path pairs between source and
+ * destination devices.
+ *
+ * @param src source device
+ * @param dst destination device
+ * @param weight edge weight object
+ * @param riskProfile map representing risk groups for each link
+ * @return set of shortest disjoint paths
+ */
+ public Set<DisjointPath> getDisjointPaths(DeviceId src, DeviceId dst, LinkWeight weight,
+ Map<Link, Object> riskProfile) {
+ Map<TopologyEdge, Object> riskProfile2 = new HashMap<>();
+ for (Link l : riskProfile.keySet()) {
+ riskProfile2.put(new TopologyEdge() {
+ Link cur = l;
+
+ public Link link() {
+ return cur;
+ }
+
+ public TopologyVertex src() {
+ return () -> src;
+ }
+
+ public TopologyVertex dst() {
+ return () -> dst;
+ }
+ }, riskProfile.get(l));
+ }
+ return disjointPaths(src, dst, weight, riskProfile2);
+ }
+
+ /**
+ * Computes on-demand the set of shortest disjoint risk groups path pairs between source and
+ * destination devices.
+ *
+ * @param src source device
+ * @param dst destination device
+ * @param riskProfile map representing risk groups for each link
+ * @return set of shortest disjoint paths
+ */
+ public Set<DisjointPath> getDisjointPaths(DeviceId src, DeviceId dst, Map<Link, Object> riskProfile) {
+ return getDisjointPaths(src, dst, null, riskProfile);
+ }
+
// Converts graph path to a network path with the same cost.
private Path networkPath(org.onlab.graph.Path<TopologyVertex, TopologyEdge> path) {
- List<Link> links = new ArrayList<>();
- for (TopologyEdge edge : path.edges()) {
- links.add(edge.link());
- }
+ List<Link> links = path.edges().stream().map(TopologyEdge::link).collect(Collectors.toList());
return new DefaultPath(CORE_PROVIDER_ID, links, path.cost());
}
+ private DisjointPath networkDisjointPath(DisjointPathPair<TopologyVertex, TopologyEdge> path) {
+ return new DefaultDisjointPath(CORE_PROVIDER_ID,
+ (DefaultPath) networkPath(path.primary()),
+ (DefaultPath) networkPath(path.secondary()));
+ }
+
// Searches for SCC clusters in the network topology graph using Tarjan
// algorithm.
private SCCResult<TopologyVertex, TopologyEdge> searchForClusters() {
@@ -334,6 +463,7 @@ public class DefaultTopology extends AbstractModel implements Topology {
private ImmutableMap<ClusterId, TopologyCluster> buildTopologyClusters() {
ImmutableMap.Builder<ClusterId, TopologyCluster> clusterBuilder = ImmutableMap.builder();
SCCResult<TopologyVertex, TopologyEdge> results = clusterResults.get();
+
// Extract both vertexes and edges from the results; the lists form
// pairs along the same index.
List<Set<TopologyVertex>> clusterVertexes = results.clusterVertexes();
diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/CriterionCodecTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/CriterionCodecTest.java
index 6bf46803..54e1146b 100644
--- a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/CriterionCodecTest.java
+++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/CriterionCodecTest.java
@@ -38,10 +38,8 @@ import org.onosproject.net.flow.criteria.Criterion;
import com.fasterxml.jackson.databind.node.ObjectNode;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.onlab.junit.TestUtils.getField;
-import static org.onlab.junit.TestUtils.setField;
import static org.onosproject.codec.impl.CriterionJsonMatcher.matchesCriterion;
/**
@@ -429,17 +427,4 @@ public class CriterionCodecTest {
ObjectNode result = criterionCodec.encode(criterion, context);
assertThat(result, matchesCriterion(criterion));
}
-
- /**
- * Tests that an unimplemented criterion type only returns the type and
- * no other data.
- */
- @Test
- public void matchUnknownTypeTest() throws Exception {
- Criterion criterion = Criteria.matchOpticalSignalType((byte) 250);
- setField(criterion, "type", Criterion.Type.UNASSIGNED_40);
- ObjectNode result = criterionCodec.encode(criterion, context);
- assertThat(result.get("type").textValue(), is(criterion.type().toString()));
- assertThat(result.size(), is(1));
- }
}
diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionJsonMatcher.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionJsonMatcher.java
index 72081e6c..c3cdca0f 100644
--- a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionJsonMatcher.java
+++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionJsonMatcher.java
@@ -416,6 +416,8 @@ public final class InstructionJsonMatcher extends TypeSafeDiagnosingMatcher<Json
description);
} else if (instruction instanceof ModMplsLabelInstruction) {
return matchModMplsLabelInstruction(jsonInstruction, description);
+ } else if (instruction instanceof NoActionInstruction) {
+ return true;
}
return false;
diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/common/DefaultTopologyTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/common/DefaultTopologyTest.java
index 4d435cfe..ef0f3324 100644
--- a/framework/src/onos/core/common/src/test/java/org/onosproject/common/DefaultTopologyTest.java
+++ b/framework/src/onos/core/common/src/test/java/org/onosproject/common/DefaultTopologyTest.java
@@ -73,7 +73,7 @@ public class DefaultTopologyTest {
link("1", 3, "4", 3), link("4", 3, "1", 3),
link("3", 4, "4", 4), link("4", 4, "3", 4));
GraphDescription graphDescription =
- new DefaultGraphDescription(now, devices, links);
+ new DefaultGraphDescription(now, System.currentTimeMillis(), devices, links);
dt = new DefaultTopology(PID, graphDescription);
assertEquals("incorrect supplier", PID, dt.providerId());
diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleFlowRuleStore.java b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleFlowRuleStore.java
index c8c92aa5..bed32a2d 100644
--- a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleFlowRuleStore.java
+++ b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleFlowRuleStore.java
@@ -20,8 +20,10 @@ import com.google.common.cache.CacheBuilder;
import com.google.common.cache.RemovalListener;
import com.google.common.cache.RemovalNotification;
import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.SettableFuture;
+
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
@@ -44,6 +46,7 @@ import org.onosproject.net.flow.FlowRuleEvent.Type;
import org.onosproject.net.flow.FlowRuleStore;
import org.onosproject.net.flow.FlowRuleStoreDelegate;
import org.onosproject.net.flow.StoredFlowEntry;
+import org.onosproject.net.flow.TableStatisticsEntry;
import org.onosproject.store.AbstractStore;
import org.slf4j.Logger;
@@ -79,6 +82,9 @@ public class SimpleFlowRuleStore
private final ConcurrentMap<DeviceId, ConcurrentMap<FlowId, List<StoredFlowEntry>>>
flowEntries = new ConcurrentHashMap<>();
+ private final ConcurrentMap<DeviceId, List<TableStatisticsEntry>>
+ deviceTableStats = new ConcurrentHashMap<>();
+
private final AtomicInteger localBatchIdGen = new AtomicInteger();
// TODO: make this configurable
@@ -97,6 +103,7 @@ public class SimpleFlowRuleStore
@Deactivate
public void deactivate() {
+ deviceTableStats.clear();
flowEntries.clear();
log.info("Stopped");
}
@@ -315,4 +322,20 @@ public class SimpleFlowRuleStore
}
}
}
+
+ @Override
+ public FlowRuleEvent updateTableStatistics(DeviceId deviceId,
+ List<TableStatisticsEntry> tableStats) {
+ deviceTableStats.put(deviceId, tableStats);
+ return null;
+ }
+
+ @Override
+ public Iterable<TableStatisticsEntry> getTableStatistics(DeviceId deviceId) {
+ List<TableStatisticsEntry> tableStats = deviceTableStats.get(deviceId);
+ if (tableStats == null) {
+ return Collections.emptyList();
+ }
+ return ImmutableList.copyOf(tableStats);
+ }
}
diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleHostStore.java b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleHostStore.java
index 264d0493..72ec98ca 100644
--- a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleHostStore.java
+++ b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleHostStore.java
@@ -160,6 +160,11 @@ public class SimpleHostStore
}
@Override
+ public HostEvent removeIp(HostId hostId, IpAddress ipAddress) {
+ return null;
+ }
+
+ @Override
public int getHostCount() {
return hosts.size();
}
diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimplePacketStore.java b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimplePacketStore.java
index f8359262..7dda12c8 100644
--- a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimplePacketStore.java
+++ b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimplePacketStore.java
@@ -15,10 +15,13 @@
*/
package org.onosproject.store.trivial;
-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.Sets;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Service;
+import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.packet.OutboundPacket;
import org.onosproject.net.packet.PacketEvent;
import org.onosproject.net.packet.PacketEvent.Type;
@@ -27,7 +30,9 @@ import org.onosproject.net.packet.PacketStore;
import org.onosproject.net.packet.PacketStoreDelegate;
import org.onosproject.store.AbstractStore;
+import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
/**
@@ -39,7 +44,7 @@ public class SimplePacketStore
extends AbstractStore<PacketEvent, PacketStoreDelegate>
implements PacketStore {
- private Set<PacketRequest> requests = Sets.newConcurrentHashSet();
+ private Map<TrafficSelector, Set<PacketRequest>> requests = Maps.newConcurrentMap();
@Override
public void emit(OutboundPacket packet) {
@@ -47,18 +52,50 @@ public class SimplePacketStore
}
@Override
- public boolean requestPackets(PacketRequest request) {
- return requests.add(request);
+ public void requestPackets(PacketRequest request) {
+ requests.compute(request.selector(), (s, existingRequests) -> {
+ if (existingRequests == null) {
+ return ImmutableSet.of(request);
+ } else if (!existingRequests.contains(request)) {
+ if (delegate != null) {
+ delegate.requestPackets(request);
+ }
+ return ImmutableSet.<PacketRequest>builder()
+ .addAll(existingRequests)
+ .add(request)
+ .build();
+ } else {
+ return existingRequests;
+ }
+ });
}
@Override
- public boolean cancelPackets(PacketRequest request) {
- return requests.remove(request);
+ public void cancelPackets(PacketRequest request) {
+ requests.computeIfPresent(request.selector(), (s, existingRequests) -> {
+ if (existingRequests.contains(request)) {
+ HashSet<PacketRequest> newRequests = Sets.newHashSet(existingRequests);
+ newRequests.remove(request);
+ if (newRequests.size() > 0) {
+ return ImmutableSet.copyOf(newRequests);
+ } else {
+ if (delegate != null) {
+ delegate.cancelPackets(request);
+ }
+ return null;
+ }
+ } else {
+ return existingRequests;
+ }
+ });
}
@Override
public List<PacketRequest> existingRequests() {
- return ImmutableList.copyOf(requests);
+ List<PacketRequest> list = Lists.newArrayList();
+ requests.values().forEach(list::addAll);
+ list.sort((o1, o2) -> o1.priority().priorityValue() - o2.priority().priorityValue());
+ return list;
}
}
diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleTopologyStore.java b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleTopologyStore.java
index 6a89c019..29c5d844 100644
--- a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleTopologyStore.java
+++ b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleTopologyStore.java
@@ -23,6 +23,7 @@ import org.onosproject.common.DefaultTopology;
import org.onosproject.event.Event;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
+import org.onosproject.net.DisjointPath;
import org.onosproject.net.Link;
import org.onosproject.net.Path;
import org.onosproject.net.provider.ProviderId;
@@ -39,6 +40,7 @@ import org.onosproject.store.AbstractStore;
import org.slf4j.Logger;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import static org.slf4j.LoggerFactory.getLogger;
@@ -114,6 +116,29 @@ public class SimpleTopologyStore
}
@Override
+ public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst) {
+ return defaultTopology(topology).getDisjointPaths(src, dst);
+ }
+
+ @Override
+ public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst,
+ LinkWeight weight) {
+ return defaultTopology(topology).getDisjointPaths(src, dst, weight);
+ }
+
+ @Override
+ public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst,
+ Map<Link, Object> riskProfile) {
+ return defaultTopology(topology).getDisjointPaths(src, dst, riskProfile);
+ }
+
+ @Override
+ public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst,
+ LinkWeight weight, Map<Link, Object> riskProfile) {
+ return defaultTopology(topology).getDisjointPaths(src, dst, weight, riskProfile);
+ }
+
+ @Override
public boolean isInfrastructure(Topology topology, ConnectPoint connectPoint) {
return defaultTopology(topology).isInfrastructure(connectPoint);
}
diff --git a/framework/src/onos/core/net/pom.xml b/framework/src/onos/core/net/pom.xml
index 9ea00070..c5d31263 100644
--- a/framework/src/onos/core/net/pom.xml
+++ b/framework/src/onos/core/net/pom.xml
@@ -52,6 +52,20 @@
<dependency>
<groupId>org.onosproject</groupId>
+ <version>${project.version}</version>
+ <artifactId>onos-cli</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-cli</artifactId>
+ <version>${project.version}</version>
+ <classifier>tests</classifier>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
<artifactId>onos-core-common</artifactId>
<version>${project.version}</version>
<classifier>tests</classifier>
diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/cfg/impl/ComponentConfigLoader.java b/framework/src/onos/core/net/src/main/java/org/onosproject/cfg/impl/ComponentConfigLoader.java
new file mode 100644
index 00000000..6678db27
--- /dev/null
+++ b/framework/src/onos/core/net/src/main/java/org/onosproject/cfg/impl/ComponentConfigLoader.java
@@ -0,0 +1,74 @@
+/*
+ * 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.cfg.impl;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onosproject.cfg.ComponentConfigService;
+import org.slf4j.Logger;
+
+import java.io.File;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Component responsible for automatically loading configuration file from
+ * configuration directory.
+ */
+@Component(immediate = true)
+public class ComponentConfigLoader {
+
+ private static final String CFG_JSON = "../config/component-cfg.json";
+ static File cfgFile = new File(CFG_JSON);
+
+ private final Logger log = getLogger(getClass());
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected ComponentConfigService configService;
+
+ private ObjectNode root;
+
+ @Activate
+ protected void activate() {
+ this.loadConfigs();
+ log.info("Started");
+ }
+
+ // Loads the configurations for each component from the file in
+ // ../config/component-cfg.json, using the preSetProperty method.
+ private void loadConfigs() {
+ try {
+ if (cfgFile.exists()) {
+ root = (ObjectNode) new ObjectMapper().readTree(cfgFile);
+ root.fieldNames().
+ forEachRemaining(component -> root.path(component).fieldNames()
+ .forEachRemaining(k -> configService
+ .preSetProperty(component, k,
+ root.path(component).path(k)
+ .asText())));
+ log.info("Loaded initial component configuration from {}", cfgFile);
+ }
+ } catch (Exception e) {
+ log.warn("Unable to load initial component configuration from {}",
+ cfgFile, e);
+ }
+ }
+}
diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/cfg/impl/ComponentConfigManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/cfg/impl/ComponentConfigManager.java
index 1933ee55..b3b22c76 100644
--- a/framework/src/onos/core/net/src/main/java/org/onosproject/cfg/impl/ComponentConfigManager.java
+++ b/framework/src/onos/core/net/src/main/java/org/onosproject/cfg/impl/ComponentConfigManager.java
@@ -61,6 +61,9 @@ public class ComponentConfigManager implements ComponentConfigService {
private static final String COMPONENT_NULL = "Component name cannot be null";
private static final String PROPERTY_NULL = "Property name cannot be null";
+ private static final String COMPONENT_MISSING = "Component %s is not registered";
+ private static final String PROPERTY_MISSING = "Property %s does not exist for %s";
+
//Symbolic constants for use with the accumulator
private static final int MAX_ITEMS = 100;
@@ -160,6 +163,22 @@ public class ComponentConfigManager implements ComponentConfigService {
checkNotNull(componentName, COMPONENT_NULL);
checkNotNull(name, PROPERTY_NULL);
+
+ checkArgument(properties.containsKey(componentName),
+ COMPONENT_MISSING, componentName);
+ checkArgument(properties.get(componentName).containsKey(name),
+ PROPERTY_MISSING, name, componentName);
+ store.setProperty(componentName, name, value);
+ }
+
+ @Override
+ public void preSetProperty(String componentName, String name, String value) {
+
+ checkPermission(CONFIG_WRITE);
+
+ checkNotNull(componentName, COMPONENT_NULL);
+ checkNotNull(name, PROPERTY_NULL);
+
store.setProperty(componentName, name, value);
}
@@ -169,6 +188,11 @@ public class ComponentConfigManager implements ComponentConfigService {
checkNotNull(componentName, COMPONENT_NULL);
checkNotNull(name, PROPERTY_NULL);
+
+ checkArgument(properties.containsKey(componentName),
+ COMPONENT_MISSING, componentName);
+ checkArgument(properties.get(componentName).containsKey(name),
+ PROPERTY_MISSING, name, componentName);
store.unsetProperty(componentName, name);
}
diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/core/impl/CoreManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/core/impl/CoreManager.java
index 8a441f61..f4d560a4 100644
--- a/framework/src/onos/core/net/src/main/java/org/onosproject/core/impl/CoreManager.java
+++ b/framework/src/onos/core/net/src/main/java/org/onosproject/core/impl/CoreManager.java
@@ -24,7 +24,6 @@ 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.SharedExecutors;
-import org.onlab.util.Tools;
import org.onosproject.cfg.ComponentConfigService;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.ApplicationIdStore;
@@ -38,6 +37,10 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.Dictionary;
import java.util.List;
import java.util.Set;
@@ -87,9 +90,15 @@ public class CoreManager implements CoreService {
public void activate() {
registerApplication(CORE_APP_NAME);
cfgService.registerProperties(getClass());
- List<String> versionLines = Tools.slurp(VERSION_FILE);
- if (versionLines != null && !versionLines.isEmpty()) {
- version = Version.version(versionLines.get(0));
+ try {
+ Path path = Paths.get(VERSION_FILE.getPath());
+ List<String> versionLines = Files.readAllLines(path);
+ if (versionLines != null && !versionLines.isEmpty()) {
+ version = Version.version(versionLines.get(0));
+ }
+ } catch (IOException e) {
+ // version file not found, using default
+ log.trace("Version file not found", e);
}
}
diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/config/impl/NetworkConfigManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/config/impl/NetworkConfigManager.java
index 5cd96cab..db484eea 100644
--- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/config/impl/NetworkConfigManager.java
+++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/config/impl/NetworkConfigManager.java
@@ -96,7 +96,7 @@ public class NetworkConfigManager
configClasses.put(identifier(configFactory), configFactory.configClass());
SubjectFactory subjectFactory = configFactory.subjectFactory();
- subjectClasses.putIfAbsent(subjectFactory.subjectKey(), subjectFactory);
+ subjectClasses.putIfAbsent(subjectFactory.subjectClassKey(), subjectFactory);
subjectClassKeys.putIfAbsent(subjectFactory.subjectClass(), subjectFactory);
store.addConfigFactory(configFactory);
@@ -145,8 +145,8 @@ public class NetworkConfigManager
}
@Override
- public SubjectFactory getSubjectFactory(String subjectKey) {
- return subjectClasses.get(subjectKey);
+ public SubjectFactory getSubjectFactory(String subjectClassKey) {
+ return subjectClasses.get(subjectClassKey);
}
@Override
@@ -155,8 +155,8 @@ public class NetworkConfigManager
}
@Override
- public Class<? extends Config> getConfigClass(String subjectKey, String configKey) {
- return configClasses.get(new ConfigIdentifier(subjectKey, configKey));
+ public Class<? extends Config> getConfigClass(String subjectClassKey, String configKey) {
+ return configClasses.get(new ConfigIdentifier(subjectClassKey, configKey));
}
@Override
@@ -255,7 +255,7 @@ public class NetworkConfigManager
}
private static ConfigIdentifier identifier(ConfigFactory factory) {
- return new ConfigIdentifier(factory.subjectFactory().subjectKey(), factory.configKey());
+ return new ConfigIdentifier(factory.subjectFactory().subjectClassKey(), factory.configKey());
}
static final class ConfigIdentifier {
diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/BasicDeviceOperator.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/BasicDeviceOperator.java
index 7900d185..fa90eb65 100644
--- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/BasicDeviceOperator.java
+++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/BasicDeviceOperator.java
@@ -15,21 +15,21 @@
*/
package org.onosproject.net.device.impl;
-import static org.slf4j.LoggerFactory.getLogger;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import org.onosproject.net.config.ConfigOperator;
-import org.onosproject.net.config.basics.BasicDeviceConfig;
import org.onosproject.net.AnnotationKeys;
import org.onosproject.net.DefaultAnnotations;
import org.onosproject.net.Device;
import org.onosproject.net.SparseAnnotations;
+import org.onosproject.net.config.ConfigOperator;
+import org.onosproject.net.config.basics.BasicDeviceConfig;
import org.onosproject.net.device.DefaultDeviceDescription;
import org.onosproject.net.device.DeviceDescription;
import org.slf4j.Logger;
import java.util.Objects;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
/**
* Implementations of merge policies for various sources of device configuration
* information. This includes applications, provides, and network configurations.
@@ -46,7 +46,7 @@ public final class BasicDeviceOperator implements ConfigOperator {
* Generates a DeviceDescription containing fields from a DeviceDescription and
* a DeviceConfig.
*
- * @param bdc the device config entity from network config
+ * @param bdc the device config entity from network config
* @param descr a DeviceDescription
* @return DeviceDescription based on both sources
*/
@@ -70,7 +70,7 @@ public final class BasicDeviceOperator implements ConfigOperator {
* Generates an annotation from an existing annotation and DeviceConfig.
*
* @param bdc the device config entity from network config
- * @param an the annotation
+ * @param an the annotation
* @return annotation combining both sources
*/
public static SparseAnnotations combine(BasicDeviceConfig bdc, SparseAnnotations an) {
@@ -93,6 +93,9 @@ public final class BasicDeviceOperator implements ConfigOperator {
if (bdc.owner() != null) {
newBuilder.set(AnnotationKeys.OWNER, bdc.owner());
}
+ if (bdc.managementAddress() != null) {
+ newBuilder.set(AnnotationKeys.MANAGEMENT_ADDRESS, bdc.managementAddress());
+ }
DefaultAnnotations newAnnotations = newBuilder.build();
return DefaultAnnotations.union(an, newAnnotations);
}
diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java
index b0b3abe2..e35dc0c5 100644
--- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java
+++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java
@@ -15,8 +15,26 @@
*/
package org.onosproject.net.device.impl;
-import com.google.common.collect.Lists;
-import com.google.common.util.concurrent.Futures;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
+import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.net.MastershipRole.MASTER;
+import static org.onosproject.net.MastershipRole.NONE;
+import static org.onosproject.net.MastershipRole.STANDBY;
+import static org.onosproject.security.AppGuard.checkPermission;
+import static org.onosproject.security.AppPermission.Type.DEVICE_READ;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
@@ -26,12 +44,6 @@ import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;
import org.onosproject.cluster.ClusterService;
import org.onosproject.cluster.NodeId;
-import org.onosproject.net.provider.AbstractListenerProviderRegistry;
-import org.onosproject.net.config.NetworkConfigEvent;
-import org.onosproject.net.config.NetworkConfigListener;
-import org.onosproject.net.config.NetworkConfigService;
-import org.onosproject.net.config.basics.BasicDeviceConfig;
-import org.onosproject.net.config.basics.OpticalPortConfig;
import org.onosproject.mastership.MastershipEvent;
import org.onosproject.mastership.MastershipListener;
import org.onosproject.mastership.MastershipService;
@@ -44,6 +56,11 @@ import org.onosproject.net.DeviceId;
import org.onosproject.net.MastershipRole;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
+import org.onosproject.net.config.NetworkConfigEvent;
+import org.onosproject.net.config.NetworkConfigListener;
+import org.onosproject.net.config.NetworkConfigService;
+import org.onosproject.net.config.basics.BasicDeviceConfig;
+import org.onosproject.net.config.basics.OpticalPortConfig;
import org.onosproject.net.device.DefaultDeviceDescription;
import org.onosproject.net.device.DefaultPortDescription;
import org.onosproject.net.device.DeviceAdminService;
@@ -58,27 +75,11 @@ import org.onosproject.net.device.DeviceStore;
import org.onosproject.net.device.DeviceStoreDelegate;
import org.onosproject.net.device.PortDescription;
import org.onosproject.net.device.PortStatistics;
+import org.onosproject.net.provider.AbstractListenerProviderRegistry;
import org.onosproject.net.provider.AbstractProviderService;
import org.slf4j.Logger;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Objects;
-import java.util.Set;
-import java.util.stream.Collectors;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
-import static org.onlab.util.Tools.groupedThreads;
-import static org.onosproject.net.MastershipRole.*;
-import static org.onosproject.security.AppGuard.checkPermission;
-import static org.slf4j.LoggerFactory.getLogger;
-import static org.onosproject.security.AppPermission.Type.*;
+import com.google.common.util.concurrent.Futures;
/**
* Provides implementation of the device SB &amp; NB APIs.
@@ -347,11 +348,15 @@ public class DeviceManager
log.info("Device {} disconnected from this node", deviceId);
List<Port> ports = store.getPorts(deviceId);
- List<PortDescription> descs = Lists.newArrayList();
- ports.forEach(port ->
- descs.add(new DefaultPortDescription(port.number(),
- false, port.type(),
- port.portSpeed())));
+ final Device device = getDevice(deviceId);
+
+ List<PortDescription> descs = ports.stream().map(
+ port -> (!(Device.Type.ROADM.equals(device.type()))) ?
+ new DefaultPortDescription(port.number(), false,
+ port.type(), port.portSpeed()) :
+ OpticalPortOperator.descriptionOf(port, false)
+ ).collect(Collectors.toList());
+
store.updatePorts(this.provider().id(), deviceId, descs);
try {
if (mastershipService.isLocalMaster(deviceId)) {
@@ -430,6 +435,12 @@ public class DeviceManager
portDescription);
return;
}
+ final Device device = getDevice(deviceId);
+ if ((Device.Type.ROADM.equals(device.type()))) {
+ Port port = getPort(deviceId, portDescription.portNumber());
+ portDescription = OpticalPortOperator.descriptionOf(port, portDescription.isEnabled());
+ }
+
portDescription = consolidate(deviceId, portDescription);
final DeviceEvent event = store.updatePortStatus(this.provider().id(),
deviceId, portDescription);
diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/OpticalPortOperator.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/OpticalPortOperator.java
index b2fd02c7..8f2bda01 100644
--- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/OpticalPortOperator.java
+++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/OpticalPortOperator.java
@@ -151,8 +151,25 @@ public final class OpticalPortOperator implements ConfigOperator {
*/
public static PortDescription descriptionOf(Port port) {
checkNotNull(port, "Must supply non-null Port");
+ final boolean isUp = port.isEnabled();
+ return descriptionOfPort(port, isUp);
+ }
+
+ /**
+ * Returns a description built from an existing port and reported status.
+ *
+ * @param port
+ * @param isEnabled
+ * @return a PortDescription based on the port
+ */
+ static PortDescription descriptionOf(Port port, boolean isEnabled) {
+ checkNotNull(port, "Must supply non-null Port");
+ final boolean isup = isEnabled;
+ return descriptionOfPort(port, isup);
+ }
+
+ private static PortDescription descriptionOfPort(Port port, final boolean isup) {
final PortNumber ptn = port.number();
- final boolean isup = port.isEnabled();
final SparseAnnotations an = (SparseAnnotations) port.annotations();
switch (port.type()) {
case OMS:
diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/flow/impl/FlowRuleManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/flow/impl/FlowRuleManager.java
index a1d046c5..5958d1f5 100644
--- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/flow/impl/FlowRuleManager.java
+++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/flow/impl/FlowRuleManager.java
@@ -22,6 +22,7 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
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;
@@ -58,6 +59,7 @@ import org.onosproject.net.flow.FlowRuleProviderService;
import org.onosproject.net.flow.FlowRuleService;
import org.onosproject.net.flow.FlowRuleStore;
import org.onosproject.net.flow.FlowRuleStoreDelegate;
+import org.onosproject.net.flow.TableStatisticsEntry;
import org.onosproject.net.provider.AbstractProviderService;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
@@ -388,6 +390,16 @@ public class FlowRuleManager
@Override
public void pushFlowMetrics(DeviceId deviceId, Iterable<FlowEntry> flowEntries) {
+ pushFlowMetricsInternal(deviceId, flowEntries, true);
+ }
+
+ @Override
+ public void pushFlowMetricsWithoutFlowMissing(DeviceId deviceId, Iterable<FlowEntry> flowEntries) {
+ pushFlowMetricsInternal(deviceId, flowEntries, false);
+ }
+
+ private void pushFlowMetricsInternal(DeviceId deviceId, Iterable<FlowEntry> flowEntries,
+ boolean useMissingFlow) {
Map<FlowEntry, FlowEntry> storedRules = Maps.newHashMap();
store.getFlowEntries(deviceId).forEach(f -> storedRules.put(f, f));
@@ -415,17 +427,20 @@ public class FlowRuleManager
continue;
}
}
- for (FlowEntry rule : storedRules.keySet()) {
- try {
- // there are rules in the store that aren't on the switch
- log.debug("Adding rule in store, but not on switch {}", rule);
- flowMissing(rule);
- } catch (Exception e) {
- log.debug("Can't add missing flow rule {}", e.getMessage());
- continue;
+
+ // DO NOT reinstall
+ if (useMissingFlow) {
+ for (FlowEntry rule : storedRules.keySet()) {
+ try {
+ // there are rules in the store that aren't on the switch
+ log.debug("Adding rule in store, but not on switch {}", rule);
+ flowMissing(rule);
+ } catch (Exception e) {
+ log.debug("Can't add missing flow rule {}", e.getMessage());
+ continue;
+ }
}
}
-
}
@Override
@@ -435,6 +450,12 @@ public class FlowRuleManager
operation
));
}
+
+ @Override
+ public void pushTableStatistics(DeviceId deviceId,
+ List<TableStatisticsEntry> tableStats) {
+ store.updateTableStatistics(deviceId, tableStats);
+ }
}
// Store delegate to re-post events emitted from the store.
@@ -590,4 +611,10 @@ public class FlowRuleManager
}
}
+
+ @Override
+ public Iterable<TableStatisticsEntry> getFlowTableStatistics(DeviceId deviceId) {
+ checkPermission(FLOWRULE_READ);
+ return store.getTableStatistics(deviceId);
+ }
}
diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java
index 43f346b7..1473f33f 100644
--- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java
+++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java
@@ -236,6 +236,16 @@ public class HostManager
post(event);
}
}
+
+ @Override
+ public void removeIpFromHost(HostId hostId, IpAddress ipAddress) {
+ checkNotNull(hostId, HOST_ID_NULL);
+ checkValidity();
+ HostEvent event = store.removeIp(hostId, ipAddress);
+ if (event != null) {
+ post(event);
+ }
+ }
}
// Store delegate to re-post events emitted from the store.
diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/host/impl/HostMonitor.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/host/impl/HostMonitor.java
index 44f8cbf0..4dc93a51 100644
--- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/host/impl/HostMonitor.java
+++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/host/impl/HostMonitor.java
@@ -84,6 +84,7 @@ public class HostMonitor implements TimerTask {
* @param hostManager host manager used to look up host information and
* probe existing hosts
* @param interfaceService interface service for interface information
+ * @param edgePortService edge port service
*/
public HostMonitor(PacketService packetService, HostManager hostManager,
InterfaceService interfaceService,
diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentCleanup.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentCleanup.java
index d7fa3223..417627ad 100644
--- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentCleanup.java
+++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentCleanup.java
@@ -196,7 +196,7 @@ public class IntentCleanup implements Runnable, IntentListener {
service.withdraw(intentData.intent());
break;
default:
- log.warn("Trying to resubmit pending intent {} in state {} with request {}",
+ log.warn("Failed to resubmit pending intent {} in state {} with request {}",
intentData.key(), intentData.state(), intentData.request());
break;
}
diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java
index 4c828e77..baa3bf4d 100644
--- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java
+++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java
@@ -256,15 +256,16 @@ public class IntentManager
submit(intent);
}
- // If required, compile all currently failed intents.
- for (Intent intent : getIntents()) {
- IntentState state = getIntentState(intent.key());
- if ((compileAllFailed && RECOMPILE.contains(state))
- || intentAllowsPartialFailure(intent)) {
- if (WITHDRAW.contains(state)) {
- withdraw(intent);
- } else {
- submit(intent);
+ if (compileAllFailed) {
+ // If required, compile all currently failed intents.
+ for (Intent intent : getIntents()) {
+ IntentState state = getIntentState(intent.key());
+ if (RECOMPILE.contains(state) || intentAllowsPartialFailure(intent)) {
+ if (WITHDRAW.contains(state)) {
+ withdraw(intent);
+ } else {
+ submit(intent);
+ }
}
}
}
diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/ObjectiveTracker.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/ObjectiveTracker.java
index 5710aced..5ebc812e 100644
--- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/ObjectiveTracker.java
+++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/ObjectiveTracker.java
@@ -16,8 +16,8 @@
package org.onosproject.net.intent.impl;
import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
import com.google.common.collect.SetMultimap;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
@@ -61,7 +61,6 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
-import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
@@ -91,8 +90,6 @@ public class ObjectiveTracker implements ObjectiveTrackerService {
private final Logger log = getLogger(getClass());
- private final ConcurrentMap<Key, Intent> intents = Maps.newConcurrentMap();
-
private final SetMultimap<LinkKey, Key> intentsByLink =
//TODO this could be slow as a point of synchronization
synchronizedSetMultimap(HashMultimap.<LinkKey, Key>create());
@@ -378,7 +375,12 @@ public class ObjectiveTracker implements ObjectiveTrackerService {
}
// TODO should we recompile on available==true?
- delegate.triggerCompile(intentsByDevice.get(id), available);
+
+ final ImmutableSet<Key> snapshot;
+ synchronized (intentsByDevice) {
+ snapshot = ImmutableSet.copyOf(intentsByDevice.get(id));
+ }
+ delegate.triggerCompile(snapshot, available);
}
}
@@ -415,9 +417,17 @@ public class ObjectiveTracker implements ObjectiveTrackerService {
@Override
public void event(HostEvent event) {
HostId id = event.subject().id();
- HostEvent.Type type = event.type();
- boolean available = (type == HostEvent.Type.HOST_ADDED);
- executorService.execute(new DeviceAvailabilityHandler(id, available));
+ switch (event.type()) {
+ case HOST_ADDED:
+ case HOST_MOVED:
+ case HOST_REMOVED:
+ executorService.execute(new DeviceAvailabilityHandler(id, false));
+ break;
+ case HOST_UPDATED:
+ default:
+ // DO NOTHING
+ break;
+ }
}
}
diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalCircuitIntentCompiler.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalCircuitIntentCompiler.java
index 99f58df7..c6eb7c5a 100644
--- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalCircuitIntentCompiler.java
+++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalCircuitIntentCompiler.java
@@ -15,10 +15,8 @@
*/
package org.onosproject.net.intent.impl.compiler;
-import com.google.common.collect.Sets;
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;
@@ -50,7 +48,10 @@ import org.onosproject.net.intent.IntentService;
import org.onosproject.net.intent.OpticalCircuitIntent;
import org.onosproject.net.intent.OpticalConnectivityIntent;
import org.onosproject.net.intent.impl.IntentCompilationException;
-import org.onosproject.net.resource.device.DeviceResourceService;
+import org.onosproject.net.newresource.ResourceAllocation;
+import org.onosproject.net.newresource.ResourcePath;
+import org.onosproject.net.newresource.ResourceService;
+import org.onosproject.net.resource.device.IntentSetMultimap;
import org.onosproject.net.resource.link.LinkResourceAllocations;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
@@ -60,6 +61,7 @@ import java.util.Collections;
import java.util.Dictionary;
import java.util.LinkedList;
import java.util.List;
+import java.util.Optional;
import java.util.Set;
import static com.google.common.base.Preconditions.checkArgument;
@@ -67,7 +69,8 @@ import static com.google.common.base.Preconditions.checkArgument;
/**
* An intent compiler for {@link org.onosproject.net.intent.OpticalCircuitIntent}.
*/
-@Component(immediate = true)
+// For now, remove component designation until dependency on the new resource manager is available.
+// @Component(immediate = true)
public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircuitIntent> {
private static final Logger log = LoggerFactory.getLogger(OpticalCircuitIntentCompiler.class);
@@ -92,7 +95,10 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu
protected DeviceService deviceService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected DeviceResourceService deviceResourceService;
+ protected ResourceService resourceService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected IntentSetMultimap intentSetMultimap;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected IntentService intentService;
@@ -153,7 +159,10 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu
log.debug("Compiling optical circuit intent between {} and {}", src, dst);
// Reserve OduClt ports
- if (!deviceResourceService.requestPorts(Sets.newHashSet(srcPort, dstPort), intent)) {
+ ResourcePath srcPortPath = new ResourcePath(src.deviceId(), src.port());
+ ResourcePath dstPortPath = new ResourcePath(dst.deviceId(), dst.port());
+ List<ResourceAllocation> allocation = resourceService.allocate(intent.id(), srcPortPath, dstPortPath);
+ if (allocation.isEmpty()) {
throw new IntentCompilationException("Unable to reserve ports for intent " + intent);
}
@@ -199,7 +208,7 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu
circuitIntent = new FlowRuleIntent(appId, rules, intent.resources());
// Save circuit to connectivity intent mapping
- deviceResourceService.requestMapping(connIntent.id(), intent.id());
+ intentSetMultimap.allocateMapping(connIntent.id(), intent.id());
intents.add(circuitIntent);
return intents;
@@ -209,16 +218,15 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu
* Checks if current allocations on given resource can satisfy request.
* If the resource is null, return true.
*
- * @param request the intent making the request
* @param resource the resource on which to map the intent
* @return true if the resource can accept the request, false otherwise
*/
- private boolean isAvailable(Intent request, IntentId resource) {
+ private boolean isAvailable(IntentId resource) {
if (resource == null) {
return true;
}
- Set<IntentId> mapping = deviceResourceService.getMapping(resource);
+ Set<IntentId> mapping = intentSetMultimap.getMapping(resource);
if (mapping == null) {
return true;
@@ -271,7 +279,7 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu
continue;
}
- if (isAvailable(circuitIntent, connIntent.id())) {
+ if (isAvailable(connIntent.id())) {
return connIntent;
}
}
@@ -296,14 +304,19 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu
return null;
}
- private OchPort findAvailableOchPort(ConnectPoint oduPort, OpticalCircuitIntent circuitIntent) {
+ private OchPort findAvailableOchPort(ConnectPoint oduPort) {
// First see if the port mappings are constrained
ConnectPoint ochCP = staticPort(oduPort);
if (ochCP != null) {
OchPort ochPort = (OchPort) deviceService.getPort(ochCP.deviceId(), ochCP.port());
- IntentId intentId = deviceResourceService.getAllocations(ochPort);
- if (isAvailable(circuitIntent, intentId)) {
+ Optional<IntentId> intentId =
+ resourceService.getResourceAllocation(new ResourcePath(ochCP.deviceId(), ochCP.port()))
+ .map(ResourceAllocation::consumer)
+ .filter(x -> x instanceof IntentId)
+ .map(x -> (IntentId) x);
+
+ if (isAvailable(intentId.orElse(null))) {
return ochPort;
}
}
@@ -316,8 +329,12 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu
continue;
}
- IntentId intentId = deviceResourceService.getAllocations(port);
- if (isAvailable(circuitIntent, intentId)) {
+ Optional<IntentId> intentId =
+ resourceService.getResourceAllocation(new ResourcePath(oduPort.deviceId(), port.number()))
+ .map(ResourceAllocation::consumer)
+ .filter(x -> x instanceof IntentId)
+ .map(x -> (IntentId) x);
+ if (isAvailable(intentId.orElse(null))) {
return (OchPort) port;
}
}
@@ -327,12 +344,12 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu
private Pair<OchPort, OchPort> findPorts(OpticalCircuitIntent intent) {
- OchPort srcPort = findAvailableOchPort(intent.getSrc(), intent);
+ OchPort srcPort = findAvailableOchPort(intent.getSrc());
if (srcPort == null) {
return null;
}
- OchPort dstPort = findAvailableOchPort(intent.getDst(), intent);
+ OchPort dstPort = findAvailableOchPort(intent.getDst());
if (dstPort == null) {
return null;
}
diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalConnectivityIntentCompiler.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalConnectivityIntentCompiler.java
index 05a20f96..eb5b4af8 100644
--- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalConnectivityIntentCompiler.java
+++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalConnectivityIntentCompiler.java
@@ -16,9 +16,7 @@
package org.onosproject.net.intent.impl.compiler;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
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;
@@ -40,9 +38,9 @@ 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.resource.ResourceAllocation;
+import org.onosproject.net.newresource.ResourcePath;
+import org.onosproject.net.newresource.ResourceService;
import org.onosproject.net.resource.ResourceType;
-import org.onosproject.net.resource.device.DeviceResourceService;
import org.onosproject.net.resource.link.DefaultLinkResourceRequest;
import org.onosproject.net.resource.link.LambdaResource;
import org.onosproject.net.resource.link.LambdaResourceAllocation;
@@ -57,13 +55,15 @@ import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Set;
+import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkArgument;
/**
* An intent compiler for {@link org.onosproject.net.intent.OpticalConnectivityIntent}.
*/
-@Component(immediate = true)
+// For now, remove component designation until dependency on the new resource manager is available.
+// @Component(immediate = true)
public class OpticalConnectivityIntentCompiler implements IntentCompiler<OpticalConnectivityIntent> {
protected static final Logger log = LoggerFactory.getLogger(OpticalConnectivityIntentCompiler.class);
@@ -78,10 +78,10 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical
protected DeviceService deviceService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected LinkResourceService linkResourceService;
+ protected ResourceService resourceService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected DeviceResourceService deviceResourceService;
+ protected LinkResourceService linkResourceService;
@Activate
public void activate() {
@@ -108,7 +108,11 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical
log.debug("Compiling optical connectivity intent between {} and {}", src, dst);
// Reserve OCh ports
- if (!deviceResourceService.requestPorts(ImmutableSet.of(srcPort, dstPort), intent)) {
+ ResourcePath srcPortPath = new ResourcePath(src.deviceId(), src.port());
+ ResourcePath dstPortPath = new ResourcePath(dst.deviceId(), dst.port());
+ List<org.onosproject.net.newresource.ResourceAllocation> allocation =
+ resourceService.allocate(intent.id(), srcPortPath, dstPortPath);
+ if (allocation.isEmpty()) {
throw new IntentCompilationException("Unable to reserve ports for intent " + intent);
}
@@ -161,7 +165,7 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical
}
// Release port allocations if unsuccessful
- deviceResourceService.releasePorts(intent.id());
+ resourceService.release(intent.id());
throw new IntentCompilationException("Unable to find suitable lightpath for intent " + intent);
}
@@ -174,15 +178,12 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical
* @return lambda allocated to the given path
*/
private LambdaResourceAllocation getWavelength(Path path, LinkResourceAllocations linkAllocs) {
- for (Link link : path.links()) {
- for (ResourceAllocation alloc : linkAllocs.getResourceAllocation(link)) {
- if (alloc.type() == ResourceType.LAMBDA) {
- return (LambdaResourceAllocation) alloc;
- }
- }
- }
-
- return null;
+ return path.links().stream()
+ .flatMap(x -> linkAllocs.getResourceAllocation(x).stream())
+ .filter(x -> x.type() == ResourceType.LAMBDA)
+ .findFirst()
+ .map(x -> (LambdaResourceAllocation) x)
+ .orElse(null);
}
/**
@@ -215,23 +216,23 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical
return false;
}
- LambdaResource lambda = null;
+ 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());
- for (Link link : path.links()) {
- for (ResourceAllocation alloc : allocations.getResourceAllocation(link)) {
- if (alloc.type() == ResourceType.LAMBDA) {
- LambdaResource nextLambda = ((LambdaResourceAllocation) alloc).lambda();
- if (nextLambda == null) {
- return false;
- }
- if (lambda == null) {
- lambda = nextLambda;
- continue;
- }
- if (!lambda.equals(nextLambda)) {
- return false;
- }
- }
+ LambdaResource lambda = null;
+ for (LambdaResource nextLambda: lambdas) {
+ if (nextLambda == null) {
+ return false;
+ }
+ if (lambda == null) {
+ lambda = nextLambda;
+ continue;
+ }
+ if (!lambda.equals(nextLambda)) {
+ return false;
}
}
diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompiler.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompiler.java
index ca9ae5cc..2cc45e79 100644
--- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompiler.java
+++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompiler.java
@@ -39,7 +39,6 @@ import org.onosproject.net.intent.IntentCompiler;
import org.onosproject.net.intent.IntentExtensionService;
import org.onosproject.net.intent.OpticalPathIntent;
import org.onosproject.net.resource.link.LinkResourceAllocations;
-import org.onosproject.net.resource.link.LinkResourceService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -59,9 +58,6 @@ public class OpticalPathIntentCompiler implements IntentCompiler<OpticalPathInte
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CoreService coreService;
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected LinkResourceService resourceService;
-
private ApplicationId appId;
@Activate
diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceManager.java
index 2cd1a2e0..5226967f 100644
--- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceManager.java
+++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceManager.java
@@ -91,6 +91,14 @@ public final class ResourceManager implements ResourceService, ResourceAdminServ
}
@Override
+ public Optional<ResourceAllocation> getResourceAllocation(ResourcePath resource) {
+ checkNotNull(resource);
+
+ Optional<ResourceConsumer> consumer = store.getConsumer(resource);
+ return consumer.map(x -> new ResourceAllocation(resource, x));
+ }
+
+ @Override
public <T> Collection<ResourceAllocation> getResourceAllocations(ResourcePath parent, Class<T> cls) {
checkNotNull(parent);
checkNotNull(cls);
diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/packet/impl/PacketManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/packet/impl/PacketManager.java
index a0bc693c..8e87a07d 100644
--- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/packet/impl/PacketManager.java
+++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/packet/impl/PacketManager.java
@@ -15,7 +15,8 @@
*/
package org.onosproject.net.packet.impl;
-import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
@@ -43,6 +44,7 @@ import org.onosproject.net.packet.PacketContext;
import org.onosproject.net.packet.PacketEvent;
import org.onosproject.net.packet.PacketPriority;
import org.onosproject.net.packet.PacketProcessor;
+import org.onosproject.net.packet.PacketProcessorEntry;
import org.onosproject.net.packet.PacketProvider;
import org.onosproject.net.packet.PacketProviderRegistry;
import org.onosproject.net.packet.PacketProviderService;
@@ -55,8 +57,6 @@ import org.onosproject.net.provider.AbstractProviderService;
import org.slf4j.Logger;
import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -102,18 +102,18 @@ public class PacketManager
private final DeviceListener deviceListener = new InternalDeviceListener();
- private final Map<Integer, PacketProcessor> processors = new ConcurrentHashMap<>();
+ private final List<ProcessorEntry> processors = Lists.newCopyOnWriteArrayList();
private ApplicationId appId;
@Activate
public void activate() {
eventHandlingExecutor = Executors.newSingleThreadExecutor(
- groupedThreads("onos/net/packet", "event-handler"));
+ groupedThreads("onos/net/packet", "event-handler"));
appId = coreService.getAppId(CoreService.CORE_APP_NAME);
store.setDelegate(delegate);
deviceService.addListener(deviceListener);
- // TODO: Should we request packets for all existing devices? I believe we should.
+ store.existingRequests().forEach(this::pushToAllDevices);
log.info("Started");
}
@@ -129,19 +129,35 @@ public class PacketManager
public void addProcessor(PacketProcessor processor, int priority) {
checkPermission(PACKET_EVENT);
checkNotNull(processor, "Processor cannot be null");
- processors.put(priority, processor);
+ ProcessorEntry entry = new ProcessorEntry(processor, priority);
+
+ // Insert the new processor according to its priority.
+ int i = 0;
+ for (; i < processors.size(); i++) {
+ if (priority < processors.get(i).priority()) {
+ break;
+ }
+ }
+ processors.add(i, entry);
}
@Override
public void removeProcessor(PacketProcessor processor) {
checkPermission(PACKET_EVENT);
checkNotNull(processor, "Processor cannot be null");
- processors.values().remove(processor);
+
+ // Remove the processor entry.
+ for (int i = 0; i < processors.size(); i++) {
+ if (processors.get(i).processor() == processor) {
+ processors.remove(i);
+ break;
+ }
+ }
}
@Override
- public Map<Integer, PacketProcessor> getProcessors() {
- return ImmutableMap.copyOf(processors);
+ public List<PacketProcessorEntry> getProcessors() {
+ return ImmutableList.copyOf(processors);
}
@Override
@@ -152,9 +168,7 @@ public class PacketManager
checkNotNull(appId, "Application ID cannot be null");
PacketRequest request = new DefaultPacketRequest(selector, priority, appId);
- if (store.requestPackets(request)) {
- pushToAllDevices(request);
- }
+ store.requestPackets(request);
}
@Override
@@ -165,9 +179,7 @@ public class PacketManager
checkNotNull(appId, "Application ID cannot be null");
PacketRequest request = new DefaultPacketRequest(selector, priority, appId);
- if (store.cancelPackets(request)) {
- removeFromAllDevices(request);
- }
+ store.cancelPackets(request);
}
@Override
@@ -176,6 +188,18 @@ public class PacketManager
}
/**
+ * Pushes all rules to the specified device.
+ *
+ * @param device device on which to install packet request flows
+ */
+ private void pushRulesToDevice(Device device) {
+ log.debug("Pushing packet requests to device {}", device.id());
+ for (PacketRequest request : store.existingRequests()) {
+ pushRule(device, request);
+ }
+ }
+
+ /**
* Pushes a packet request flow rule to all devices.
*
* @param request the packet request
@@ -187,16 +211,13 @@ public class PacketManager
}
}
-
/**
* Removes packet request flow rule from all devices.
*
* @param request the packet request
*/
private void removeFromAllDevices(PacketRequest request) {
- for (Device device : deviceService.getDevices()) {
- removeRule(device, request);
- }
+ deviceService.getAvailableDevices().forEach(d -> removeRule(d, request));
}
/**
@@ -232,7 +253,6 @@ public class PacketManager
if (!device.type().equals(Device.Type.SWITCH)) {
return;
}
-
ForwardingObjective forwarding = createBuilder(request)
.remove(new ObjectiveContext() {
@Override
@@ -241,7 +261,6 @@ public class PacketManager
request, device.id(), error);
}
});
-
objectiveService.forward(device.id(), forwarding);
}
@@ -263,12 +282,10 @@ public class PacketManager
}
private void localEmit(OutboundPacket packet) {
- final Device device = deviceService.getDevice(packet.sendThrough());
-
+ Device device = deviceService.getDevice(packet.sendThrough());
if (device == null) {
return;
}
-
PacketProvider packetProvider = getProvider(device.providerId());
if (packetProvider != null) {
packetProvider.emit(packet);
@@ -280,7 +297,9 @@ public class PacketManager
return new InternalPacketProviderService(provider);
}
- // Personalized packet provider service issued to the supplied provider.
+ /**
+ * Personalized packet provider service issued to the supplied provider.
+ */
private class InternalPacketProviderService
extends AbstractProviderService<PacketProvider>
implements PacketProviderService {
@@ -292,8 +311,10 @@ public class PacketManager
@Override
public void processPacket(PacketContext context) {
// TODO filter packets sent to processors based on registrations
- for (PacketProcessor processor : processors.values()) {
- processor.process(context);
+ for (ProcessorEntry entry : processors) {
+ long start = System.nanoTime();
+ entry.processor().process(context);
+ entry.addNanos(System.nanoTime() - start);
}
}
@@ -307,6 +328,16 @@ public class PacketManager
public void notify(PacketEvent event) {
localEmit(event.subject());
}
+
+ @Override
+ public void requestPackets(PacketRequest request) {
+ pushToAllDevices(request);
+ }
+
+ @Override
+ public void cancelPackets(PacketRequest request) {
+ removeFromAllDevices(request);
+ }
}
/**
@@ -319,17 +350,14 @@ public class PacketManager
try {
Device device = event.subject();
switch (event.type()) {
- case DEVICE_ADDED:
- case DEVICE_AVAILABILITY_CHANGED:
- if (deviceService.isAvailable(event.subject().id())) {
- log.debug("Pushing packet requests to device {}", event.subject().id());
- for (PacketRequest request : store.existingRequests()) {
- pushRule(device, request);
+ case DEVICE_ADDED:
+ case DEVICE_AVAILABILITY_CHANGED:
+ if (deviceService.isAvailable(event.subject().id())) {
+ pushRulesToDevice(device);
}
- }
- break;
- default:
- break;
+ break;
+ default:
+ break;
}
} catch (Exception e) {
log.warn("Failed to process {}", event, e);
@@ -338,4 +366,48 @@ public class PacketManager
}
}
+ /**
+ * Entity for tracking stats for a packet processor.
+ */
+ private class ProcessorEntry implements PacketProcessorEntry {
+ private final PacketProcessor processor;
+ private final int priority;
+ private long invocations = 0;
+ private long nanos = 0;
+
+ public ProcessorEntry(PacketProcessor processor, int priority) {
+ this.processor = processor;
+ this.priority = priority;
+ }
+
+ @Override
+ public PacketProcessor processor() {
+ return processor;
+ }
+
+ @Override
+ public int priority() {
+ return priority;
+ }
+
+ @Override
+ public long invocations() {
+ return invocations;
+ }
+
+ @Override
+ public long totalNanos() {
+ return nanos;
+ }
+
+ @Override
+ public long averageNanos() {
+ return invocations > 0 ? nanos / invocations : 0;
+ }
+
+ void addNanos(long nanos) {
+ this.nanos += nanos;
+ this.invocations++;
+ }
+ }
}
diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/statistic/impl/FlowStatisticManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/statistic/impl/FlowStatisticManager.java
new file mode 100644
index 00000000..6515ef31
--- /dev/null
+++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/statistic/impl/FlowStatisticManager.java
@@ -0,0 +1,634 @@
+/*
+ * 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.statistic.impl;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableSet;
+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.onosproject.cli.Comparators;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.Device;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.flow.DefaultTypedFlowEntry;
+import org.onosproject.net.flow.FlowEntry;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleEvent;
+import org.onosproject.net.flow.FlowRuleListener;
+import org.onosproject.net.flow.FlowRuleService;
+import org.onosproject.net.flow.TypedStoredFlowEntry;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.statistic.DefaultLoad;
+import org.onosproject.net.statistic.FlowStatisticService;
+import org.onosproject.net.statistic.Load;
+import org.onosproject.net.statistic.FlowStatisticStore;
+import org.onosproject.net.statistic.SummaryFlowEntryWithLoad;
+import org.onosproject.net.statistic.TypedFlowEntryWithLoad;
+
+import org.slf4j.Logger;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.stream.Collectors;
+
+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.*;
+
+/**
+ * Provides an implementation of the Flow Statistic Service.
+ */
+@Component(immediate = true, enabled = true)
+@Service
+public class FlowStatisticManager implements FlowStatisticService {
+ private final Logger log = getLogger(getClass());
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected FlowRuleService flowRuleService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected FlowStatisticStore flowStatisticStore;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected DeviceService deviceService;
+
+ private final InternalFlowRuleStatsListener frListener = new InternalFlowRuleStatsListener();
+
+ @Activate
+ public void activate() {
+ flowRuleService.addListener(frListener);
+ log.info("Started");
+ }
+
+ @Deactivate
+ public void deactivate() {
+ flowRuleService.removeListener(frListener);
+ log.info("Stopped");
+ }
+
+ @Override
+ public Map<ConnectPoint, SummaryFlowEntryWithLoad> loadSummary(Device device) {
+ checkPermission(STATISTIC_READ);
+
+ Map<ConnectPoint, SummaryFlowEntryWithLoad> summaryLoad = new TreeMap<>(Comparators.CONNECT_POINT_COMPARATOR);
+
+ if (device == null) {
+ return summaryLoad;
+ }
+
+ List<Port> ports = new ArrayList<>(deviceService.getPorts(device.id()));
+
+ for (Port port : ports) {
+ ConnectPoint cp = new ConnectPoint(device.id(), port.number());
+ SummaryFlowEntryWithLoad sfe = loadSummaryPortInternal(cp);
+ summaryLoad.put(cp, sfe);
+ }
+
+ return summaryLoad;
+ }
+
+ @Override
+ public SummaryFlowEntryWithLoad loadSummary(Device device, PortNumber pNumber) {
+ checkPermission(STATISTIC_READ);
+
+ ConnectPoint cp = new ConnectPoint(device.id(), pNumber);
+ return loadSummaryPortInternal(cp);
+ }
+
+ @Override
+ public Map<ConnectPoint, List<TypedFlowEntryWithLoad>> loadAllByType(Device device,
+ TypedStoredFlowEntry.FlowLiveType liveType,
+ Instruction.Type instType) {
+ checkPermission(STATISTIC_READ);
+
+ Map<ConnectPoint, List<TypedFlowEntryWithLoad>> allLoad = new TreeMap<>(Comparators.CONNECT_POINT_COMPARATOR);
+
+ if (device == null) {
+ return allLoad;
+ }
+
+ List<Port> ports = new ArrayList<>(deviceService.getPorts(device.id()));
+
+ for (Port port : ports) {
+ ConnectPoint cp = new ConnectPoint(device.id(), port.number());
+ List<TypedFlowEntryWithLoad> tfel = loadAllPortInternal(cp, liveType, instType);
+ allLoad.put(cp, tfel);
+ }
+
+ return allLoad;
+ }
+
+ @Override
+ public List<TypedFlowEntryWithLoad> loadAllByType(Device device, PortNumber pNumber,
+ TypedStoredFlowEntry.FlowLiveType liveType,
+ Instruction.Type instType) {
+ checkPermission(STATISTIC_READ);
+
+ ConnectPoint cp = new ConnectPoint(device.id(), pNumber);
+ return loadAllPortInternal(cp, liveType, instType);
+ }
+
+ @Override
+ public Map<ConnectPoint, List<TypedFlowEntryWithLoad>> loadTopnByType(Device device,
+ TypedStoredFlowEntry.FlowLiveType liveType,
+ Instruction.Type instType,
+ int topn) {
+ checkPermission(STATISTIC_READ);
+
+ Map<ConnectPoint, List<TypedFlowEntryWithLoad>> allLoad = new TreeMap<>(Comparators.CONNECT_POINT_COMPARATOR);
+
+ if (device == null) {
+ return allLoad;
+ }
+
+ List<Port> ports = new ArrayList<>(deviceService.getPorts(device.id()));
+
+ for (Port port : ports) {
+ ConnectPoint cp = new ConnectPoint(device.id(), port.number());
+ List<TypedFlowEntryWithLoad> tfel = loadTopnPortInternal(cp, liveType, instType, topn);
+ allLoad.put(cp, tfel);
+ }
+
+ return allLoad;
+ }
+
+ @Override
+ public List<TypedFlowEntryWithLoad> loadTopnByType(Device device, PortNumber pNumber,
+ TypedStoredFlowEntry.FlowLiveType liveType,
+ Instruction.Type instType,
+ int topn) {
+ checkPermission(STATISTIC_READ);
+
+ ConnectPoint cp = new ConnectPoint(device.id(), pNumber);
+ return loadTopnPortInternal(cp, liveType, instType, topn);
+ }
+
+ private SummaryFlowEntryWithLoad loadSummaryPortInternal(ConnectPoint cp) {
+ checkPermission(STATISTIC_READ);
+
+ Set<FlowEntry> currentStats;
+ Set<FlowEntry> previousStats;
+
+ TypedStatistics typedStatistics;
+ synchronized (flowStatisticStore) {
+ currentStats = flowStatisticStore.getCurrentFlowStatistic(cp);
+ if (currentStats == null) {
+ return new SummaryFlowEntryWithLoad(cp, new DefaultLoad());
+ }
+ previousStats = flowStatisticStore.getPreviousFlowStatistic(cp);
+ if (previousStats == null) {
+ return new SummaryFlowEntryWithLoad(cp, new DefaultLoad());
+ }
+ // copy to local flow entry
+ typedStatistics = new TypedStatistics(currentStats, previousStats);
+
+ // Check for validity of this stats data
+ checkLoadValidity(currentStats, previousStats);
+ }
+
+ // current and previous set is not empty!
+ Set<FlowEntry> currentSet = typedStatistics.current();
+ Set<FlowEntry> previousSet = typedStatistics.previous();
+ Load totalLoad = new DefaultLoad(aggregateBytesSet(currentSet), aggregateBytesSet(previousSet),
+ TypedFlowEntryWithLoad.avgPollInterval());
+
+ Map<FlowRule, TypedStoredFlowEntry> currentMap;
+ Map<FlowRule, TypedStoredFlowEntry> previousMap;
+
+ currentMap = typedStatistics.currentImmediate();
+ previousMap = typedStatistics.previousImmediate();
+ Load immediateLoad = new DefaultLoad(aggregateBytesMap(currentMap), aggregateBytesMap(previousMap),
+ TypedFlowEntryWithLoad.shortPollInterval());
+
+ currentMap = typedStatistics.currentShort();
+ previousMap = typedStatistics.previousShort();
+ Load shortLoad = new DefaultLoad(aggregateBytesMap(currentMap), aggregateBytesMap(previousMap),
+ TypedFlowEntryWithLoad.shortPollInterval());
+
+ currentMap = typedStatistics.currentMid();
+ previousMap = typedStatistics.previousMid();
+ Load midLoad = new DefaultLoad(aggregateBytesMap(currentMap), aggregateBytesMap(previousMap),
+ TypedFlowEntryWithLoad.midPollInterval());
+
+ currentMap = typedStatistics.currentLong();
+ previousMap = typedStatistics.previousLong();
+ Load longLoad = new DefaultLoad(aggregateBytesMap(currentMap), aggregateBytesMap(previousMap),
+ TypedFlowEntryWithLoad.longPollInterval());
+
+ currentMap = typedStatistics.currentUnknown();
+ previousMap = typedStatistics.previousUnknown();
+ Load unknownLoad = new DefaultLoad(aggregateBytesMap(currentMap), aggregateBytesMap(previousMap),
+ TypedFlowEntryWithLoad.avgPollInterval());
+
+ return new SummaryFlowEntryWithLoad(cp, totalLoad, immediateLoad, shortLoad, midLoad, longLoad, unknownLoad);
+ }
+
+ private List<TypedFlowEntryWithLoad> loadAllPortInternal(ConnectPoint cp,
+ TypedStoredFlowEntry.FlowLiveType liveType,
+ Instruction.Type instType) {
+ checkPermission(STATISTIC_READ);
+
+ List<TypedFlowEntryWithLoad> retTFEL = new ArrayList<>();
+
+ Set<FlowEntry> currentStats;
+ Set<FlowEntry> previousStats;
+
+ TypedStatistics typedStatistics;
+ synchronized (flowStatisticStore) {
+ currentStats = flowStatisticStore.getCurrentFlowStatistic(cp);
+ if (currentStats == null) {
+ return retTFEL;
+ }
+ previousStats = flowStatisticStore.getPreviousFlowStatistic(cp);
+ if (previousStats == null) {
+ return retTFEL;
+ }
+ // copy to local flow entry set
+ typedStatistics = new TypedStatistics(currentStats, previousStats);
+
+ // Check for validity of this stats data
+ checkLoadValidity(currentStats, previousStats);
+ }
+
+ // current and previous set is not empty!
+ boolean isAllLiveType = (liveType == null ? true : false); // null is all live type
+ boolean isAllInstType = (instType == null ? true : false); // null is all inst type
+
+ Map<FlowRule, TypedStoredFlowEntry> currentMap;
+ Map<FlowRule, TypedStoredFlowEntry> previousMap;
+
+ if (isAllLiveType || liveType == TypedStoredFlowEntry.FlowLiveType.IMMEDIATE_FLOW) {
+ currentMap = typedStatistics.currentImmediate();
+ previousMap = typedStatistics.previousImmediate();
+
+ List<TypedFlowEntryWithLoad> fel = typedFlowEntryLoadByInstInternal(cp, currentMap, previousMap,
+ isAllInstType, instType, TypedFlowEntryWithLoad.shortPollInterval());
+ if (fel.size() > 0) {
+ retTFEL.addAll(fel);
+ }
+ }
+
+ if (isAllLiveType || liveType == TypedStoredFlowEntry.FlowLiveType.SHORT_FLOW) {
+ currentMap = typedStatistics.currentShort();
+ previousMap = typedStatistics.previousShort();
+
+ List<TypedFlowEntryWithLoad> fel = typedFlowEntryLoadByInstInternal(cp, currentMap, previousMap,
+ isAllInstType, instType, TypedFlowEntryWithLoad.shortPollInterval());
+ if (fel.size() > 0) {
+ retTFEL.addAll(fel);
+ }
+ }
+
+ if (isAllLiveType || liveType == TypedStoredFlowEntry.FlowLiveType.MID_FLOW) {
+ currentMap = typedStatistics.currentMid();
+ previousMap = typedStatistics.previousMid();
+
+ List<TypedFlowEntryWithLoad> fel = typedFlowEntryLoadByInstInternal(cp, currentMap, previousMap,
+ isAllInstType, instType, TypedFlowEntryWithLoad.midPollInterval());
+ if (fel.size() > 0) {
+ retTFEL.addAll(fel);
+ }
+ }
+
+ if (isAllLiveType || liveType == TypedStoredFlowEntry.FlowLiveType.LONG_FLOW) {
+ currentMap = typedStatistics.currentLong();
+ previousMap = typedStatistics.previousLong();
+
+ List<TypedFlowEntryWithLoad> fel = typedFlowEntryLoadByInstInternal(cp, currentMap, previousMap,
+ isAllInstType, instType, TypedFlowEntryWithLoad.longPollInterval());
+ if (fel.size() > 0) {
+ retTFEL.addAll(fel);
+ }
+ }
+
+ if (isAllLiveType || liveType == TypedStoredFlowEntry.FlowLiveType.UNKNOWN_FLOW) {
+ currentMap = typedStatistics.currentUnknown();
+ previousMap = typedStatistics.previousUnknown();
+
+ List<TypedFlowEntryWithLoad> fel = typedFlowEntryLoadByInstInternal(cp, currentMap, previousMap,
+ isAllInstType, instType, TypedFlowEntryWithLoad.avgPollInterval());
+ if (fel.size() > 0) {
+ retTFEL.addAll(fel);
+ }
+ }
+
+ return retTFEL;
+ }
+
+ private List<TypedFlowEntryWithLoad> typedFlowEntryLoadByInstInternal(ConnectPoint cp,
+ Map<FlowRule, TypedStoredFlowEntry> currentMap,
+ Map<FlowRule, TypedStoredFlowEntry> previousMap,
+ boolean isAllInstType,
+ Instruction.Type instType,
+ int liveTypePollInterval) {
+ List<TypedFlowEntryWithLoad> fel = new ArrayList<>();
+
+ for (TypedStoredFlowEntry tfe : currentMap.values()) {
+ if (isAllInstType ||
+ tfe.treatment().allInstructions().stream().
+ filter(i -> i.type() == instType).
+ findAny().isPresent()) {
+ long currentBytes = tfe.bytes();
+ long previousBytes = previousMap.getOrDefault(tfe, new DefaultTypedFlowEntry((FlowRule) tfe)).bytes();
+ Load fLoad = new DefaultLoad(currentBytes, previousBytes, liveTypePollInterval);
+ fel.add(new TypedFlowEntryWithLoad(cp, tfe, fLoad));
+ }
+ }
+
+ return fel;
+ }
+
+ private List<TypedFlowEntryWithLoad> loadTopnPortInternal(ConnectPoint cp,
+ TypedStoredFlowEntry.FlowLiveType liveType,
+ Instruction.Type instType,
+ int topn) {
+ List<TypedFlowEntryWithLoad> fel = loadAllPortInternal(cp, liveType, instType);
+
+ // Sort with descending order of load
+ List<TypedFlowEntryWithLoad> tfel =
+ fel.stream().sorted(Comparators.TYPEFLOWENTRY_WITHLOAD_COMPARATOR).
+ limit(topn).collect(Collectors.toList());
+
+ return tfel;
+ }
+
+ private long aggregateBytesSet(Set<FlowEntry> setFE) {
+ return setFE.stream().mapToLong(FlowEntry::bytes).sum();
+ }
+
+ private long aggregateBytesMap(Map<FlowRule, TypedStoredFlowEntry> mapFE) {
+ return mapFE.values().stream().mapToLong(FlowEntry::bytes).sum();
+ }
+
+ /**
+ * Internal data class holding two set of typed flow entries.
+ */
+ private static class TypedStatistics {
+ private final ImmutableSet<FlowEntry> currentAll;
+ private final ImmutableSet<FlowEntry> previousAll;
+
+ private final Map<FlowRule, TypedStoredFlowEntry> currentImmediate = new HashMap<>();
+ private final Map<FlowRule, TypedStoredFlowEntry> previousImmediate = new HashMap<>();
+
+ private final Map<FlowRule, TypedStoredFlowEntry> currentShort = new HashMap<>();
+ private final Map<FlowRule, TypedStoredFlowEntry> previousShort = new HashMap<>();
+
+ private final Map<FlowRule, TypedStoredFlowEntry> currentMid = new HashMap<>();
+ private final Map<FlowRule, TypedStoredFlowEntry> previousMid = new HashMap<>();
+
+ private final Map<FlowRule, TypedStoredFlowEntry> currentLong = new HashMap<>();
+ private final Map<FlowRule, TypedStoredFlowEntry> previousLong = new HashMap<>();
+
+ private final Map<FlowRule, TypedStoredFlowEntry> currentUnknown = new HashMap<>();
+ private final Map<FlowRule, TypedStoredFlowEntry> previousUnknown = new HashMap<>();
+
+ public TypedStatistics(Set<FlowEntry> current, Set<FlowEntry> previous) {
+ this.currentAll = ImmutableSet.copyOf(checkNotNull(current));
+ this.previousAll = ImmutableSet.copyOf(checkNotNull(previous));
+
+ currentAll.forEach(fe -> {
+ TypedStoredFlowEntry tfe = TypedFlowEntryWithLoad.newTypedStoredFlowEntry(fe);
+
+ switch (tfe.flowLiveType()) {
+ case IMMEDIATE_FLOW:
+ currentImmediate.put(fe, tfe);
+ break;
+ case SHORT_FLOW:
+ currentShort.put(fe, tfe);
+ break;
+ case MID_FLOW:
+ currentMid.put(fe, tfe);
+ break;
+ case LONG_FLOW:
+ currentLong.put(fe, tfe);
+ break;
+ default:
+ currentUnknown.put(fe, tfe);
+ break;
+ }
+ });
+
+ previousAll.forEach(fe -> {
+ TypedStoredFlowEntry tfe = TypedFlowEntryWithLoad.newTypedStoredFlowEntry(fe);
+
+ switch (tfe.flowLiveType()) {
+ case IMMEDIATE_FLOW:
+ if (currentImmediate.containsKey(fe)) {
+ previousImmediate.put(fe, tfe);
+ } else if (currentShort.containsKey(fe)) {
+ previousShort.put(fe, tfe);
+ } else if (currentMid.containsKey(fe)) {
+ previousMid.put(fe, tfe);
+ } else if (currentLong.containsKey(fe)) {
+ previousLong.put(fe, tfe);
+ } else {
+ previousUnknown.put(fe, tfe);
+ }
+ break;
+ case SHORT_FLOW:
+ if (currentShort.containsKey(fe)) {
+ previousShort.put(fe, tfe);
+ } else if (currentMid.containsKey(fe)) {
+ previousMid.put(fe, tfe);
+ } else if (currentLong.containsKey(fe)) {
+ previousLong.put(fe, tfe);
+ } else {
+ previousUnknown.put(fe, tfe);
+ }
+ break;
+ case MID_FLOW:
+ if (currentMid.containsKey(fe)) {
+ previousMid.put(fe, tfe);
+ } else if (currentLong.containsKey(fe)) {
+ previousLong.put(fe, tfe);
+ } else {
+ previousUnknown.put(fe, tfe);
+ }
+ break;
+ case LONG_FLOW:
+ if (currentLong.containsKey(fe)) {
+ previousLong.put(fe, tfe);
+ } else {
+ previousUnknown.put(fe, tfe);
+ }
+ break;
+ default:
+ previousUnknown.put(fe, tfe);
+ break;
+ }
+ });
+ }
+
+ /**
+ * Returns flow entries as the current value.
+ *
+ * @return flow entries as the current value
+ */
+ public ImmutableSet<FlowEntry> current() {
+ return currentAll;
+ }
+
+ /**
+ * Returns flow entries as the previous value.
+ *
+ * @return flow entries as the previous value
+ */
+ public ImmutableSet<FlowEntry> previous() {
+ return previousAll;
+ }
+
+ public Map<FlowRule, TypedStoredFlowEntry> currentImmediate() {
+ return currentImmediate;
+ }
+ public Map<FlowRule, TypedStoredFlowEntry> previousImmediate() {
+ return previousImmediate;
+ }
+ public Map<FlowRule, TypedStoredFlowEntry> currentShort() {
+ return currentShort;
+ }
+ public Map<FlowRule, TypedStoredFlowEntry> previousShort() {
+ return previousShort;
+ }
+ public Map<FlowRule, TypedStoredFlowEntry> currentMid() {
+ return currentMid;
+ }
+ public Map<FlowRule, TypedStoredFlowEntry> previousMid() {
+ return previousMid;
+ }
+ public Map<FlowRule, TypedStoredFlowEntry> currentLong() {
+ return currentLong;
+ }
+ public Map<FlowRule, TypedStoredFlowEntry> previousLong() {
+ return previousLong;
+ }
+ public Map<FlowRule, TypedStoredFlowEntry> currentUnknown() {
+ return currentUnknown;
+ }
+ public Map<FlowRule, TypedStoredFlowEntry> previousUnknown() {
+ return previousUnknown;
+ }
+
+ /**
+ * Validates values are not empty.
+ *
+ * @return false if either of the sets is empty. Otherwise, true.
+ */
+ public boolean isValid() {
+ return !(currentAll.isEmpty() || previousAll.isEmpty());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(currentAll, previousAll);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof TypedStatistics)) {
+ return false;
+ }
+ final TypedStatistics other = (TypedStatistics) obj;
+ return Objects.equals(this.currentAll, other.currentAll) &&
+ Objects.equals(this.previousAll, other.previousAll);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("current", currentAll)
+ .add("previous", previousAll)
+ .toString();
+ }
+ }
+
+ private void checkLoadValidity(Set<FlowEntry> current, Set<FlowEntry> previous) {
+ current.stream().forEach(c -> {
+ FlowEntry f = previous.stream().filter(p -> c.equals(p)).
+ findAny().orElse(null);
+ if (f != null && c.bytes() < f.bytes()) {
+ log.debug("FlowStatisticManager:checkLoadValidity():" +
+ "Error: " + c + " :Previous bytes=" + f.bytes() +
+ " is larger than current bytes=" + c.bytes() + " !!!");
+ }
+ });
+
+ }
+
+ /**
+ * Creates a predicate that checks the instruction type of a flow entry is the same as
+ * the specified instruction type.
+ *
+ * @param instType instruction type to be checked
+ * @return predicate
+ */
+ private static Predicate<FlowEntry> hasInstructionType(Instruction.Type instType) {
+ return new Predicate<FlowEntry>() {
+ @Override
+ public boolean apply(FlowEntry flowEntry) {
+ List<Instruction> allInstructions = flowEntry.treatment().allInstructions();
+
+ return allInstructions.stream().filter(i -> i.type() == instType).findAny().isPresent();
+ }
+ };
+ }
+
+ /**
+ * Internal flow rule event listener for FlowStatisticManager.
+ */
+ private class InternalFlowRuleStatsListener implements FlowRuleListener {
+
+ @Override
+ public void event(FlowRuleEvent event) {
+ FlowRule rule = event.subject();
+ switch (event.type()) {
+ case RULE_ADDED:
+ if (rule instanceof FlowEntry) {
+ flowStatisticStore.addFlowStatistic((FlowEntry) rule);
+ }
+ break;
+ case RULE_UPDATED:
+ flowStatisticStore.updateFlowStatistic((FlowEntry) rule);
+ break;
+ case RULE_ADD_REQUESTED:
+ break;
+ case RULE_REMOVE_REQUESTED:
+ break;
+ case RULE_REMOVED:
+ flowStatisticStore.removeFlowStatistic(rule);
+ break;
+ default:
+ log.warn("Unknown flow rule event {}", event);
+ }
+ }
+ }
+}
diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/topology/impl/PathManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/topology/impl/PathManager.java
index a238c7fb..8347ee38 100644
--- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/topology/impl/PathManager.java
+++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/topology/impl/PathManager.java
@@ -27,6 +27,8 @@ import org.apache.felix.scr.annotations.Service;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DefaultEdgeLink;
import org.onosproject.net.DefaultPath;
+import org.onosproject.net.DisjointPath;
+import org.onosproject.net.DefaultDisjointPath;
import org.onosproject.net.DeviceId;
import org.onosproject.net.EdgeLink;
import org.onosproject.net.ElementId;
@@ -46,6 +48,8 @@ import org.slf4j.Logger;
import java.util.List;
import java.util.Set;
+import java.util.Map;
+
import static com.google.common.base.Preconditions.checkNotNull;
import static org.slf4j.LoggerFactory.getLogger;
@@ -128,6 +132,84 @@ public class PathManager implements PathService {
return edgeToEdgePaths(srcEdge, dstEdge, paths);
}
+ @Override
+ public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst) {
+ return getDisjointPaths(src, dst, (LinkWeight) null);
+ }
+
+ @Override
+ public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst, LinkWeight weight) {
+ checkNotNull(src, ELEMENT_ID_NULL);
+ checkNotNull(dst, ELEMENT_ID_NULL);
+
+ // Get the source and destination edge locations
+ EdgeLink srcEdge = getEdgeLink(src, true);
+ EdgeLink dstEdge = getEdgeLink(dst, false);
+
+ // If either edge is null, bail with no paths.
+ if (srcEdge == null || dstEdge == null) {
+ return ImmutableSet.of();
+ }
+
+ DeviceId srcDevice = srcEdge != NOT_HOST ? srcEdge.dst().deviceId() : (DeviceId) src;
+ DeviceId dstDevice = dstEdge != NOT_HOST ? dstEdge.src().deviceId() : (DeviceId) dst;
+
+ // If the source and destination are on the same edge device, there
+ // is just one path, so build it and return it.
+ if (srcDevice.equals(dstDevice)) {
+ return edgeToEdgePathsDisjoint(srcEdge, dstEdge);
+ }
+
+ // Otherwise get all paths between the source and destination edge
+ // devices.
+ Topology topology = topologyService.currentTopology();
+ Set<DisjointPath> paths = weight == null ?
+ topologyService.getDisjointPaths(topology, srcDevice, dstDevice) :
+ topologyService.getDisjointPaths(topology, srcDevice, dstDevice, weight);
+
+ return edgeToEdgePathsDisjoint(srcEdge, dstEdge, paths);
+ }
+
+ @Override
+ public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst,
+ Map<Link, Object> riskProfile) {
+ return getDisjointPaths(src, dst, null, riskProfile);
+ }
+
+ @Override
+ public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst, LinkWeight weight,
+ Map<Link, Object> riskProfile) {
+ checkNotNull(src, ELEMENT_ID_NULL);
+ checkNotNull(dst, ELEMENT_ID_NULL);
+
+ // Get the source and destination edge locations
+ EdgeLink srcEdge = getEdgeLink(src, true);
+ EdgeLink dstEdge = getEdgeLink(dst, false);
+
+ // If either edge is null, bail with no paths.
+ if (srcEdge == null || dstEdge == null) {
+ return ImmutableSet.of();
+ }
+
+ DeviceId srcDevice = srcEdge != NOT_HOST ? srcEdge.dst().deviceId() : (DeviceId) src;
+ DeviceId dstDevice = dstEdge != NOT_HOST ? dstEdge.src().deviceId() : (DeviceId) dst;
+
+ // If the source and destination are on the same edge device, there
+ // is just one path, so build it and return it.
+ if (srcDevice.equals(dstDevice)) {
+ return edgeToEdgePathsDisjoint(srcEdge, dstEdge);
+ }
+
+ // Otherwise get all paths between the source and destination edge
+ // devices.
+ Topology topology = topologyService.currentTopology();
+ Set<DisjointPath> paths = weight == null ?
+ topologyService.getDisjointPaths(topology, srcDevice, dstDevice, riskProfile) :
+ topologyService.getDisjointPaths(topology, srcDevice, dstDevice, weight, riskProfile);
+
+ return edgeToEdgePathsDisjoint(srcEdge, dstEdge, paths);
+ }
+
// Finds the host edge link if the element ID is a host id of an existing
// host. Otherwise, if the host does not exist, it returns null and if
// the element ID is not a host ID, returns NOT_HOST edge link.
@@ -162,6 +244,20 @@ public class PathManager implements PathService {
return endToEndPaths;
}
+ private Set<DisjointPath> edgeToEdgePathsDisjoint(EdgeLink srcLink, EdgeLink dstLink) {
+ Set<DisjointPath> endToEndPaths = Sets.newHashSetWithExpectedSize(1);
+ endToEndPaths.add(edgeToEdgePathD(srcLink, dstLink, null));
+ return endToEndPaths;
+ }
+
+ private Set<DisjointPath> edgeToEdgePathsDisjoint(EdgeLink srcLink, EdgeLink dstLink, Set<DisjointPath> paths) {
+ Set<DisjointPath> endToEndPaths = Sets.newHashSetWithExpectedSize(paths.size());
+ for (DisjointPath path : paths) {
+ endToEndPaths.add(edgeToEdgePathD(srcLink, dstLink, path));
+ }
+ return endToEndPaths;
+ }
+
// Produces a direct edge-to-edge path.
private Path edgeToEdgePath(EdgeLink srcLink, EdgeLink dstLink, Path path) {
List<Link> links = Lists.newArrayListWithCapacity(2);
@@ -179,6 +275,13 @@ public class PathManager implements PathService {
return new DefaultPath(PID, links, 2);
}
+ // Produces a direct edge-to-edge path.
+ private DisjointPath edgeToEdgePathD(EdgeLink srcLink, EdgeLink dstLink, DisjointPath path) {
+ return new DefaultDisjointPath(PID, (DefaultPath) edgeToEdgePath(srcLink, dstLink, path.primary()),
+ (DefaultPath) edgeToEdgePath(srcLink, dstLink, path.backup()));
+ }
+
+
// Special value for edge link to represent that this is really not an
// edge link since the src or dst are really an infrastructure device.
private static class NotHost extends DefaultEdgeLink implements EdgeLink {
diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/topology/impl/TopologyManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/topology/impl/TopologyManager.java
index 04c4f1c1..4425e1c1 100644
--- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/topology/impl/TopologyManager.java
+++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/topology/impl/TopologyManager.java
@@ -21,6 +21,7 @@ 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.onosproject.net.DisjointPath;
import org.onosproject.net.provider.AbstractListenerProviderRegistry;
import org.onosproject.event.Event;
import org.onosproject.net.ConnectPoint;
@@ -46,6 +47,7 @@ import org.slf4j.Logger;
import java.util.List;
import java.util.Set;
+import java.util.Map;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.onosproject.security.AppGuard.checkPermission;
@@ -60,7 +62,7 @@ import static org.onosproject.security.AppPermission.Type.*;
@Service
public class TopologyManager
extends AbstractListenerProviderRegistry<TopologyEvent, TopologyListener,
- TopologyProvider, TopologyProviderService>
+ TopologyProvider, TopologyProviderService>
implements TopologyService, TopologyProviderRegistry {
public static final String TOPOLOGY_NULL = "Topology cannot be null";
@@ -68,6 +70,7 @@ public class TopologyManager
private static final String CLUSTER_ID_NULL = "Cluster ID cannot be null";
private static final String CLUSTER_NULL = "Topology cluster cannot be null";
public static final String CONNECTION_POINT_NULL = "Connection point cannot be null";
+ public static final String LINK_WEIGHT_NULL = "Link weight cannot be null";
private final Logger log = getLogger(getClass());
@@ -162,6 +165,44 @@ public class TopologyManager
}
@Override
+ public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst) {
+ checkNotNull(topology, TOPOLOGY_NULL);
+ checkNotNull(src, DEVICE_ID_NULL);
+ checkNotNull(dst, DEVICE_ID_NULL);
+ return store.getDisjointPaths(topology, src, dst);
+ }
+
+ @Override
+ public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src,
+ DeviceId dst, LinkWeight weight) {
+ checkNotNull(topology, TOPOLOGY_NULL);
+ checkNotNull(src, DEVICE_ID_NULL);
+ checkNotNull(dst, DEVICE_ID_NULL);
+ checkNotNull(weight, LINK_WEIGHT_NULL);
+ return store.getDisjointPaths(topology, src, dst, weight);
+ }
+
+ @Override
+ public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst,
+ Map<Link, Object> riskProfile) {
+ checkNotNull(topology, TOPOLOGY_NULL);
+ checkNotNull(src, DEVICE_ID_NULL);
+ checkNotNull(dst, DEVICE_ID_NULL);
+ return store.getDisjointPaths(topology, src, dst, riskProfile);
+ }
+
+ @Override
+ public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src,
+ DeviceId dst, LinkWeight weight,
+ Map<Link, Object> riskProfile) {
+ checkNotNull(topology, TOPOLOGY_NULL);
+ checkNotNull(src, DEVICE_ID_NULL);
+ checkNotNull(dst, DEVICE_ID_NULL);
+ checkNotNull(weight, LINK_WEIGHT_NULL);
+ return store.getDisjointPaths(topology, src, dst, weight, riskProfile);
+ }
+
+ @Override
public boolean isInfrastructure(Topology topology, ConnectPoint connectPoint) {
checkPermission(TOPOLOGY_READ);
checkNotNull(topology, TOPOLOGY_NULL);
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/cfg/impl/ComponentConfigLoaderTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/cfg/impl/ComponentConfigLoaderTest.java
new file mode 100644
index 00000000..0320cf77
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/cfg/impl/ComponentConfigLoaderTest.java
@@ -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.cfg.impl;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.io.Files;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.cfg.ComponentConfigAdapter;
+import org.slf4j.Logger;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Set;
+
+import static com.google.common.io.ByteStreams.toByteArray;
+import static com.google.common.io.Files.write;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * UnitTest for ComponentLoader.
+ */
+public class ComponentConfigLoaderTest {
+
+ static final File TEST_DIR = Files.createTempDir();
+
+ private static final String FOO_COMPONENT = "fooComponent";
+
+ private ComponentConfigLoader loader;
+
+ private TestConfigService service;
+
+ private final Logger log = getLogger(getClass());
+
+ /*
+ * Method to SetUp the test environment with test file, a config loader a service,
+ * and assign it to the loader.configService for the test.
+ */
+ @Before
+ public void setUp() {
+ ComponentConfigLoader.cfgFile = new File(TEST_DIR, "test.json");
+ loader = new ComponentConfigLoader();
+ service = new TestConfigService();
+ loader.configService = service;
+ }
+
+ /*
+ * Tests that the component in the json receives the correct configuration.
+ */
+ @Test
+ public void basics() throws IOException {
+ stageTestResource("basic.json");
+ loader.activate();
+ assertEquals("incorrect component", FOO_COMPONENT, service.component);
+ }
+
+ /*
+ * Tests that the component is null if the file has a bad configuration format
+ * for which it yielded an exception. Can't test the exception because it happens
+ * in a different thread.
+ */
+ @Test
+ public void badConfig() throws IOException {
+ stageTestResource("badConfig.json");
+ loader.activate();
+ assertNull("incorrect configuration", service.component);
+
+ }
+
+ /*
+ * Writes the necessary file for the tests in the temporary directory
+ */
+ static void stageTestResource(String name) throws IOException {
+ byte[] bytes = toByteArray(ComponentConfigLoaderTest.class.getResourceAsStream(name));
+ write(bytes, ComponentConfigLoader.cfgFile);
+ }
+
+ /*
+ * Mockup class for the config service.
+ */
+ private class TestConfigService extends ComponentConfigAdapter {
+
+ protected String component;
+ protected String name;
+ protected String value;
+
+ @Override
+ public Set<String> getComponentNames() {
+ return ImmutableSet.of(FOO_COMPONENT);
+ }
+
+ @Override
+ public void preSetProperty(String componentName, String name, String value) {
+ log.info("preSet");
+ this.component = componentName;
+ this.name = name;
+ this.value = value;
+
+ }
+
+ @Override
+ public void setProperty(String componentName, String name, String value) {
+ log.info("Set");
+ this.component = componentName;
+ this.name = name;
+ this.value = value;
+
+ }
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/host/impl/HostMonitorTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/host/impl/HostMonitorTest.java
index d167197a..3cd2ca2b 100644
--- a/framework/src/onos/core/net/src/test/java/org/onosproject/net/host/impl/HostMonitorTest.java
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/host/impl/HostMonitorTest.java
@@ -23,10 +23,12 @@ import org.junit.Before;
import org.junit.Test;
import org.onlab.packet.ARP;
import org.onlab.packet.Ethernet;
+import org.onlab.packet.IPv6;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
+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;
@@ -64,14 +66,22 @@ import static org.junit.Assert.assertTrue;
public class HostMonitorTest {
- private static final IpAddress TARGET_IP_ADDR =
+ private static final IpAddress TARGET_IPV4_ADDR =
IpAddress.valueOf("10.0.0.1");
- private static final IpAddress SOURCE_ADDR =
+ private static final IpAddress SOURCE_IPV4_ADDR =
IpAddress.valueOf("10.0.0.99");
private static final InterfaceIpAddress IA1 =
- new InterfaceIpAddress(SOURCE_ADDR, IpPrefix.valueOf("10.0.0.0/24"));
+ new InterfaceIpAddress(SOURCE_IPV4_ADDR, IpPrefix.valueOf("10.0.0.0/24"));
private MacAddress sourceMac = MacAddress.valueOf(1L);
+ private static final IpAddress TARGET_IPV6_ADDR =
+ IpAddress.valueOf("1000::1");
+ private static final IpAddress SOURCE_IPV6_ADDR =
+ IpAddress.valueOf("1000::f");
+ private static final InterfaceIpAddress IA2 =
+ new InterfaceIpAddress(SOURCE_IPV6_ADDR, IpPrefix.valueOf("1000::/64"));
+ private MacAddress sourceMac2 = MacAddress.valueOf(2L);
+
private EdgePortService edgePortService;
private HostMonitor hostMonitor;
@@ -90,7 +100,36 @@ public class HostMonitorTest {
}
@Test
- public void testMonitorHostExists() throws Exception {
+ public void testMonitorIpv4HostExists() throws Exception {
+ ProviderId id = new ProviderId("fake://", "id");
+
+ Host host = createMock(Host.class);
+ expect(host.providerId()).andReturn(id);
+ replay(host);
+
+ HostManager hostManager = createMock(HostManager.class);
+ expect(hostManager.getHostsByIp(TARGET_IPV4_ADDR))
+ .andReturn(Collections.singleton(host));
+ replay(hostManager);
+
+ HostProvider hostProvider = createMock(HostProvider.class);
+ expect(hostProvider.id()).andReturn(id).anyTimes();
+ hostProvider.triggerProbe(host);
+ expectLastCall().once();
+ replay(hostProvider);
+
+ hostMonitor = new HostMonitor(null, hostManager, null, edgePortService);
+
+ hostMonitor.registerHostProvider(hostProvider);
+ hostMonitor.addMonitoringFor(TARGET_IPV4_ADDR);
+
+ hostMonitor.run(null);
+
+ verify(hostProvider);
+ }
+
+ @Test
+ public void testMonitorIpv6HostExists() throws Exception {
ProviderId id = new ProviderId("fake://", "id");
Host host = createMock(Host.class);
@@ -98,7 +137,7 @@ public class HostMonitorTest {
replay(host);
HostManager hostManager = createMock(HostManager.class);
- expect(hostManager.getHostsByIp(TARGET_IP_ADDR))
+ expect(hostManager.getHostsByIp(TARGET_IPV6_ADDR))
.andReturn(Collections.singleton(host));
replay(hostManager);
@@ -111,7 +150,7 @@ public class HostMonitorTest {
hostMonitor = new HostMonitor(null, hostManager, null, edgePortService);
hostMonitor.registerHostProvider(hostProvider);
- hostMonitor.addMonitoringFor(TARGET_IP_ADDR);
+ hostMonitor.addMonitoringFor(TARGET_IPV6_ADDR);
hostMonitor.run(null);
@@ -119,7 +158,7 @@ public class HostMonitorTest {
}
@Test
- public void testMonitorHostDoesNotExist() throws Exception {
+ public void testMonitorIpv4HostDoesNotExist() throws Exception {
HostManager hostManager = createMock(HostManager.class);
@@ -140,12 +179,12 @@ public class HostMonitorTest {
ConnectPoint cp = new ConnectPoint(devId, portNum);
- expect(hostManager.getHostsByIp(TARGET_IP_ADDR))
+ expect(hostManager.getHostsByIp(TARGET_IPV4_ADDR))
.andReturn(Collections.emptySet()).anyTimes();
replay(hostManager);
InterfaceService interfaceService = createMock(InterfaceService.class);
- expect(interfaceService.getMatchingInterface(TARGET_IP_ADDR))
+ expect(interfaceService.getMatchingInterface(TARGET_IPV4_ADDR))
.andReturn(new Interface(cp, Collections.singleton(IA1), sourceMac, VlanId.NONE))
.anyTimes();
replay(interfaceService);
@@ -156,7 +195,7 @@ public class HostMonitorTest {
// Run the test
hostMonitor = new HostMonitor(packetService, hostManager, interfaceService, edgePortService);
- hostMonitor.addMonitoringFor(TARGET_IP_ADDR);
+ hostMonitor.addMonitoringFor(TARGET_IPV4_ADDR);
hostMonitor.run(null);
@@ -178,16 +217,85 @@ public class HostMonitorTest {
Ethernet eth = Ethernet.deserializer().deserialize(pktData, 0, pktData.length);
assertEquals(Ethernet.VLAN_UNTAGGED, eth.getVlanID());
ARP arp = (ARP) eth.getPayload();
- assertArrayEquals(SOURCE_ADDR.toOctets(),
+ assertArrayEquals(SOURCE_IPV4_ADDR.toOctets(),
arp.getSenderProtocolAddress());
assertArrayEquals(sourceMac.toBytes(),
arp.getSenderHardwareAddress());
- assertArrayEquals(TARGET_IP_ADDR.toOctets(),
+ assertArrayEquals(TARGET_IPV4_ADDR.toOctets(),
arp.getTargetProtocolAddress());
}
@Test
- public void testMonitorHostDoesNotExistWithVlan() throws Exception {
+ public void testMonitorIpv6HostDoesNotExist() throws Exception {
+
+ HostManager hostManager = createMock(HostManager.class);
+
+ DeviceId devId = DeviceId.deviceId("fake");
+
+ Device device = createMock(Device.class);
+ expect(device.id()).andReturn(devId).anyTimes();
+ replay(device);
+
+ PortNumber portNum = PortNumber.portNumber(2L);
+
+ Port port = createMock(Port.class);
+ expect(port.number()).andReturn(portNum).anyTimes();
+ replay(port);
+
+ TestDeviceService deviceService = new TestDeviceService();
+ deviceService.addDevice(device, Collections.singleton(port));
+
+ ConnectPoint cp = new ConnectPoint(devId, portNum);
+
+ expect(hostManager.getHostsByIp(TARGET_IPV6_ADDR))
+ .andReturn(Collections.emptySet()).anyTimes();
+ replay(hostManager);
+
+ InterfaceService interfaceService = createMock(InterfaceService.class);
+ expect(interfaceService.getMatchingInterface(TARGET_IPV6_ADDR))
+ .andReturn(new Interface(cp, Collections.singleton(IA2), sourceMac2, VlanId.NONE))
+ .anyTimes();
+ replay(interfaceService);
+
+ TestPacketService packetService = new TestPacketService();
+
+
+ // Run the test
+ hostMonitor = new HostMonitor(packetService, hostManager, interfaceService, edgePortService);
+
+ hostMonitor.addMonitoringFor(TARGET_IPV6_ADDR);
+ hostMonitor.run(null);
+
+
+ // Check that a packet was sent to our PacketService and that it has
+ // the properties we expect
+ assertEquals(1, packetService.packets.size());
+ OutboundPacket packet = packetService.packets.get(0);
+
+ // Check the output port is correct
+ assertEquals(1, packet.treatment().immediate().size());
+ Instruction instruction = packet.treatment().immediate().get(0);
+ assertTrue(instruction instanceof OutputInstruction);
+ OutputInstruction oi = (OutputInstruction) instruction;
+ assertEquals(portNum, oi.port());
+
+ // Check the output packet is correct (well the important bits anyway)
+ final byte[] pktData = new byte[packet.data().remaining()];
+ packet.data().get(pktData);
+ Ethernet eth = Ethernet.deserializer().deserialize(pktData, 0, pktData.length);
+ assertEquals(Ethernet.VLAN_UNTAGGED, eth.getVlanID());
+ IPv6 ipv6 = (IPv6) eth.getPayload();
+ assertArrayEquals(SOURCE_IPV6_ADDR.toOctets(), ipv6.getSourceAddress());
+
+ NeighborSolicitation ns =
+ (NeighborSolicitation) ipv6.getPayload().getPayload();
+ assertArrayEquals(sourceMac2.toBytes(), ns.getOptions().get(0).data());
+
+ assertArrayEquals(TARGET_IPV6_ADDR.toOctets(), ns.getTargetAddress());
+ }
+
+ @Test
+ public void testMonitorIpv4HostDoesNotExistWithVlan() throws Exception {
HostManager hostManager = createMock(HostManager.class);
@@ -209,12 +317,12 @@ public class HostMonitorTest {
ConnectPoint cp = new ConnectPoint(devId, portNum);
- expect(hostManager.getHostsByIp(TARGET_IP_ADDR))
+ expect(hostManager.getHostsByIp(TARGET_IPV4_ADDR))
.andReturn(Collections.emptySet()).anyTimes();
replay(hostManager);
InterfaceService interfaceService = createMock(InterfaceService.class);
- expect(interfaceService.getMatchingInterface(TARGET_IP_ADDR))
+ expect(interfaceService.getMatchingInterface(TARGET_IPV4_ADDR))
.andReturn(new Interface(cp, Collections.singleton(IA1), sourceMac, VlanId.vlanId(vlan)))
.anyTimes();
replay(interfaceService);
@@ -225,7 +333,7 @@ public class HostMonitorTest {
// Run the test
hostMonitor = new HostMonitor(packetService, hostManager, interfaceService, edgePortService);
- hostMonitor.addMonitoringFor(TARGET_IP_ADDR);
+ hostMonitor.addMonitoringFor(TARGET_IPV4_ADDR);
hostMonitor.run(null);
@@ -247,14 +355,84 @@ public class HostMonitorTest {
Ethernet eth = Ethernet.deserializer().deserialize(pktData, 0, pktData.length);
assertEquals(vlan, eth.getVlanID());
ARP arp = (ARP) eth.getPayload();
- assertArrayEquals(SOURCE_ADDR.toOctets(),
+ assertArrayEquals(SOURCE_IPV4_ADDR.toOctets(),
arp.getSenderProtocolAddress());
assertArrayEquals(sourceMac.toBytes(),
arp.getSenderHardwareAddress());
- assertArrayEquals(TARGET_IP_ADDR.toOctets(),
+ assertArrayEquals(TARGET_IPV4_ADDR.toOctets(),
arp.getTargetProtocolAddress());
}
+ @Test
+ public void testMonitorIpv6HostDoesNotExistWithVlan() throws Exception {
+
+ HostManager hostManager = createMock(HostManager.class);
+
+ DeviceId devId = DeviceId.deviceId("fake");
+ short vlan = 5;
+
+ Device device = createMock(Device.class);
+ expect(device.id()).andReturn(devId).anyTimes();
+ replay(device);
+
+ PortNumber portNum = PortNumber.portNumber(1L);
+
+ Port port = createMock(Port.class);
+ expect(port.number()).andReturn(portNum).anyTimes();
+ replay(port);
+
+ TestDeviceService deviceService = new TestDeviceService();
+ deviceService.addDevice(device, Collections.singleton(port));
+
+ ConnectPoint cp = new ConnectPoint(devId, portNum);
+
+ expect(hostManager.getHostsByIp(TARGET_IPV6_ADDR))
+ .andReturn(Collections.emptySet()).anyTimes();
+ replay(hostManager);
+
+ InterfaceService interfaceService = createMock(InterfaceService.class);
+ expect(interfaceService.getMatchingInterface(TARGET_IPV6_ADDR))
+ .andReturn(new Interface(cp, Collections.singleton(IA2), sourceMac2, VlanId.vlanId(vlan)))
+ .anyTimes();
+ replay(interfaceService);
+
+ TestPacketService packetService = new TestPacketService();
+
+
+ // Run the test
+ hostMonitor = new HostMonitor(packetService, hostManager, interfaceService, edgePortService);
+
+ hostMonitor.addMonitoringFor(TARGET_IPV6_ADDR);
+ hostMonitor.run(null);
+
+
+ // Check that a packet was sent to our PacketService and that it has
+ // the properties we expect
+ assertEquals(1, packetService.packets.size());
+ OutboundPacket packet = packetService.packets.get(0);
+
+ // Check the output port is correct
+ assertEquals(1, packet.treatment().immediate().size());
+ Instruction instruction = packet.treatment().immediate().get(0);
+ assertTrue(instruction instanceof OutputInstruction);
+ OutputInstruction oi = (OutputInstruction) instruction;
+ assertEquals(portNum, oi.port());
+
+ // Check the output packet is correct (well the important bits anyway)
+ final byte[] pktData = new byte[packet.data().remaining()];
+ packet.data().get(pktData);
+ Ethernet eth = Ethernet.deserializer().deserialize(pktData, 0, pktData.length);
+ assertEquals(vlan, eth.getVlanID());
+ IPv6 ipv6 = (IPv6) eth.getPayload();
+ assertArrayEquals(SOURCE_IPV6_ADDR.toOctets(), ipv6.getSourceAddress());
+
+ NeighborSolicitation ns =
+ (NeighborSolicitation) ipv6.getPayload().getPayload();
+ assertArrayEquals(sourceMac2.toBytes(), ns.getOptions().get(0).data());
+
+ assertArrayEquals(TARGET_IPV6_ADDR.toOctets(), ns.getTargetAddress());
+ }
+
class TestPacketService extends PacketServiceAdapter {
List<OutboundPacket> packets = new ArrayList<>();
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java
index 4bf32f43..3f40de09 100644
--- a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java
@@ -157,7 +157,7 @@ public class IntentManagerTest {
private static class MockInstallableIntent extends FlowRuleIntent {
public MockInstallableIntent() {
- super(APPID, Collections.singletonList(new MockFlowRule(100)));
+ super(APPID, Collections.singletonList(new MockFlowRule(100)), Collections.emptyList());
}
}
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MultiPointToSinglePointIntentCompilerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MultiPointToSinglePointIntentCompilerTest.java
index eb7a3936..03d664d3 100644
--- a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MultiPointToSinglePointIntentCompilerTest.java
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MultiPointToSinglePointIntentCompilerTest.java
@@ -31,8 +31,7 @@ import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentTestsMocks;
import org.onosproject.net.intent.LinkCollectionIntent;
import org.onosproject.net.intent.MultiPointToSinglePointIntent;
-import org.onosproject.net.topology.LinkWeight;
-import org.onosproject.net.topology.PathService;
+import org.onosproject.net.topology.PathServiceAdapter;
import java.util.HashSet;
import java.util.List;
@@ -60,7 +59,7 @@ public class MultiPointToSinglePointIntentCompilerTest extends AbstractIntentTes
/**
* Mock path service for creating paths within the test.
*/
- private static class MockPathService implements PathService {
+ private static class MockPathService extends PathServiceAdapter {
final String[] pathHops;
@@ -86,11 +85,6 @@ public class MultiPointToSinglePointIntentCompilerTest extends AbstractIntentTes
return result;
}
-
- @Override
- public Set<Path> getPaths(ElementId src, ElementId dst, LinkWeight weight) {
- return null;
- }
}
/**
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompilerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompilerTest.java
index 2f40b37a..38a116dd 100644
--- a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompilerTest.java
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompilerTest.java
@@ -27,18 +27,12 @@ import org.onosproject.net.DefaultLink;
import org.onosproject.net.DefaultPath;
import org.onosproject.net.Link;
import org.onosproject.net.OchSignalType;
-import org.onosproject.net.flow.DefaultTrafficSelector;
-import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.FlowRule;
-import org.onosproject.net.flow.TrafficSelector;
-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.OpticalPathIntent;
-import org.onosproject.net.provider.ProviderId;
import java.util.Arrays;
import java.util.Collection;
@@ -63,16 +57,11 @@ public class OpticalPathIntentCompilerTest {
private final IdGenerator idGenerator = new MockIdGenerator();
private OpticalPathIntentCompiler sut;
- private final TrafficSelector selector = DefaultTrafficSelector.builder().build();
- private final TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
private final ApplicationId appId = new TestApplicationId("test");
- private final ProviderId pid = new ProviderId("of", "test");
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 d3p0 = connectPoint("s3", 10);
- private final ConnectPoint d1p0 = connectPoint("s1", 10);
private final List<Link> links = Arrays.asList(
new DefaultLink(PID, d1p1, d2p0, DIRECT),
@@ -103,7 +92,6 @@ public class OpticalPathIntentCompilerTest {
intentExtensionService.registerCompiler(OpticalPathIntent.class, sut);
intentExtensionService.unregisterCompiler(OpticalPathIntent.class);
sut.intentManager = intentExtensionService;
- sut.resourceService = new IntentTestsMocks.MockResourceService();
replay(coreService, intentExtensionService);
}
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/PathManagerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/PathManagerTest.java
index 2a2d0b54..1911da56 100644
--- a/framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/PathManagerTest.java
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/PathManagerTest.java
@@ -23,13 +23,11 @@ import org.onosproject.net.ElementId;
import org.onosproject.net.Host;
import org.onosproject.net.HostId;
import org.onosproject.net.Path;
-import org.onosproject.net.host.HostService;
import org.onosproject.net.host.HostServiceAdapter;
import org.onosproject.net.provider.ProviderId;
import org.onosproject.net.topology.LinkWeight;
import org.onosproject.net.topology.PathService;
import org.onosproject.net.topology.Topology;
-import org.onosproject.net.topology.TopologyService;
import org.onosproject.net.topology.TopologyServiceAdapter;
import java.util.HashMap;
@@ -137,7 +135,7 @@ public class PathManagerTest {
}
// Fake entity to give out paths.
- private class FakeTopoMgr extends TopologyServiceAdapter implements TopologyService {
+ private class FakeTopoMgr extends TopologyServiceAdapter {
Set<Path> paths = new HashSet<>();
@Override
@@ -152,7 +150,7 @@ public class PathManagerTest {
}
// Fake entity to give out hosts.
- private class FakeHostMgr extends HostServiceAdapter implements HostService {
+ private class FakeHostMgr extends HostServiceAdapter {
private Map<HostId, Host> hosts = new HashMap<>();
@Override
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/TopologyManagerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/TopologyManagerTest.java
index f3cd28df..56133a0f 100644
--- a/framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/TopologyManagerTest.java
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/TopologyManagerTest.java
@@ -114,7 +114,7 @@ public class TopologyManagerTest {
link("c", 2, "d", 1), link("d", 1, "c", 2),
link("d", 2, "a", 2), link("a", 2, "d", 2),
link("e", 1, "f", 1), link("f", 1, "e", 1));
- GraphDescription data = new DefaultGraphDescription(4321L, devices, links);
+ GraphDescription data = new DefaultGraphDescription(4321L, System.currentTimeMillis(), devices, links);
providerService.topologyChanged(data, null);
}
diff --git a/framework/src/onos/core/net/src/test/resources/org/onosproject/cfg/impl/badComponent.json b/framework/src/onos/core/net/src/test/resources/org/onosproject/cfg/impl/badComponent.json
new file mode 100644
index 00000000..5c0ac35d
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/resources/org/onosproject/cfg/impl/badComponent.json
@@ -0,0 +1,5 @@
+{
+ "org.onosproject.proxyarp.ProxyArp2": {
+ "testProperty": true
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/core/net/src/test/resources/org/onosproject/cfg/impl/badConfig.json b/framework/src/onos/core/net/src/test/resources/org/onosproject/cfg/impl/badConfig.json
new file mode 100644
index 00000000..a76552e5
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/resources/org/onosproject/cfg/impl/badConfig.json
@@ -0,0 +1,5 @@
+{
+ "fooComponent": {
+ badconfig
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/core/net/src/test/resources/org/onosproject/cfg/impl/basic.json b/framework/src/onos/core/net/src/test/resources/org/onosproject/cfg/impl/basic.json
new file mode 100644
index 00000000..dd329243
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/resources/org/onosproject/cfg/impl/basic.json
@@ -0,0 +1,5 @@
+{
+ "fooComponent": {
+ "testProperty": true
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/Database.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/Database.java
index ff3e36ac..52a999a4 100644
--- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/Database.java
+++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/Database.java
@@ -38,7 +38,7 @@ public interface Database extends DatabaseProxy<String, byte[]>, Resource<Databa
* options specified in {@code cluster.conf} will override those in {cluster-defaults.conf}.<p>
*
* Additionally, the database will be constructed with an database configuration that searches the classpath for
- * three configuration files - {@code {name}}, {@code database}, {@code database-defaults}, {@code resource}, and
+ * three configuration files - {@code name}, {@code database}, {@code database-defaults}, {@code resource}, and
* {@code resource-defaults} - in that order. The first resource is a configuration resource with the same name
* as the map resource. If the resource is namespaced - e.g. `databases.my-database.conf` - then resource
* configurations will be loaded according to namespaces as well; for example, `databases.conf`.
@@ -54,7 +54,7 @@ public interface Database extends DatabaseProxy<String, byte[]>, Resource<Databa
* Creates a new database.<p>
*
* The database will be constructed with an database configuration that searches the classpath for
- * three configuration files - {@code {name}}, {@code database}, {@code database-defaults}, {@code resource}, and
+ * three configuration files - {@code name}, {@code database}, {@code database-defaults}, {@code resource}, and
* {@code resource-defaults} - in that order. The first resource is a configuration resource with the same name
* as the database resource. If the resource is namespaced - e.g. `databases.my-database.conf` - then resource
* configurations will be loaded according to namespaces as well; for example, `databases.conf`.
diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseManager.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseManager.java
index fbc2c88d..6ea7c220 100644
--- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseManager.java
+++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseManager.java
@@ -443,7 +443,10 @@ public class DatabaseManager implements StorageService, StorageAdminService {
public void event(ApplicationEvent event) {
if (event.type() == APP_UNINSTALLED || event.type() == APP_DEACTIVATED) {
ApplicationId appId = event.subject().id();
- List<DefaultAsyncConsistentMap> mapsToRemove = ImmutableList.copyOf(mapsByApplication.get(appId));
+ List<DefaultAsyncConsistentMap> mapsToRemove;
+ synchronized (mapsByApplication) {
+ mapsToRemove = ImmutableList.copyOf(mapsByApplication.get(appId));
+ }
mapsToRemove.forEach(DatabaseManager.this::unregisterMap);
if (event.type() == APP_UNINSTALLED) {
mapsToRemove.stream().filter(map -> map.purgeOnUninstall()).forEach(map -> map.clear());
diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseProxy.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseProxy.java
index 95f9e39a..1d81f998 100644
--- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseProxy.java
+++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseProxy.java
@@ -16,14 +16,14 @@
package org.onosproject.store.consistent.impl;
+import org.onosproject.store.service.Transaction;
+import org.onosproject.store.service.Versioned;
+
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
-import org.onosproject.store.service.Transaction;
-import org.onosproject.store.service.Versioned;
-
/**
* Database proxy.
*/
@@ -45,6 +45,7 @@ public interface DatabaseProxy<K, V> {
/**
* Returns the number of entries in map.
+ *
* @param mapName map name
* @return A completable future to be completed with the result once complete.
*/
@@ -62,7 +63,7 @@ public interface DatabaseProxy<K, V> {
* Checks whether the map contains a key.
*
* @param mapName map name
- * @param key key to check.
+ * @param key key to check.
* @return A completable future to be completed with the result once complete.
*/
CompletableFuture<Boolean> mapContainsKey(String mapName, K key);
@@ -71,7 +72,7 @@ public interface DatabaseProxy<K, V> {
* Checks whether the map contains a value.
*
* @param mapName map name
- * @param value The value to check.
+ * @param value The value to check.
* @return A completable future to be completed with the result once complete.
*/
CompletableFuture<Boolean> mapContainsValue(String mapName, V value);
@@ -80,7 +81,7 @@ public interface DatabaseProxy<K, V> {
* Gets a value from the map.
*
* @param mapName map name
- * @param key The key to get.
+ * @param key The key to get.
* @return A completable future to be completed with the result once complete.
*/
CompletableFuture<Versioned<V>> mapGet(String mapName, K key);
@@ -88,11 +89,11 @@ public interface DatabaseProxy<K, V> {
/**
* Updates the map.
*
- * @param mapName map name
- * @param key The key to set
- * @param valueMatch match for checking existing value
- * @param versionMatch match for checking existing version
- * @param value new value
+ * @param mapName map name
+ * @param key The key to set
+ * @param valueMatch match for checking existing value
+ * @param versionMatch match for checking existing version
+ * @param value new value
* @return A completable future to be completed with the result once complete
*/
CompletableFuture<Result<UpdateResult<K, V>>> mapUpdate(
@@ -130,11 +131,11 @@ public interface DatabaseProxy<K, V> {
*/
CompletableFuture<Set<Map.Entry<K, Versioned<V>>>> mapEntrySet(String mapName);
- /**
+ /**
* Atomically add the given value to current value of the specified counter.
*
* @param counterName counter name
- * @param delta value to add
+ * @param delta value to add
* @return updated value
*/
CompletableFuture<Long> counterAddAndGet(String counterName, long delta);
@@ -143,11 +144,31 @@ public interface DatabaseProxy<K, V> {
* Atomically add the given value to current value of the specified counter.
*
* @param counterName counter name
- * @param delta value to add
+ * @param delta value to add
* @return previous value
*/
CompletableFuture<Long> counterGetAndAdd(String counterName, long delta);
+
+ /**
+ * Atomically sets the given value to current value of the specified counter.
+ *
+ * @param counterName counter name
+ * @param value value to set
+ * @return void future
+ */
+ CompletableFuture<Void> counterSet(String counterName, long value);
+
+ /**
+ * Atomically sets the given counter to the specified update value if and only if the current value is equal to the
+ * expected value.
+ * @param counterName counter name
+ * @param expectedValue value to use for equivalence check
+ * @param update value to set if expected value is current value
+ * @return true if an update occurred, false otherwise
+ */
+ CompletableFuture<Boolean> counterCompareAndSet(String counterName, long expectedValue, long update);
+
/**
* Returns the current value of the specified atomic counter.
*
@@ -158,6 +179,7 @@ public interface DatabaseProxy<K, V> {
/**
* Returns the size of queue.
+ *
* @param queueName queue name
* @return queue size
*/
@@ -165,14 +187,16 @@ public interface DatabaseProxy<K, V> {
/**
* Inserts an entry into the queue.
+ *
* @param queueName queue name
- * @param entry queue entry
+ * @param entry queue entry
* @return void future
*/
CompletableFuture<Void> queuePush(String queueName, byte[] entry);
/**
* Removes an entry from the queue if the queue is non-empty.
+ *
* @param queueName queue name
* @return entry future. Can be completed with null if queue is empty
*/
@@ -180,6 +204,7 @@ public interface DatabaseProxy<K, V> {
/**
* Returns but does not remove an entry from the queue.
+ *
* @param queueName queue name
* @return entry. Can be null if queue is empty
*/
diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseState.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseState.java
index b3dd1c44..1136428b 100644
--- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseState.java
+++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseState.java
@@ -16,18 +16,17 @@
package org.onosproject.store.consistent.impl;
-import java.util.Collection;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-import org.onosproject.store.service.Transaction;
-import org.onosproject.store.service.Versioned;
-
import net.kuujo.copycat.state.Command;
import net.kuujo.copycat.state.Initializer;
import net.kuujo.copycat.state.Query;
import net.kuujo.copycat.state.StateContext;
+import org.onosproject.store.service.Transaction;
+import org.onosproject.store.service.Versioned;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
/**
* Database state.
@@ -83,6 +82,9 @@ public interface DatabaseState<K, V> {
Long counterAddAndGet(String counterName, long delta);
@Command
+ Boolean counterCompareAndSet(String counterName, long expectedValue, long updateValue);
+
+ @Command
Long counterGetAndAdd(String counterName, long delta);
@Query
diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAsyncAtomicCounter.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAsyncAtomicCounter.java
index 7a439c34..d851eaa0 100644
--- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAsyncAtomicCounter.java
+++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAsyncAtomicCounter.java
@@ -18,6 +18,7 @@ package org.onosproject.store.consistent.impl;
import org.onosproject.store.service.AsyncAtomicCounter;
import java.util.concurrent.CompletableFuture;
+
import static com.google.common.base.Preconditions.checkNotNull;
/**
@@ -38,6 +39,8 @@ public class DefaultAsyncAtomicCounter implements AsyncAtomicCounter {
private static final String GET_AND_ADD = "getAndAdd";
private static final String ADD_AND_GET = "addAndGet";
private static final String GET = "get";
+ private static final String SET = "set";
+ private static final String COMPARE_AND_SET = "compareAndSet";
public DefaultAsyncAtomicCounter(String name,
Database database,
@@ -72,13 +75,27 @@ public class DefaultAsyncAtomicCounter implements AsyncAtomicCounter {
public CompletableFuture<Long> getAndAdd(long delta) {
final MeteringAgent.Context timer = monitor.startTimer(GET_AND_ADD);
return database.counterGetAndAdd(name, delta)
- .whenComplete((r, e) -> timer.stop(e));
+ .whenComplete((r, e) -> timer.stop(e));
}
@Override
public CompletableFuture<Long> addAndGet(long delta) {
final MeteringAgent.Context timer = monitor.startTimer(ADD_AND_GET);
return database.counterAddAndGet(name, delta)
- .whenComplete((r, e) -> timer.stop(e));
+ .whenComplete((r, e) -> timer.stop(e));
+ }
+
+ @Override
+ public CompletableFuture<Void> set(long value) {
+ final MeteringAgent.Context timer = monitor.startTimer(SET);
+ return database.counterSet(name, value)
+ .whenComplete((r, e) -> timer.stop(e));
+ }
+
+ @Override
+ public CompletableFuture<Boolean> compareAndSet(long expectedValue, long updateValue) {
+ final MeteringAgent.Context timer = monitor.startTimer(COMPARE_AND_SET);
+ return database.counterCompareAndSet(name, expectedValue, updateValue)
+ .whenComplete((r, e) -> timer.stop(e));
}
}
diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAtomicCounter.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAtomicCounter.java
index 64886e41..2d6a956c 100644
--- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAtomicCounter.java
+++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAtomicCounter.java
@@ -63,6 +63,16 @@ public class DefaultAtomicCounter implements AtomicCounter {
}
@Override
+ public void set(long value) {
+ complete(asyncCounter.set(value));
+ }
+
+ @Override
+ public boolean compareAndSet(long expectedValue, long updateValue) {
+ return complete(asyncCounter.compareAndSet(expectedValue, updateValue));
+ }
+
+ @Override
public long get() {
return complete(asyncCounter.get());
}
diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabase.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabase.java
index 4d9776ee..2a50fbd6 100644
--- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabase.java
+++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabase.java
@@ -16,12 +16,15 @@
package org.onosproject.store.consistent.impl;
-import net.kuujo.copycat.state.StateMachine;
+import com.google.common.collect.Sets;
import net.kuujo.copycat.resource.internal.AbstractResource;
import net.kuujo.copycat.resource.internal.ResourceManager;
+import net.kuujo.copycat.state.StateMachine;
import net.kuujo.copycat.state.internal.DefaultStateMachine;
import net.kuujo.copycat.util.concurrent.Futures;
import net.kuujo.copycat.util.function.TriConsumer;
+import org.onosproject.store.service.Transaction;
+import org.onosproject.store.service.Versioned;
import java.util.Collection;
import java.util.Map;
@@ -30,11 +33,6 @@ import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.function.Supplier;
-import org.onosproject.store.service.Transaction;
-import org.onosproject.store.service.Versioned;
-
-import com.google.common.collect.Sets;
-
/**
* Default database.
*/
@@ -44,7 +42,7 @@ public class DefaultDatabase extends AbstractResource<Database> implements Datab
private final Set<Consumer<StateMachineUpdate>> consumers = Sets.newCopyOnWriteArraySet();
private final TriConsumer<String, Object, Object> watcher = new InternalStateMachineWatcher();
- @SuppressWarnings({ "unchecked", "rawtypes" })
+ @SuppressWarnings({"unchecked", "rawtypes"})
public DefaultDatabase(ResourceManager context) {
super(context);
this.stateMachine = new DefaultStateMachine(context,
@@ -66,7 +64,7 @@ public class DefaultDatabase extends AbstractResource<Database> implements Datab
* return the completed future result.
*
* @param supplier The supplier to call if the database is open.
- * @param <T> The future result type.
+ * @param <T> The future result type.
* @return A completable future that if this database is closed is immediately failed.
*/
protected <T> CompletableFuture<T> checkOpen(Supplier<CompletableFuture<T>> supplier) {
@@ -153,6 +151,16 @@ public class DefaultDatabase extends AbstractResource<Database> implements Datab
}
@Override
+ public CompletableFuture<Void> counterSet(String counterName, long value) {
+ return checkOpen(() -> proxy.counterSet(counterName, value));
+ }
+
+ @Override
+ public CompletableFuture<Boolean> counterCompareAndSet(String counterName, long expectedValue, long update) {
+ return checkOpen(() -> proxy.counterCompareAndSet(counterName, expectedValue, update));
+ }
+
+ @Override
public CompletableFuture<Long> queueSize(String queueName) {
return checkOpen(() -> proxy.queueSize(queueName));
}
diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabaseState.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabaseState.java
index 9a55ffb1..8943fc87 100644
--- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabaseState.java
+++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabaseState.java
@@ -16,27 +16,26 @@
package org.onosproject.store.consistent.impl;
+import com.google.common.base.Objects;
+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 net.kuujo.copycat.state.Initializer;
+import net.kuujo.copycat.state.StateContext;
+import org.onosproject.store.service.DatabaseUpdate;
+import org.onosproject.store.service.Transaction;
+import org.onosproject.store.service.Versioned;
+
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedList;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Queue;
+import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
-import java.util.Set;
-
-import org.onosproject.store.service.DatabaseUpdate;
-import org.onosproject.store.service.Transaction;
-import org.onosproject.store.service.Versioned;
-import com.google.common.base.Objects;
-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 net.kuujo.copycat.state.Initializer;
-import net.kuujo.copycat.state.StateContext;
/**
* Default database state.
@@ -195,6 +194,11 @@ public class DefaultDatabaseState implements DatabaseState<String, byte[]> {
}
@Override
+ public Boolean counterCompareAndSet(String counterName, long expectedValue, long updateValue) {
+ return getCounter(counterName).compareAndSet(expectedValue, updateValue);
+ }
+
+ @Override
public Long counterGet(String counterName) {
return getCounter(counterName).get();
}
diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/MutexExecutionManager.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/MutexExecutionManager.java
new file mode 100644
index 00000000..d8593e37
--- /dev/null
+++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/MutexExecutionManager.java
@@ -0,0 +1,315 @@
+/*
+ * 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 org.slf4j.LoggerFactory.getLogger;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executor;
+
+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.util.Tools;
+import org.onosproject.cluster.ClusterEvent;
+import org.onosproject.cluster.ClusterEventListener;
+import org.onosproject.cluster.ClusterService;
+import org.onosproject.cluster.ControllerNode.State;
+import org.onosproject.cluster.NodeId;
+import org.onosproject.store.serializers.KryoNamespaces;
+import org.onosproject.store.service.ConsistentMap;
+import org.onosproject.store.service.ConsistentMapException;
+import org.onosproject.store.service.MapEvent;
+import org.onosproject.store.service.MapEventListener;
+import org.onosproject.store.service.MutexExecutionService;
+import org.onosproject.store.service.MutexTask;
+import org.onosproject.store.service.Serializer;
+import org.onosproject.store.service.StorageService;
+import org.onosproject.store.service.Versioned;
+import org.slf4j.Logger;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+/**
+ * Implementation of a MutexExecutionService.
+ */
+@Component(immediate = true)
+@Service
+public class MutexExecutionManager implements MutexExecutionService {
+
+ private final Logger log = getLogger(getClass());
+
+ protected ConsistentMap<String, MutexState> lockMap;
+ protected NodeId localNodeId;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected ClusterService clusterService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected StorageService storageService;
+
+ private final MapEventListener<String, MutexState> mapEventListener = new InternalLockMapEventListener();
+ private final ClusterEventListener clusterEventListener = new InternalClusterEventListener();
+
+ private Map<String, CompletableFuture<MutexState>> pending = Maps.newConcurrentMap();
+ private Map<String, InnerMutexTask> activeTasks = Maps.newConcurrentMap();
+
+ @Activate
+ public void activate() {
+ localNodeId = clusterService.getLocalNode().id();
+ lockMap = storageService.<String, MutexState>consistentMapBuilder()
+ .withName("onos-mutexes")
+ .withSerializer(Serializer.using(Arrays.asList(KryoNamespaces.API), MutexState.class))
+ .withPartitionsDisabled()
+ .build();
+ lockMap.addListener(mapEventListener);
+ clusterService.addListener(clusterEventListener);
+ releaseOldLocks();
+ log.info("Started");
+ }
+
+ @Deactivate
+ public void deactivate() {
+ lockMap.removeListener(mapEventListener);
+ pending.values().forEach(future -> future.cancel(true));
+ activeTasks.forEach((k, v) -> {
+ v.stop();
+ unlock(k);
+ });
+ clusterService.removeListener(clusterEventListener);
+ log.info("Stopped");
+ }
+
+ @Override
+ public CompletableFuture<Void> execute(MutexTask task, String exclusionPath, Executor executor) {
+ return lock(exclusionPath)
+ .thenApply(state -> activeTasks.computeIfAbsent(exclusionPath,
+ k -> new InnerMutexTask(exclusionPath,
+ task,
+ state.term())))
+ .thenAcceptAsync(t -> t.start(), executor)
+ .whenComplete((r, e) -> unlock(exclusionPath));
+ }
+
+ protected CompletableFuture<MutexState> lock(String exclusionPath) {
+ CompletableFuture<MutexState> future =
+ pending.computeIfAbsent(exclusionPath, k -> new CompletableFuture<>());
+ tryLock(exclusionPath);
+ return future;
+ }
+
+ /**
+ * Attempts to acquire lock for a path. If lock is held by some other node, adds this node to
+ * the wait list.
+ * @param exclusionPath exclusion path
+ */
+ protected void tryLock(String exclusionPath) {
+ Tools.retryable(() -> lockMap.asJavaMap()
+ .compute(exclusionPath,
+ (k, v) -> MutexState.admit(v, localNodeId)),
+ ConsistentMapException.ConcurrentModification.class,
+ Integer.MAX_VALUE,
+ 100).get();
+ }
+
+ /**
+ * Releases lock for the specific path. This operation is idempotent.
+ * @param exclusionPath exclusion path
+ */
+ protected void unlock(String exclusionPath) {
+ Tools.retryable(() -> lockMap.asJavaMap()
+ .compute(exclusionPath, (k, v) -> MutexState.evict(v, localNodeId)),
+ ConsistentMapException.ConcurrentModification.class,
+ Integer.MAX_VALUE,
+ 100).get();
+ }
+
+ /**
+ * Detects and releases all locks held by this node.
+ */
+ private void releaseOldLocks() {
+ Maps.filterValues(lockMap.asJavaMap(), state -> localNodeId.equals(state.holder()))
+ .keySet()
+ .forEach(path -> {
+ log.info("Detected zombie task still holding lock for {}. Releasing lock.", path);
+ unlock(path);
+ });
+ }
+
+ private class InternalLockMapEventListener implements MapEventListener<String, MutexState> {
+
+ @Override
+ public void event(MapEvent<String, MutexState> event) {
+ log.debug("Received {}", event);
+ if (event.type() == MapEvent.Type.UPDATE || event.type() == MapEvent.Type.INSERT) {
+ pending.computeIfPresent(event.key(), (k, future) -> {
+ MutexState state = Versioned.valueOrElse(event.value(), null);
+ if (state != null && localNodeId.equals(state.holder())) {
+ log.debug("Local node is now owner for {}", event.key());
+ future.complete(state);
+ return null;
+ } else {
+ return future;
+ }
+ });
+ InnerMutexTask task = activeTasks.get(event.key());
+ if (task != null && task.term() < Versioned.valueOrElse(event.value(), null).term()) {
+ task.stop();
+ }
+ }
+ }
+ }
+
+ private class InternalClusterEventListener implements ClusterEventListener {
+
+ @Override
+ public void event(ClusterEvent event) {
+ if (event.type() == ClusterEvent.Type.INSTANCE_DEACTIVATED ||
+ event.type() == ClusterEvent.Type.INSTANCE_REMOVED) {
+ NodeId nodeId = event.subject().id();
+ log.debug("{} is no longer active. Attemping to clean up its locks.", nodeId);
+ lockMap.asJavaMap().forEach((k, v) -> {
+ if (v.contains(nodeId)) {
+ lockMap.compute(k, (path, state) -> MutexState.evict(v, nodeId));
+ }
+ });
+ }
+ long activeNodes = clusterService.getNodes()
+ .stream()
+ .map(node -> clusterService.getState(node.id()))
+ .filter(State.ACTIVE::equals)
+ .count();
+ if (clusterService.getNodes().size() > 1 && activeNodes == 1) {
+ log.info("This node is partitioned away from the cluster. Stopping all inflight executions");
+ activeTasks.forEach((k, v) -> {
+ v.stop();
+ });
+ }
+ }
+ }
+
+ private static final class MutexState {
+
+ private final NodeId holder;
+ private final List<NodeId> waitList;
+ private final long term;
+
+ public static MutexState admit(MutexState state, NodeId nodeId) {
+ if (state == null) {
+ return new MutexState(nodeId, 1L, Lists.newArrayList());
+ } else if (state.holder() == null) {
+ return new MutexState(nodeId, state.term() + 1, Lists.newArrayList());
+ } else {
+ if (!state.contains(nodeId)) {
+ NodeId newHolder = state.holder();
+ List<NodeId> newWaitList = Lists.newArrayList(state.waitList());
+ newWaitList.add(nodeId);
+ return new MutexState(newHolder, state.term(), newWaitList);
+ } else {
+ return state;
+ }
+ }
+ }
+
+ public static MutexState evict(MutexState state, NodeId nodeId) {
+ return state.evict(nodeId);
+ }
+
+ public MutexState evict(NodeId nodeId) {
+ if (nodeId.equals(holder)) {
+ if (waitList.isEmpty()) {
+ return new MutexState(null, term, waitList);
+ }
+ List<NodeId> newWaitList = Lists.newArrayList(waitList);
+ NodeId newHolder = newWaitList.remove(0);
+ return new MutexState(newHolder, term + 1, newWaitList);
+ } else {
+ NodeId newHolder = holder;
+ List<NodeId> newWaitList = Lists.newArrayList(waitList);
+ newWaitList.remove(nodeId);
+ return new MutexState(newHolder, term, newWaitList);
+ }
+ }
+
+ public NodeId holder() {
+ return holder;
+ }
+
+ public List<NodeId> waitList() {
+ return waitList;
+ }
+
+ public long term() {
+ return term;
+ }
+
+ private boolean contains(NodeId nodeId) {
+ return (nodeId.equals(holder) || waitList.contains(nodeId));
+ }
+
+ private MutexState(NodeId holder, long term, List<NodeId> waitList) {
+ this.holder = holder;
+ this.term = term;
+ this.waitList = Lists.newArrayList(waitList);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("holder", holder)
+ .add("term", term)
+ .add("waitList", waitList)
+ .toString();
+ }
+ }
+
+ private class InnerMutexTask implements MutexTask {
+ private final MutexTask task;
+ private final String mutexPath;
+ private final long term;
+
+ public InnerMutexTask(String mutexPath, MutexTask task, long term) {
+ this.mutexPath = mutexPath;
+ this.term = term;
+ this.task = task;
+ }
+
+ public long term() {
+ return term;
+ }
+
+ @Override
+ public void start() {
+ log.debug("Starting execution for mutex task guarded by {}", mutexPath);
+ task.start();
+ log.debug("Finished execution for mutex task guarded by {}", mutexPath);
+ }
+
+ @Override
+ public void stop() {
+ log.debug("Stopping execution for mutex task guarded by {}", mutexPath);
+ task.stop();
+ }
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/PartitionedDatabase.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/PartitionedDatabase.java
index a294681e..f741b367 100644
--- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/PartitionedDatabase.java
+++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/PartitionedDatabase.java
@@ -16,6 +16,17 @@
package org.onosproject.store.consistent.impl;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import net.kuujo.copycat.Task;
+import net.kuujo.copycat.cluster.Cluster;
+import net.kuujo.copycat.resource.ResourceState;
+import org.onosproject.store.service.DatabaseUpdate;
+import org.onosproject.store.service.Transaction;
+import org.onosproject.store.service.Versioned;
+
import java.util.Collection;
import java.util.List;
import java.util.Map;
@@ -28,18 +39,6 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.stream.Collectors;
-import org.onosproject.store.service.DatabaseUpdate;
-import org.onosproject.store.service.Transaction;
-import org.onosproject.store.service.Versioned;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-
-import net.kuujo.copycat.Task;
-import net.kuujo.copycat.cluster.Cluster;
-import net.kuujo.copycat.resource.ResourceState;
import static com.google.common.base.Preconditions.checkState;
/**
@@ -100,10 +99,10 @@ public class PartitionedDatabase implements Database {
return CompletableFuture.allOf(partitions
.stream()
.map(db -> db.counters()
- .thenApply(m -> {
- counters.putAll(m);
- return null;
- }))
+ .thenApply(m -> {
+ counters.putAll(m);
+ return null;
+ }))
.toArray(CompletableFuture[]::new))
.thenApply(v -> counters);
}
@@ -113,9 +112,9 @@ public class PartitionedDatabase implements Database {
checkState(isOpen.get(), DB_NOT_OPEN);
AtomicInteger totalSize = new AtomicInteger(0);
return CompletableFuture.allOf(partitions
- .stream()
- .map(p -> p.mapSize(mapName).thenApply(totalSize::addAndGet))
- .toArray(CompletableFuture[]::new))
+ .stream()
+ .map(p -> p.mapSize(mapName).thenApply(totalSize::addAndGet))
+ .toArray(CompletableFuture[]::new))
.thenApply(v -> totalSize.get());
}
@@ -136,10 +135,10 @@ public class PartitionedDatabase implements Database {
checkState(isOpen.get(), DB_NOT_OPEN);
AtomicBoolean containsValue = new AtomicBoolean(false);
return CompletableFuture.allOf(partitions
- .stream()
- .map(p -> p.mapContainsValue(mapName, value)
- .thenApply(v -> containsValue.compareAndSet(false, v)))
- .toArray(CompletableFuture[]::new))
+ .stream()
+ .map(p -> p.mapContainsValue(mapName, value)
+ .thenApply(v -> containsValue.compareAndSet(false, v)))
+ .toArray(CompletableFuture[]::new))
.thenApply(v -> containsValue.get());
}
@@ -196,9 +195,9 @@ public class PartitionedDatabase implements Database {
checkState(isOpen.get(), DB_NOT_OPEN);
Set<Entry<String, Versioned<byte[]>>> entrySet = Sets.newConcurrentHashSet();
return CompletableFuture.allOf(partitions
- .stream()
- .map(p -> p.mapEntrySet(mapName).thenApply(entrySet::addAll))
- .toArray(CompletableFuture[]::new))
+ .stream()
+ .map(p -> p.mapEntrySet(mapName).thenApply(entrySet::addAll))
+ .toArray(CompletableFuture[]::new))
.thenApply(v -> entrySet);
}
@@ -220,6 +219,19 @@ public class PartitionedDatabase implements Database {
return partitioner.getPartition(counterName, counterName).counterGetAndAdd(counterName, delta);
}
+ @Override
+ public CompletableFuture<Void> counterSet(String counterName, long value) {
+ checkState(isOpen.get(), DB_NOT_OPEN);
+ return partitioner.getPartition(counterName, counterName).counterSet(counterName, value);
+ }
+
+ @Override
+ public CompletableFuture<Boolean> counterCompareAndSet(String counterName, long expectedValue, long updateValue) {
+ checkState(isOpen.get(), DB_NOT_OPEN);
+ return partitioner.getPartition(counterName, counterName).
+ counterCompareAndSet(counterName, expectedValue, updateValue);
+
+ }
@Override
public CompletableFuture<Long> queueSize(String queueName) {
@@ -268,8 +280,8 @@ public class PartitionedDatabase implements Database {
AtomicBoolean status = new AtomicBoolean(true);
return CompletableFuture.allOf(subTransactions.entrySet()
.stream()
- .map(entry -> entry
- .getKey()
+ .map(entry -> entry
+ .getKey()
.prepare(entry.getValue())
.thenApply(v -> status.compareAndSet(true, v)))
.toArray(CompletableFuture[]::new))
@@ -282,15 +294,15 @@ public class PartitionedDatabase implements Database {
AtomicBoolean success = new AtomicBoolean(true);
List<UpdateResult<String, byte[]>> allUpdates = Lists.newArrayList();
return CompletableFuture.allOf(subTransactions.entrySet()
- .stream()
- .map(entry -> entry.getKey().commit(entry.getValue())
- .thenAccept(response -> {
- success.set(success.get() && response.success());
- if (success.get()) {
- allUpdates.addAll(response.updates());
- }
- }))
- .toArray(CompletableFuture[]::new))
+ .stream()
+ .map(entry -> entry.getKey().commit(entry.getValue())
+ .thenAccept(response -> {
+ success.set(success.get() && response.success());
+ if (success.get()) {
+ allUpdates.addAll(response.updates());
+ }
+ }))
+ .toArray(CompletableFuture[]::new))
.thenApply(v -> success.get() ?
CommitResponse.success(allUpdates) : CommitResponse.failure());
}
@@ -301,7 +313,7 @@ public class PartitionedDatabase implements Database {
return CompletableFuture.allOf(subTransactions.entrySet()
.stream()
.map(entry -> entry.getKey().rollback(entry.getValue()))
- .toArray(CompletableFuture[]::new))
+ .toArray(CompletableFuture[]::new))
.thenApply(v -> true);
}
@@ -384,3 +396,4 @@ public class PartitionedDatabase implements Database {
partitions.forEach(p -> p.unregisterConsumer(consumer));
}
}
+
diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/ecmap/EventuallyConsistentMapImpl.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/ecmap/EventuallyConsistentMapImpl.java
index 2859b62f..f1e0dbd4 100644
--- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/ecmap/EventuallyConsistentMapImpl.java
+++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/ecmap/EventuallyConsistentMapImpl.java
@@ -21,7 +21,6 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
-
import org.apache.commons.lang3.tuple.Pair;
import org.onlab.util.AbstractAccumulator;
import org.onlab.util.KryoNamespace;
@@ -33,18 +32,15 @@ import org.onosproject.store.Timestamp;
import org.onosproject.store.cluster.messaging.ClusterCommunicationService;
import org.onosproject.store.cluster.messaging.MessageSubject;
import org.onosproject.store.impl.LogicalTimestamp;
-import org.onosproject.store.service.WallClockTimestamp;
import org.onosproject.store.serializers.KryoNamespaces;
import org.onosproject.store.serializers.KryoSerializer;
import org.onosproject.store.service.EventuallyConsistentMap;
import org.onosproject.store.service.EventuallyConsistentMapEvent;
import org.onosproject.store.service.EventuallyConsistentMapListener;
+import org.onosproject.store.service.WallClockTimestamp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import static org.onosproject.store.service.EventuallyConsistentMapEvent.Type.PUT;
-import static org.onosproject.store.service.EventuallyConsistentMapEvent.Type.REMOVE;
-
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@@ -67,6 +63,8 @@ import static com.google.common.base.Preconditions.checkState;
import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
import static org.onlab.util.BoundedThreadPool.newFixedThreadPool;
import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.store.service.EventuallyConsistentMapEvent.Type.PUT;
+import static org.onosproject.store.service.EventuallyConsistentMapEvent.Type.REMOVE;
/**
* Distributed Map implementation which uses optimistic replication and gossip
@@ -359,7 +357,7 @@ public class EventuallyConsistentMapImpl<K, V>
valueMatches = Objects.equals(value.get(), existing.get());
}
if (existing == null) {
- log.debug("ECMap Remove: Existing value for key {} is already null", k);
+ log.trace("ECMap Remove: Existing value for key {} is already null", k);
}
if (valueMatches) {
if (existing == null) {
@@ -523,7 +521,7 @@ public class EventuallyConsistentMapImpl<K, V>
return;
}
peers.forEach(node ->
- senderPending.computeIfAbsent(node, unusedKey -> new EventAccumulator(node)).add(event)
+ senderPending.computeIfAbsent(node, unusedKey -> new EventAccumulator(node)).add(event)
);
}
@@ -576,8 +574,10 @@ public class EventuallyConsistentMapImpl<K, V>
return;
}
try {
- log.debug("Received anti-entropy advertisement from {} for {} with {} entries in it",
- mapName, ad.sender(), ad.digest().size());
+ if (log.isTraceEnabled()) {
+ log.trace("Received anti-entropy advertisement from {} for {} with {} entries in it",
+ mapName, ad.sender(), ad.digest().size());
+ }
antiEntropyCheckLocalItems(ad).forEach(this::notifyListeners);
if (!lightweightAntiEntropy) {
@@ -675,4 +675,4 @@ public class EventuallyConsistentMapImpl<K, V>
});
}
}
-} \ No newline at end of file
+}
diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/flow/impl/NewDistributedFlowRuleStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/flow/impl/NewDistributedFlowRuleStore.java
index de7a3ac3..8cd63e7d 100644
--- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/flow/impl/NewDistributedFlowRuleStore.java
+++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/flow/impl/NewDistributedFlowRuleStore.java
@@ -16,6 +16,7 @@
package org.onosproject.store.flow.impl;
import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
@@ -57,6 +58,7 @@ import org.onosproject.net.flow.FlowRuleService;
import org.onosproject.net.flow.FlowRuleStore;
import org.onosproject.net.flow.FlowRuleStoreDelegate;
import org.onosproject.net.flow.StoredFlowEntry;
+import org.onosproject.net.flow.TableStatisticsEntry;
import org.onosproject.store.AbstractStore;
import org.onosproject.store.cluster.messaging.ClusterCommunicationService;
import org.onosproject.store.cluster.messaging.ClusterMessage;
@@ -64,9 +66,16 @@ import org.onosproject.store.cluster.messaging.ClusterMessageHandler;
import org.onosproject.store.flow.ReplicaInfoEvent;
import org.onosproject.store.flow.ReplicaInfoEventListener;
import org.onosproject.store.flow.ReplicaInfoService;
+import org.onosproject.store.impl.MastershipBasedTimestamp;
+import org.onosproject.store.serializers.KryoNamespaces;
import org.onosproject.store.serializers.KryoSerializer;
import org.onosproject.store.serializers.StoreSerializer;
import org.onosproject.store.serializers.custom.DistributedStoreSerializers;
+import org.onosproject.store.service.EventuallyConsistentMap;
+import org.onosproject.store.service.EventuallyConsistentMapEvent;
+import org.onosproject.store.service.EventuallyConsistentMapListener;
+import org.onosproject.store.service.StorageService;
+import org.onosproject.store.service.WallClockTimestamp;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
@@ -151,6 +160,13 @@ public class NewDistributedFlowRuleStore
private final ScheduledExecutorService backupSenderExecutor =
Executors.newSingleThreadScheduledExecutor(groupedThreads("onos/flow", "backup-sender"));
+ private EventuallyConsistentMap<DeviceId, List<TableStatisticsEntry>> deviceTableStats;
+ private final EventuallyConsistentMapListener<DeviceId, List<TableStatisticsEntry>> tableStatsListener =
+ new InternalTableStatsListener();
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected StorageService storageService;
+
protected static final StoreSerializer SERIALIZER = new KryoSerializer() {
@Override
protected void setupKryoPool() {
@@ -161,6 +177,11 @@ public class NewDistributedFlowRuleStore
}
};
+ protected static final KryoNamespace.Builder SERIALIZER_BUILDER = KryoNamespace.newBuilder()
+ .register(KryoNamespaces.API)
+ .register(MastershipBasedTimestamp.class);
+
+
private IdGenerator idGenerator;
private NodeId local;
@@ -186,6 +207,15 @@ public class NewDistributedFlowRuleStore
TimeUnit.MILLISECONDS);
}
+ deviceTableStats = storageService.<DeviceId, List<TableStatisticsEntry>>eventuallyConsistentMapBuilder()
+ .withName("onos-flow-table-stats")
+ .withSerializer(SERIALIZER_BUILDER)
+ .withAntiEntropyPeriod(5, TimeUnit.SECONDS)
+ .withTimestampProvider((k, v) -> new WallClockTimestamp())
+ .withTombstonesDisabled()
+ .build();
+ deviceTableStats.addListener(tableStatsListener);
+
logConfig("Started");
}
@@ -197,6 +227,8 @@ public class NewDistributedFlowRuleStore
}
configService.unregisterProperties(getClass(), false);
unregisterMessageHandlers();
+ deviceTableStats.removeListener(tableStatsListener);
+ deviceTableStats.destroy();
messageHandlingExecutor.shutdownNow();
backupSenderExecutor.shutdownNow();
log.info("Stopped");
@@ -786,4 +818,36 @@ public class NewDistributedFlowRuleStore
return backedupDevices;
}
}
+
+ @Override
+ public FlowRuleEvent updateTableStatistics(DeviceId deviceId,
+ List<TableStatisticsEntry> tableStats) {
+ deviceTableStats.put(deviceId, tableStats);
+ return null;
+ }
+
+ @Override
+ public Iterable<TableStatisticsEntry> getTableStatistics(DeviceId deviceId) {
+ NodeId master = mastershipService.getMasterFor(deviceId);
+
+ if (master == null) {
+ log.debug("Failed to getTableStats: No master for {}", deviceId);
+ return Collections.emptyList();
+ }
+
+ List<TableStatisticsEntry> tableStats = deviceTableStats.get(deviceId);
+ if (tableStats == null) {
+ return Collections.emptyList();
+ }
+ return ImmutableList.copyOf(tableStats);
+ }
+
+ private class InternalTableStatsListener
+ implements EventuallyConsistentMapListener<DeviceId, List<TableStatisticsEntry>> {
+ @Override
+ public void event(EventuallyConsistentMapEvent<DeviceId,
+ List<TableStatisticsEntry>> event) {
+ //TODO: Generate an event to listeners (do we need?)
+ }
+ }
}
diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/group/impl/DistributedGroupStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/group/impl/DistributedGroupStore.java
index 97333ebf..a999ee7f 100644
--- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/group/impl/DistributedGroupStore.java
+++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/group/impl/DistributedGroupStore.java
@@ -28,19 +28,11 @@ import org.apache.felix.scr.annotations.Service;
import org.onlab.util.KryoNamespace;
import org.onlab.util.NewConcurrentHashMap;
import org.onosproject.cluster.ClusterService;
-import org.onosproject.core.DefaultApplicationId;
import org.onosproject.core.DefaultGroupId;
import org.onosproject.core.GroupId;
import org.onosproject.mastership.MastershipService;
import org.onosproject.net.DeviceId;
import org.onosproject.net.MastershipRole;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.flow.DefaultTrafficTreatment;
-import org.onosproject.net.flow.FlowRule;
-import org.onosproject.net.flow.instructions.Instructions;
-import org.onosproject.net.flow.instructions.L0ModificationInstruction;
-import org.onosproject.net.flow.instructions.L2ModificationInstruction;
-import org.onosproject.net.flow.instructions.L3ModificationInstruction;
import org.onosproject.net.group.DefaultGroup;
import org.onosproject.net.group.DefaultGroupBucket;
import org.onosproject.net.group.DefaultGroupDescription;
@@ -61,9 +53,7 @@ import org.onosproject.net.group.StoredGroupEntry;
import org.onosproject.store.AbstractStore;
import org.onosproject.store.cluster.messaging.ClusterCommunicationService;
import org.onosproject.store.service.MultiValuedTimestamp;
-import org.onosproject.store.serializers.DeviceIdSerializer;
import org.onosproject.store.serializers.KryoNamespaces;
-import org.onosproject.store.serializers.URISerializer;
import org.onosproject.store.service.EventuallyConsistentMap;
import org.onosproject.store.service.EventuallyConsistentMapBuilder;
import org.onosproject.store.service.EventuallyConsistentMapEvent;
@@ -71,7 +61,6 @@ import org.onosproject.store.service.EventuallyConsistentMapListener;
import org.onosproject.store.service.StorageService;
import org.slf4j.Logger;
-import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
@@ -139,9 +128,12 @@ public class DistributedGroupStore
private final AtomicLong sequenceNumber = new AtomicLong(0);
+ private KryoNamespace clusterMsgSerializer;
+
@Activate
public void activate() {
kryoBuilder = new KryoNamespace.Builder()
+ .register(KryoNamespaces.API)
.register(DefaultGroup.class,
DefaultGroupBucket.class,
DefaultGroupDescription.class,
@@ -158,38 +150,9 @@ public class DistributedGroupStore
GroupStoreKeyMapKey.class,
GroupStoreIdMapKey.class,
GroupStoreMapKey.class
- )
- .register(new URISerializer(), URI.class)
- .register(new DeviceIdSerializer(), DeviceId.class)
- .register(PortNumber.class)
- .register(DefaultApplicationId.class)
- .register(DefaultTrafficTreatment.class,
- Instructions.DropInstruction.class,
- Instructions.OutputInstruction.class,
- Instructions.GroupInstruction.class,
- Instructions.TableTypeTransition.class,
- FlowRule.Type.class,
- L0ModificationInstruction.class,
- L0ModificationInstruction.L0SubType.class,
- L0ModificationInstruction.ModLambdaInstruction.class,
- L2ModificationInstruction.class,
- L2ModificationInstruction.L2SubType.class,
- L2ModificationInstruction.ModEtherInstruction.class,
- L2ModificationInstruction.PushHeaderInstructions.class,
- L2ModificationInstruction.ModVlanIdInstruction.class,
- L2ModificationInstruction.ModVlanPcpInstruction.class,
- L2ModificationInstruction.ModMplsLabelInstruction.class,
- L2ModificationInstruction.ModMplsTtlInstruction.class,
- L3ModificationInstruction.class,
- L3ModificationInstruction.L3SubType.class,
- L3ModificationInstruction.ModIPInstruction.class,
- L3ModificationInstruction.ModIPv6FlowLabelInstruction.class,
- L3ModificationInstruction.ModTtlInstruction.class,
- org.onlab.packet.MplsLabel.class
- )
- .register(org.onosproject.cluster.NodeId.class)
- .register(KryoNamespaces.BASIC)
- .register(KryoNamespaces.MISC);
+ );
+
+ clusterMsgSerializer = kryoBuilder.build();
messageHandlingExecutor = Executors.
newFixedThreadPool(MESSAGE_HANDLER_THREAD_POOL_SIZE,
@@ -197,7 +160,7 @@ public class DistributedGroupStore
"message-handlers"));
clusterCommunicator.addSubscriber(GroupStoreMessageSubjects.REMOTE_GROUP_OP_REQUEST,
- kryoBuilder.build()::deserialize,
+ clusterMsgSerializer::deserialize,
this::process,
messageHandlingExecutor);
@@ -233,6 +196,7 @@ public class DistributedGroupStore
@Deactivate
public void deactivate() {
+ clusterCommunicator.removeSubscriber(GroupStoreMessageSubjects.REMOTE_GROUP_OP_REQUEST);
groupStoreEntriesByKey.destroy();
auditPendingReqQueue.destroy();
log.info("Stopped");
@@ -313,8 +277,6 @@ public class DistributedGroupStore
@Override
public Iterable<Group> getGroups(DeviceId deviceId) {
// flatten and make iterator unmodifiable
- log.debug("getGroups: for device {} total number of groups {}",
- deviceId, getGroupStoreKeyMap().values().size());
return FluentIterable.from(getGroupStoreKeyMap().values())
.filter(input -> input.deviceId().equals(deviceId))
.transform(input -> input);
@@ -322,8 +284,6 @@ public class DistributedGroupStore
private Iterable<StoredGroupEntry> getStoredGroups(DeviceId deviceId) {
// flatten and make iterator unmodifiable
- log.debug("getGroups: for device {} total number of groups {}",
- deviceId, getGroupStoreKeyMap().values().size());
return FluentIterable.from(getGroupStoreKeyMap().values())
.filter(input -> input.deviceId().equals(deviceId));
}
@@ -411,7 +371,7 @@ public class DistributedGroupStore
clusterCommunicator.unicast(groupOp,
GroupStoreMessageSubjects.REMOTE_GROUP_OP_REQUEST,
- m -> kryoBuilder.build().serialize(m),
+ clusterMsgSerializer::serialize,
mastershipService.getMasterFor(groupDesc.deviceId())).whenComplete((result, error) -> {
if (error != null) {
log.warn("Failed to send request to master: {} to {}",
@@ -609,7 +569,7 @@ public class DistributedGroupStore
clusterCommunicator.unicast(groupOp,
GroupStoreMessageSubjects.REMOTE_GROUP_OP_REQUEST,
- m -> kryoBuilder.build().serialize(m),
+ clusterMsgSerializer::serialize,
mastershipService.getMasterFor(deviceId)).whenComplete((result, error) -> {
if (error != null) {
log.warn("Failed to send request to master: {} to {}",
@@ -741,7 +701,7 @@ public class DistributedGroupStore
clusterCommunicator.unicast(groupOp,
GroupStoreMessageSubjects.REMOTE_GROUP_OP_REQUEST,
- m -> kryoBuilder.build().serialize(m),
+ clusterMsgSerializer::serialize,
mastershipService.getMasterFor(deviceId)).whenComplete((result, error) -> {
if (error != null) {
log.warn("Failed to send request to master: {} to {}",
diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/host/impl/ECHostStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/host/impl/ECHostStore.java
index d0b827cd..f9c96891 100644
--- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/host/impl/ECHostStore.java
+++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/host/impl/ECHostStore.java
@@ -27,6 +27,7 @@ import static org.onosproject.store.service.EventuallyConsistentMapEvent.Type.RE
import static org.slf4j.LoggerFactory.getLogger;
import java.util.Collection;
+import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
@@ -67,7 +68,6 @@ import org.onosproject.store.service.StorageService;
import org.slf4j.Logger;
import com.google.common.collect.HashMultimap;
-import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimaps;
import com.google.common.collect.SetMultimap;
@@ -197,6 +197,35 @@ public class ECHostStore
}
@Override
+ public HostEvent removeIp(HostId hostId, IpAddress ipAddress) {
+ DefaultHost host = hosts.compute(hostId, (id, existingHost) -> {
+ if (existingHost != null) {
+ checkState(Objects.equals(hostId.mac(), existingHost.mac()),
+ "Existing and new MAC addresses differ.");
+ checkState(Objects.equals(hostId.vlanId(), existingHost.vlan()),
+ "Existing and new VLANs differ.");
+
+ Set<IpAddress> addresses = existingHost.ipAddresses();
+ if (addresses != null && addresses.contains(ipAddress)) {
+ addresses = new HashSet<>(existingHost.ipAddresses());
+ addresses.remove(ipAddress);
+ return new DefaultHost(existingHost.providerId(),
+ hostId,
+ existingHost.mac(),
+ existingHost.vlan(),
+ existingHost.location(),
+ ImmutableSet.copyOf(addresses),
+ existingHost.annotations());
+ } else {
+ return existingHost;
+ }
+ }
+ return null;
+ });
+ return host != null ? new HostEvent(HOST_UPDATED, host) : null;
+ }
+
+ @Override
public int getHostCount() {
return hosts.size();
}
@@ -228,17 +257,23 @@ public class ECHostStore
@Override
public Set<Host> getConnectedHosts(ConnectPoint connectPoint) {
- return ImmutableSet.copyOf(locations.get(connectPoint));
+ synchronized (locations) {
+ return ImmutableSet.copyOf(locations.get(connectPoint));
+ }
}
@Override
public Set<Host> getConnectedHosts(DeviceId deviceId) {
- return ImmutableMultimap.copyOf(locations)
- .entries()
- .stream()
- .filter(entry -> entry.getKey().deviceId().equals(deviceId))
- .map(entry -> entry.getValue())
- .collect(Collectors.toSet());
+ Set<Host> filtered;
+ synchronized (locations) {
+ filtered = locations
+ .entries()
+ .stream()
+ .filter(entry -> entry.getKey().deviceId().equals(deviceId))
+ .map(entry -> entry.getValue())
+ .collect(Collectors.toSet());
+ }
+ return ImmutableSet.copyOf(filtered);
}
private Set<Host> filter(Collection<DefaultHost> collection, Predicate<DefaultHost> predicate) {
diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/intent/impl/GossipIntentStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/intent/impl/GossipIntentStore.java
index fa3a0751..1e5db99c 100644
--- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/intent/impl/GossipIntentStore.java
+++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/intent/impl/GossipIntentStore.java
@@ -193,7 +193,7 @@ public class GossipIntentStore
private Collection<NodeId> getPeerNodes(Key key, IntentData data) {
NodeId master = partitionService.getLeader(key);
NodeId origin = (data != null) ? data.origin() : null;
- if (master == null || origin == null) {
+ if (data != null && (master == null || origin == null)) {
log.debug("Intent {} missing master and/or origin; master = {}, origin = {}",
key, master, origin);
}
diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/link/impl/GossipLinkStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/link/impl/GossipLinkStore.java
index 105c77df..47aa85c5 100644
--- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/link/impl/GossipLinkStore.java
+++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/link/impl/GossipLinkStore.java
@@ -826,7 +826,7 @@ public class GossipLinkStore
public void handle(ClusterMessage message) {
log.trace("Received link event from peer: {}", message.sender());
- InternalLinkEvent event = (InternalLinkEvent) SERIALIZER.decode(message.payload());
+ InternalLinkEvent event = SERIALIZER.decode(message.payload());
ProviderId providerId = event.providerId();
Timestamped<LinkDescription> linkDescription = event.linkDescription();
@@ -845,7 +845,7 @@ public class GossipLinkStore
public void handle(ClusterMessage message) {
log.trace("Received link removed event from peer: {}", message.sender());
- InternalLinkRemovedEvent event = (InternalLinkRemovedEvent) SERIALIZER.decode(message.payload());
+ InternalLinkRemovedEvent event = SERIALIZER.decode(message.payload());
LinkKey linkKey = event.linkKey();
Timestamp timestamp = event.timestamp();
diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/packet/impl/DistributedPacketStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/packet/impl/DistributedPacketStore.java
index d4c89c93..f0f3eb5e 100644
--- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/packet/impl/DistributedPacketStore.java
+++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/packet/impl/DistributedPacketStore.java
@@ -15,7 +15,9 @@
*/
package org.onosproject.store.packet.impl;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
+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;
@@ -41,14 +43,13 @@ import org.onosproject.store.serializers.KryoSerializer;
import org.onosproject.store.service.ConsistentMap;
import org.onosproject.store.service.Serializer;
import org.onosproject.store.service.StorageService;
-import org.onosproject.store.service.Versioned;
import org.slf4j.Logger;
-import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicBoolean;
import static org.onlab.util.Tools.groupedThreads;
import static org.slf4j.LoggerFactory.getLogger;
@@ -117,6 +118,7 @@ public class DistributedPacketStore
public void deactivate() {
communicationService.removeSubscriber(PACKET_OUT_SUBJECT);
messageHandlingExecutor.shutdown();
+ tracker = null;
log.info("Stopped");
}
@@ -143,13 +145,13 @@ public class DistributedPacketStore
}
@Override
- public boolean requestPackets(PacketRequest request) {
- return tracker.add(request);
+ public void requestPackets(PacketRequest request) {
+ tracker.add(request);
}
@Override
- public boolean cancelPackets(PacketRequest request) {
- return tracker.remove(request);
+ public void cancelPackets(PacketRequest request) {
+ tracker.remove(request);
}
@Override
@@ -169,33 +171,50 @@ public class DistributedPacketStore
.build();
}
- public boolean add(PacketRequest request) {
- Versioned<Set<PacketRequest>> old = requests.get(request.selector());
- if (old != null && old.value().contains(request)) {
- return false;
+ public void add(PacketRequest request) {
+ AtomicBoolean firstRequest = new AtomicBoolean(false);
+ requests.compute(request.selector(), (s, existingRequests) -> {
+ if (existingRequests == null) {
+ firstRequest.set(true);
+ return ImmutableSet.of(request);
+ } else if (!existingRequests.contains(request)) {
+ return ImmutableSet.<PacketRequest>builder()
+ .addAll(existingRequests)
+ .add(request)
+ .build();
+ } else {
+ return existingRequests;
+ }
+ });
+
+ if (firstRequest.get() && delegate != null) {
+ // The instance that makes the first request will push to all devices
+ delegate.requestPackets(request);
}
- // FIXME: add retry logic using a random delay
- Set<PacketRequest> newSet = new HashSet<>();
- newSet.add(request);
- if (old == null) {
- return requests.putIfAbsent(request.selector(), newSet) == null;
- }
- newSet.addAll(old.value());
- return requests.replace(request.selector(), old.version(), newSet);
}
- public boolean remove(PacketRequest request) {
- Versioned<Set<PacketRequest>> old = requests.get(request.selector());
- if (old == null || !old.value().contains(request)) {
- return false;
- }
- // FIXME: add retry logic using a random delay
- Set<PacketRequest> newSet = new HashSet<>(old.value());
- newSet.remove(request);
- if (newSet.isEmpty()) {
- return requests.remove(request.selector(), old.version());
+ public void remove(PacketRequest request) {
+ AtomicBoolean removedLast = new AtomicBoolean(false);
+ requests.computeIfPresent(request.selector(), (s, existingRequests) -> {
+ if (existingRequests.contains(request)) {
+ Set<PacketRequest> newRequests = Sets.newHashSet(existingRequests);
+ newRequests.remove(request);
+ if (newRequests.size() > 0) {
+ return ImmutableSet.copyOf(newRequests);
+ } else {
+ removedLast.set(true);
+ return null;
+ }
+ } else {
+ return existingRequests;
+ }
+ });
+
+ if (removedLast.get() && delegate != null) {
+ // The instance that removes the last request will remove from all devices
+ delegate.cancelPackets(request);
}
- return requests.replace(request.selector(), old.version(), newSet);
+
}
public List<PacketRequest> requests() {
@@ -204,6 +223,5 @@ public class DistributedPacketStore
list.sort((o1, o2) -> o1.priority().priorityValue() - o2.priority().priorityValue());
return list;
}
-
}
}
diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentIntentSetMultimap.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentIntentSetMultimap.java
new file mode 100644
index 00000000..87e67215
--- /dev/null
+++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentIntentSetMultimap.java
@@ -0,0 +1,111 @@
+/*
+ * 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.resource.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.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.intent.IntentId;
+import org.onosproject.net.resource.device.IntentSetMultimap;
+import org.onosproject.store.serializers.KryoNamespaces;
+import org.onosproject.store.service.ConsistentMap;
+import org.onosproject.store.service.Serializer;
+import org.onosproject.store.service.StorageService;
+import org.onosproject.store.service.Versioned;
+import org.slf4j.Logger;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * A collection that maps Intent IDs as keys to values as Intent IDs,
+ * where each key may associated with multiple values without duplication.
+ */
+@Component(immediate = true, enabled = true)
+@Service
+public class ConsistentIntentSetMultimap implements IntentSetMultimap {
+ private final Logger log = getLogger(getClass());
+
+ private static final String INTENT_MAPPING = "IntentMapping";
+
+ private static final Serializer SERIALIZER = Serializer.using(KryoNamespaces.API);
+
+ private ConsistentMap<IntentId, Set<IntentId>> intentMapping;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected StorageService storageService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected DeviceService deviceService;
+
+ @Activate
+ public void activate() {
+ intentMapping = storageService.<IntentId, Set<IntentId>>consistentMapBuilder()
+ .withName(INTENT_MAPPING)
+ .withSerializer(SERIALIZER)
+ .build();
+ log.info("Started");
+ }
+
+ @Deactivate
+ public void deactivate() {
+ log.info("Stopped");
+ }
+
+ @Override
+ public Set<IntentId> getMapping(IntentId intentId) {
+ Versioned<Set<IntentId>> result = intentMapping.get(intentId);
+
+ if (result != null) {
+ return result.value();
+ }
+
+ return null;
+ }
+
+ @Override
+ public boolean allocateMapping(IntentId keyIntentId, IntentId valIntentId) {
+ Versioned<Set<IntentId>> versionedIntents = intentMapping.get(keyIntentId);
+
+ if (versionedIntents == null) {
+ Set<IntentId> newSet = new HashSet<>();
+ newSet.add(valIntentId);
+ intentMapping.put(keyIntentId, newSet);
+ } else {
+ versionedIntents.value().add(valIntentId);
+ }
+
+ return true;
+ }
+
+ @Override
+ public void releaseMapping(IntentId intentId) {
+ for (IntentId intent : intentMapping.keySet()) {
+ // TODO: optimize by checking for identical src & dst
+ Set<IntentId> mapping = intentMapping.get(intent).value();
+ if (mapping.remove(intentId)) {
+ return;
+ }
+ }
+ }
+
+}
diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentLinkResourceStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentLinkResourceStore.java
index 3a296353..11137aa2 100644
--- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentLinkResourceStore.java
+++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentLinkResourceStore.java
@@ -40,7 +40,6 @@ import org.onosproject.net.Link;
import org.onosproject.net.LinkKey;
import org.onosproject.net.Port;
import org.onosproject.net.intent.IntentId;
-import org.onosproject.net.link.LinkService;
import org.onosproject.net.resource.link.BandwidthResource;
import org.onosproject.net.resource.link.BandwidthResourceAllocation;
import org.onosproject.net.resource.link.LambdaResource;
@@ -69,7 +68,6 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
import static org.slf4j.LoggerFactory.getLogger;
import static org.onosproject.net.AnnotationKeys.BANDWIDTH;
@@ -108,9 +106,6 @@ public class ConsistentLinkResourceStore extends
protected StorageService storageService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected LinkService linkService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DeviceService deviceService;
@Activate
@@ -139,29 +134,30 @@ public class ConsistentLinkResourceStore extends
return storageService.transactionContextBuilder().build();
}
- private Set<? extends ResourceAllocation> getResourceCapacity(ResourceType type, Link link) {
- if (type == ResourceType.BANDWIDTH) {
- return ImmutableSet.of(getBandwidthResourceCapacity(link));
- }
- if (type == ResourceType.LAMBDA) {
- return getLambdaResourceCapacity(link);
+ private Set<ResourceAllocation> getResourceCapacity(ResourceType type, Link link) {
+ switch (type) {
+ case BANDWIDTH:
+ return ImmutableSet.of(getBandwidthResourceCapacity(link));
+ case LAMBDA:
+ return getLambdaResourceCapacity(link);
+ case MPLS_LABEL:
+ return getMplsResourceCapacity();
+ default:
+ return ImmutableSet.of();
}
- if (type == ResourceType.MPLS_LABEL) {
- return getMplsResourceCapacity();
- }
- return ImmutableSet.of();
}
- private Set<LambdaResourceAllocation> getLambdaResourceCapacity(Link link) {
- Set<LambdaResourceAllocation> allocations = new HashSet<>();
+ private Set<ResourceAllocation> getLambdaResourceCapacity(Link link) {
Port port = deviceService.getPort(link.src().deviceId(), link.src().port());
- if (port instanceof OmsPort) {
- OmsPort omsPort = (OmsPort) port;
+ if (!(port instanceof OmsPort)) {
+ return Collections.emptySet();
+ }
- // Assume fixed grid for now
- for (int i = 0; i < omsPort.totalChannels(); i++) {
- allocations.add(new LambdaResourceAllocation(LambdaResource.valueOf(i)));
- }
+ OmsPort omsPort = (OmsPort) port;
+ Set<ResourceAllocation> allocations = new HashSet<>();
+ // Assume fixed grid for now
+ for (int i = 0; i < omsPort.totalChannels(); i++) {
+ allocations.add(new LambdaResourceAllocation(LambdaResource.valueOf(i)));
}
return allocations;
}
@@ -170,26 +166,23 @@ public class ConsistentLinkResourceStore extends
// if Link annotation exist, use them
// if all fails, use DEFAULT_BANDWIDTH
- BandwidthResource bandwidth = null;
+ BandwidthResource bandwidth = DEFAULT_BANDWIDTH;
String strBw = link.annotations().value(BANDWIDTH);
- if (strBw != null) {
- try {
- bandwidth = new BandwidthResource(Bandwidth.mbps(Double.parseDouble(strBw)));
- } catch (NumberFormatException e) {
- // do nothings
- bandwidth = null;
- }
+ if (strBw == null) {
+ return new BandwidthResourceAllocation(bandwidth);
}
- if (bandwidth == null) {
- // fall back, use fixed default
+ try {
+ bandwidth = new BandwidthResource(Bandwidth.mbps(Double.parseDouble(strBw)));
+ } catch (NumberFormatException e) {
+ // do nothings, use default bandwidth
bandwidth = DEFAULT_BANDWIDTH;
}
return new BandwidthResourceAllocation(bandwidth);
}
- private Set<MplsLabelResourceAllocation> getMplsResourceCapacity() {
- Set<MplsLabelResourceAllocation> allocations = new HashSet<>();
+ private Set<ResourceAllocation> getMplsResourceCapacity() {
+ Set<ResourceAllocation> allocations = new HashSet<>();
//Ignoring reserved labels of 0 through 15
for (int i = MIN_UNRESERVED_LABEL; i <= MAX_UNRESERVED_LABEL; i++) {
allocations.add(new MplsLabelResourceAllocation(MplsLabel
@@ -199,13 +192,11 @@ public class ConsistentLinkResourceStore extends
return allocations;
}
- private Map<ResourceType, Set<? extends ResourceAllocation>> getResourceCapacity(Link link) {
- Map<ResourceType, Set<? extends ResourceAllocation>> caps = new HashMap<>();
+ private Map<ResourceType, Set<ResourceAllocation>> getResourceCapacity(Link link) {
+ Map<ResourceType, Set<ResourceAllocation>> caps = new HashMap<>();
for (ResourceType type : ResourceType.values()) {
- Set<? extends ResourceAllocation> cap = getResourceCapacity(type, link);
- if (cap != null) {
- caps.put(type, cap);
- }
+ Set<ResourceAllocation> cap = getResourceCapacity(type, link);
+ caps.put(type, cap);
}
return caps;
}
@@ -216,106 +207,80 @@ public class ConsistentLinkResourceStore extends
tx.begin();
try {
- Map<ResourceType, Set<? extends ResourceAllocation>> freeResources = getFreeResourcesEx(tx, link);
- Set<ResourceAllocation> allFree = new HashSet<>();
- freeResources.values().forEach(allFree::addAll);
- return allFree;
+ Map<ResourceType, Set<ResourceAllocation>> freeResources = getFreeResourcesEx(tx, link);
+ return freeResources.values().stream()
+ .flatMap(Collection::stream)
+ .collect(Collectors.toSet());
} finally {
tx.abort();
}
}
- private Map<ResourceType, Set<? extends ResourceAllocation>> getFreeResourcesEx(TransactionContext tx, Link link) {
+ private Map<ResourceType, Set<ResourceAllocation>> getFreeResourcesEx(TransactionContext tx, Link link) {
checkNotNull(tx);
checkNotNull(link);
- Map<ResourceType, Set<? extends ResourceAllocation>> free = new HashMap<>();
- final Map<ResourceType, Set<? extends ResourceAllocation>> caps = getResourceCapacity(link);
- final Iterable<LinkResourceAllocations> allocations = getAllocations(tx, link);
+ Map<ResourceType, Set<ResourceAllocation>> free = new HashMap<>();
+ final Map<ResourceType, Set<ResourceAllocation>> caps = getResourceCapacity(link);
+ final List<LinkResourceAllocations> allocations = ImmutableList.copyOf(getAllocations(tx, link));
- for (ResourceType type : ResourceType.values()) {
- // there should be class/category of resources
+ Set<ResourceAllocation> bw = caps.get(ResourceType.BANDWIDTH);
+ Set<ResourceAllocation> value = getFreeBandwidthResources(link, bw, allocations);
+ free.put(ResourceType.BANDWIDTH, value);
- switch (type) {
- case BANDWIDTH:
- Set<? extends ResourceAllocation> bw = caps.get(type);
- if (bw == null || bw.isEmpty()) {
- bw = Sets.newHashSet(new BandwidthResourceAllocation(EMPTY_BW));
- }
+ Set<ResourceAllocation> lmd = caps.get(ResourceType.LAMBDA);
+ Set<ResourceAllocation> freeL = getFreeResources(link, lmd, allocations,
+ LambdaResourceAllocation.class);
+ free.put(ResourceType.LAMBDA, freeL);
- BandwidthResourceAllocation cap = (BandwidthResourceAllocation) bw.iterator().next();
- double freeBw = cap.bandwidth().toDouble();
-
- // enumerate current allocations, subtracting resources
- for (LinkResourceAllocations alloc : allocations) {
- Set<ResourceAllocation> types = alloc.getResourceAllocation(link);
- for (ResourceAllocation a : types) {
- if (a instanceof BandwidthResourceAllocation) {
- BandwidthResourceAllocation bwA = (BandwidthResourceAllocation) a;
- freeBw -= bwA.bandwidth().toDouble();
- }
- }
- }
+ Set<ResourceAllocation> mpls = caps.get(ResourceType.MPLS_LABEL);
+ Set<ResourceAllocation> freeLabel = getFreeResources(link, mpls, allocations,
+ MplsLabelResourceAllocation.class);
+ free.put(ResourceType.MPLS_LABEL, freeLabel);
- free.put(type, Sets.newHashSet(
- new BandwidthResourceAllocation(new BandwidthResource(Bandwidth.bps(freeBw)))));
- break;
- case LAMBDA:
- Set<? extends ResourceAllocation> lmd = caps.get(type);
- if (lmd == null || lmd.isEmpty()) {
- // nothing left
- break;
- }
- Set<LambdaResourceAllocation> freeL = new HashSet<>();
- for (ResourceAllocation r : lmd) {
- if (r instanceof LambdaResourceAllocation) {
- freeL.add((LambdaResourceAllocation) r);
- }
- }
-
- // enumerate current allocations, removing resources
- for (LinkResourceAllocations alloc : allocations) {
- Set<ResourceAllocation> types = alloc.getResourceAllocation(link);
- for (ResourceAllocation a : types) {
- if (a instanceof LambdaResourceAllocation) {
- freeL.remove(a);
- }
- }
- }
+ return free;
+ }
- free.put(type, freeL);
- break;
- case MPLS_LABEL:
- Set<? extends ResourceAllocation> mpls = caps.get(type);
- if (mpls == null || mpls.isEmpty()) {
- // nothing left
- break;
- }
- Set<MplsLabelResourceAllocation> freeLabel = new HashSet<>();
- for (ResourceAllocation r : mpls) {
- if (r instanceof MplsLabelResourceAllocation) {
- freeLabel.add((MplsLabelResourceAllocation) r);
- }
- }
+ private Set<ResourceAllocation> getFreeBandwidthResources(Link link, Set<ResourceAllocation> bw,
+ List<LinkResourceAllocations> allocations) {
+ if (bw == null || bw.isEmpty()) {
+ bw = Sets.newHashSet(new BandwidthResourceAllocation(EMPTY_BW));
+ }
- // enumerate current allocations, removing resources
- for (LinkResourceAllocations alloc : allocations) {
- Set<ResourceAllocation> types = alloc.getResourceAllocation(link);
- for (ResourceAllocation a : types) {
- if (a instanceof MplsLabelResourceAllocation) {
- freeLabel.remove(a);
- }
- }
- }
+ BandwidthResourceAllocation cap = (BandwidthResourceAllocation) bw.iterator().next();
+ double freeBw = cap.bandwidth().toDouble();
+
+ // enumerate current allocations, subtracting resources
+ double allocatedBw = allocations.stream()
+ .flatMap(x -> x.getResourceAllocation(link).stream())
+ .filter(x -> x instanceof BandwidthResourceAllocation)
+ .map(x -> (BandwidthResourceAllocation) x)
+ .mapToDouble(x -> x.bandwidth().toDouble())
+ .sum();
+ freeBw -= allocatedBw;
+ return Sets.newHashSet(
+ new BandwidthResourceAllocation(new BandwidthResource(Bandwidth.bps(freeBw))));
+ }
- free.put(type, freeLabel);
- break;
- default:
- log.debug("unsupported ResourceType {}", type);
- break;
- }
+ private Set<ResourceAllocation> getFreeResources(Link link,
+ Set<ResourceAllocation> resources,
+ List<LinkResourceAllocations> allocations,
+ Class<? extends ResourceAllocation> cls) {
+ if (resources == null || resources.isEmpty()) {
+ // nothing left
+ return Collections.emptySet();
}
- return free;
+ Set<ResourceAllocation> freeL = resources.stream()
+ .filter(cls::isInstance)
+ .collect(Collectors.toSet());
+
+ // enumerate current allocations, removing resources
+ List<ResourceAllocation> allocated = allocations.stream()
+ .flatMap(x -> x.getResourceAllocation(link).stream())
+ .filter(cls::isInstance)
+ .collect(Collectors.toList());
+ freeL.removeAll(allocated);
+ return freeL;
}
@Override
@@ -329,6 +294,9 @@ public class ConsistentLinkResourceStore extends
intentAllocs.put(allocations.intentId(), allocations);
allocations.links().forEach(link -> allocateLinkResource(tx, link, allocations));
tx.commit();
+ } catch (TransactionException | ResourceAllocationException e) {
+ log.error("Exception thrown, rolling back", e);
+ tx.abort();
} catch (Exception e) {
log.error("Exception thrown, rolling back", e);
tx.abort();
@@ -340,15 +308,13 @@ public class ConsistentLinkResourceStore extends
LinkResourceAllocations allocations) {
// requested resources
Set<ResourceAllocation> reqs = allocations.getResourceAllocation(link);
- Map<ResourceType, Set<? extends ResourceAllocation>> available = getFreeResourcesEx(tx, link);
+ Map<ResourceType, Set<ResourceAllocation>> available = getFreeResourcesEx(tx, link);
for (ResourceAllocation req : reqs) {
- Set<? extends ResourceAllocation> avail = available.get(req.type());
+ Set<ResourceAllocation> avail = available.get(req.type());
if (req instanceof BandwidthResourceAllocation) {
// check if allocation should be accepted
if (avail.isEmpty()) {
- checkState(!avail.isEmpty(),
- "There's no Bandwidth resource on %s?",
- link);
+ throw new ResourceAllocationException(String.format("There's no Bandwidth resource on %s?", link));
}
BandwidthResourceAllocation bw = (BandwidthResourceAllocation) avail.iterator().next();
double bwLeft = bw.bandwidth().toDouble();
@@ -395,12 +361,7 @@ public class ConsistentLinkResourceStore extends
if (before == null) {
List<LinkResourceAllocations> after = new ArrayList<>();
after.add(allocations);
- before = linkAllocs.putIfAbsent(linkKey, after);
- if (before != null) {
- // concurrent allocation detected, retry transaction : is this needed?
- log.warn("Concurrent Allocation, retrying");
- throw new TransactionException();
- }
+ linkAllocs.putIfAbsent(linkKey, after);
} else {
List<LinkResourceAllocations> after = new ArrayList<>(before.size() + 1);
after.addAll(before);
@@ -500,19 +461,18 @@ public class ConsistentLinkResourceStore extends
checkNotNull(link);
final LinkKey key = LinkKey.linkKey(link);
TransactionalMap<LinkKey, List<LinkResourceAllocations>> linkAllocs = getLinkAllocs(tx);
- List<LinkResourceAllocations> res = null;
- res = linkAllocs.get(key);
- if (res == null) {
- res = linkAllocs.putIfAbsent(key, new ArrayList<>());
+ List<LinkResourceAllocations> res = linkAllocs.get(key);
+ if (res != null) {
+ return res;
+ }
- if (res == null) {
- return Collections.emptyList();
- } else {
- return res;
- }
+ res = linkAllocs.putIfAbsent(key, new ArrayList<>());
+ if (res == null) {
+ return Collections.emptyList();
+ } else {
+ return res;
}
- return res;
}
}
diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/statistic/impl/DistributedFlowStatisticStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/statistic/impl/DistributedFlowStatisticStore.java
new file mode 100644
index 00000000..0cd4a831
--- /dev/null
+++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/statistic/impl/DistributedFlowStatisticStore.java
@@ -0,0 +1,289 @@
+/*
+ * 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.statistic.impl;
+
+import com.google.common.base.Objects;
+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.util.KryoNamespace;
+import org.onlab.util.Tools;
+import org.onosproject.cluster.ClusterService;
+import org.onosproject.cluster.NodeId;
+import org.onosproject.mastership.MastershipService;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.FlowEntry;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.Instructions;
+import org.onosproject.net.statistic.FlowStatisticStore;
+import org.onosproject.store.cluster.messaging.ClusterCommunicationService;
+import org.onosproject.store.serializers.KryoNamespaces;
+import org.onosproject.store.serializers.KryoSerializer;
+import org.slf4j.Logger;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.store.statistic.impl.StatisticStoreMessageSubjects.GET_CURRENT;
+import static org.onosproject.store.statistic.impl.StatisticStoreMessageSubjects.GET_PREVIOUS;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Maintains flow statistics using RPC calls to collect stats from remote instances
+ * on demand.
+ */
+@Component(immediate = true)
+@Service
+public class DistributedFlowStatisticStore implements FlowStatisticStore {
+ private final Logger log = getLogger(getClass());
+
+ // TODO: Make configurable.
+ private static final int MESSAGE_HANDLER_THREAD_POOL_SIZE = 4;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected MastershipService mastershipService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected ClusterCommunicationService clusterCommunicator;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected ClusterService clusterService;
+
+ private Map<ConnectPoint, Set<FlowEntry>> previous =
+ new ConcurrentHashMap<>();
+
+ private Map<ConnectPoint, Set<FlowEntry>> current =
+ new ConcurrentHashMap<>();
+
+ protected static final KryoSerializer SERIALIZER = new KryoSerializer() {
+ @Override
+ protected void setupKryoPool() {
+ serializerPool = KryoNamespace.newBuilder()
+ .register(KryoNamespaces.API)
+ .nextId(KryoNamespaces.BEGIN_USER_CUSTOM_ID)
+ // register this store specific classes here
+ .build();
+ }
+ };
+
+ private NodeId local;
+ private ExecutorService messageHandlingExecutor;
+
+ private static final long STATISTIC_STORE_TIMEOUT_MILLIS = 3000;
+
+ @Activate
+ public void activate() {
+ local = clusterService.getLocalNode().id();
+
+ messageHandlingExecutor = Executors.newFixedThreadPool(
+ MESSAGE_HANDLER_THREAD_POOL_SIZE,
+ groupedThreads("onos/store/statistic", "message-handlers"));
+
+ clusterCommunicator.addSubscriber(
+ GET_CURRENT, SERIALIZER::decode, this::getCurrentStatisticInternal, SERIALIZER::encode,
+ messageHandlingExecutor);
+
+ clusterCommunicator.addSubscriber(
+ GET_CURRENT, SERIALIZER::decode, this::getPreviousStatisticInternal, SERIALIZER::encode,
+ messageHandlingExecutor);
+
+ log.info("Started");
+ }
+
+ @Deactivate
+ public void deactivate() {
+ clusterCommunicator.removeSubscriber(GET_PREVIOUS);
+ clusterCommunicator.removeSubscriber(GET_CURRENT);
+ messageHandlingExecutor.shutdown();
+ log.info("Stopped");
+ }
+
+ @Override
+ public synchronized void removeFlowStatistic(FlowRule rule) {
+ ConnectPoint cp = buildConnectPoint(rule);
+ if (cp == null) {
+ return;
+ }
+
+ // remove this rule if present from current map
+ current.computeIfPresent(cp, (c, e) -> { e.remove(rule); return e; });
+
+ // remove this on if present from previous map
+ previous.computeIfPresent(cp, (c, e) -> { e.remove(rule); return e; });
+ }
+
+ @Override
+ public synchronized void addFlowStatistic(FlowEntry rule) {
+ ConnectPoint cp = buildConnectPoint(rule);
+ if (cp == null) {
+ return;
+ }
+
+ // create one if absent and add this rule
+ current.putIfAbsent(cp, new HashSet<>());
+ current.computeIfPresent(cp, (c, e) -> { e.add(rule); return e; });
+
+ // remove previous one if present
+ previous.computeIfPresent(cp, (c, e) -> { e.remove(rule); return e; });
+ }
+
+ public synchronized void updateFlowStatistic(FlowEntry rule) {
+ ConnectPoint cp = buildConnectPoint(rule);
+ if (cp == null) {
+ return;
+ }
+
+ Set<FlowEntry> curr = current.get(cp);
+ if (curr == null) {
+ addFlowStatistic(rule);
+ } else {
+ Optional<FlowEntry> f = curr.stream().filter(c -> rule.equals(c)).
+ findAny();
+ if (f.isPresent() && rule.bytes() < f.get().bytes()) {
+ log.debug("DistributedFlowStatisticStore:updateFlowStatistic():" +
+ " Invalid Flow Update! Will be removed!!" +
+ " curr flowId=" + Long.toHexString(rule.id().value()) +
+ ", prev flowId=" + Long.toHexString(f.get().id().value()) +
+ ", curr bytes=" + rule.bytes() + ", prev bytes=" + f.get().bytes() +
+ ", curr life=" + rule.life() + ", prev life=" + f.get().life() +
+ ", curr lastSeen=" + rule.lastSeen() + ", prev lastSeen=" + f.get().lastSeen());
+ // something is wrong! invalid flow entry, so delete it
+ removeFlowStatistic(rule);
+ return;
+ }
+ Set<FlowEntry> prev = previous.get(cp);
+ if (prev == null) {
+ prev = new HashSet<>();
+ previous.put(cp, prev);
+ }
+
+ // previous one is exist
+ if (f.isPresent()) {
+ // remove old one and add new one
+ prev.remove(rule);
+ if (!prev.add(f.get())) {
+ log.debug("DistributedFlowStatisticStore:updateFlowStatistic():" +
+ " flowId={}, add failed into previous.",
+ Long.toHexString(rule.id().value()));
+ }
+ }
+
+ // remove old one and add new one
+ curr.remove(rule);
+ if (!curr.add(rule)) {
+ log.debug("DistributedFlowStatisticStore:updateFlowStatistic():" +
+ " flowId={}, add failed into current.",
+ Long.toHexString(rule.id().value()));
+ }
+ }
+ }
+
+ @Override
+ public Set<FlowEntry> getCurrentFlowStatistic(ConnectPoint connectPoint) {
+ final DeviceId deviceId = connectPoint.deviceId();
+
+ NodeId master = mastershipService.getMasterFor(deviceId);
+ if (master == null) {
+ log.warn("No master for {}", deviceId);
+ return Collections.emptySet();
+ }
+
+ if (Objects.equal(local, master)) {
+ return getCurrentStatisticInternal(connectPoint);
+ } else {
+ return Tools.futureGetOrElse(clusterCommunicator.sendAndReceive(
+ connectPoint,
+ GET_CURRENT,
+ SERIALIZER::encode,
+ SERIALIZER::decode,
+ master),
+ STATISTIC_STORE_TIMEOUT_MILLIS,
+ TimeUnit.MILLISECONDS,
+ Collections.emptySet());
+ }
+ }
+
+ private synchronized Set<FlowEntry> getCurrentStatisticInternal(ConnectPoint connectPoint) {
+ return current.get(connectPoint);
+ }
+
+ @Override
+ public Set<FlowEntry> getPreviousFlowStatistic(ConnectPoint connectPoint) {
+ final DeviceId deviceId = connectPoint.deviceId();
+
+ NodeId master = mastershipService.getMasterFor(deviceId);
+ if (master == null) {
+ log.warn("No master for {}", deviceId);
+ return Collections.emptySet();
+ }
+
+ if (Objects.equal(local, master)) {
+ return getPreviousStatisticInternal(connectPoint);
+ } else {
+ return Tools.futureGetOrElse(clusterCommunicator.sendAndReceive(
+ connectPoint,
+ GET_PREVIOUS,
+ SERIALIZER::encode,
+ SERIALIZER::decode,
+ master),
+ STATISTIC_STORE_TIMEOUT_MILLIS,
+ TimeUnit.MILLISECONDS,
+ Collections.emptySet());
+ }
+ }
+
+ private synchronized Set<FlowEntry> getPreviousStatisticInternal(ConnectPoint connectPoint) {
+ return previous.get(connectPoint);
+ }
+
+ private ConnectPoint buildConnectPoint(FlowRule rule) {
+ PortNumber port = getOutput(rule);
+
+ if (port == null) {
+ return null;
+ }
+ ConnectPoint cp = new ConnectPoint(rule.deviceId(), port);
+ return cp;
+ }
+
+ private PortNumber getOutput(FlowRule rule) {
+ for (Instruction i : rule.treatment().allInstructions()) {
+ if (i.type() == Instruction.Type.OUTPUT) {
+ Instructions.OutputInstruction out = (Instructions.OutputInstruction) i;
+ return out.port();
+ }
+ if (i.type() == Instruction.Type.DROP) {
+ return PortNumber.P0;
+ }
+ }
+ return null;
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/topology/impl/DistributedTopologyStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/topology/impl/DistributedTopologyStore.java
index 487fad9b..da4e3cc4 100644
--- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/topology/impl/DistributedTopologyStore.java
+++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/topology/impl/DistributedTopologyStore.java
@@ -21,6 +21,7 @@ import static org.onosproject.net.topology.TopologyEvent.Type.TOPOLOGY_CHANGED;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.Collections;
+import java.util.Map;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@@ -40,6 +41,7 @@ import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Link;
import org.onosproject.net.Path;
+import org.onosproject.net.DisjointPath;
import org.onosproject.net.provider.ProviderId;
import org.onosproject.net.topology.ClusterId;
import org.onosproject.net.topology.DefaultGraphDescription;
@@ -74,7 +76,6 @@ public class DistributedTopologyStore
implements TopologyStore {
private final Logger log = getLogger(getClass());
-
private volatile DefaultTopology current =
new DefaultTopology(ProviderId.NONE,
new DefaultGraphDescription(0L, System.currentTimeMillis(),
@@ -167,6 +168,29 @@ public class DistributedTopologyStore
}
@Override
+ public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst) {
+ return defaultTopology(topology).getDisjointPaths(src, dst);
+ }
+
+ @Override
+ public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst,
+ LinkWeight weight) {
+ return defaultTopology(topology).getDisjointPaths(src, dst, weight);
+ }
+
+ @Override
+ public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst,
+ Map<Link, Object> riskProfile) {
+ return defaultTopology(topology).getDisjointPaths(src, dst, riskProfile);
+ }
+
+ @Override
+ public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst,
+ LinkWeight weight, Map<Link, Object> riskProfile) {
+ return defaultTopology(topology).getDisjointPaths(src, dst, weight, riskProfile);
+ }
+
+ @Override
public boolean isInfrastructure(Topology topology, ConnectPoint connectPoint) {
return defaultTopology(topology).isInfrastructure(connectPoint);
}
diff --git a/framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/host/impl/ECHostStoreTest.java b/framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/host/impl/ECHostStoreTest.java
new file mode 100644
index 00000000..a7077a81
--- /dev/null
+++ b/framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/host/impl/ECHostStoreTest.java
@@ -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.store.host.impl;
+
+import junit.framework.TestCase;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onosproject.net.Host;
+import org.onosproject.net.HostId;
+import org.onosproject.net.HostLocation;
+import org.onosproject.net.host.DefaultHostDescription;
+import org.onosproject.net.host.HostDescription;
+import org.onosproject.net.provider.ProviderId;
+import org.onosproject.store.Timestamp;
+import org.onosproject.store.service.LogicalClockService;
+import org.onosproject.store.service.TestStorageService;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Tests for the ECHostStore.
+ */
+public class ECHostStoreTest extends TestCase {
+
+ private ECHostStore ecXHostStore;
+
+ private static final HostId HOSTID = HostId.hostId(MacAddress.valueOf("1a:1a:1a:1a:1a:1a"));
+
+ private static final IpAddress IP1 = IpAddress.valueOf("10.2.0.2");
+ private static final IpAddress IP2 = IpAddress.valueOf("10.2.0.3");
+
+ private static final ProviderId PID = new ProviderId("of", "foo");
+
+ @Before
+ public void setUp() {
+ ecXHostStore = new ECHostStore();
+
+ ecXHostStore.storageService = new TestStorageService();
+ ecXHostStore.clockService = new TestLogicalClockService();
+ ecXHostStore.activate();
+ }
+
+ @After
+ public void tearDown() {
+ ecXHostStore.deactivate();
+ }
+
+ /**
+ * Tests the removeIp method call.
+ */
+ @Test
+ public void testRemoveIp() {
+ Set<IpAddress> ips = new HashSet<>();
+ ips.add(IP1);
+ ips.add(IP2);
+
+ HostDescription description = new DefaultHostDescription(HOSTID.mac(),
+ HOSTID.vlanId(),
+ HostLocation.NONE,
+ ips);
+ ecXHostStore.createOrUpdateHost(PID, HOSTID, description, false);
+ ecXHostStore.removeIp(HOSTID, IP1);
+ Host host = ecXHostStore.getHost(HOSTID);
+
+ assertFalse(host.ipAddresses().contains(IP1));
+ assertTrue(host.ipAddresses().contains(IP2));
+ }
+
+ /**
+ * Mocks the LogicalClockService class.
+ */
+ class TestLogicalClockService implements LogicalClockService {
+ @Override
+ public Timestamp getTimestamp() {
+ return null;
+ }
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java b/framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java
index 66ee7be7..5b5056cb 100644
--- a/framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java
+++ b/framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java
@@ -19,7 +19,6 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
-
import org.onlab.packet.ChassisId;
import org.onlab.packet.EthType;
import org.onlab.packet.Ip4Address;
@@ -85,11 +84,11 @@ import org.onosproject.net.device.PortStatistics;
import org.onosproject.net.flow.CompletedBatchOperation;
import org.onosproject.net.flow.DefaultFlowEntry;
import org.onosproject.net.flow.DefaultFlowRule;
+import org.onosproject.net.flow.DefaultTableStatisticsEntry;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.FlowEntry;
import org.onosproject.net.flow.FlowId;
-import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.FlowRuleBatchEntry;
import org.onosproject.net.flow.FlowRuleBatchEvent;
import org.onosproject.net.flow.FlowRuleBatchOperation;
@@ -97,6 +96,7 @@ import org.onosproject.net.flow.FlowRuleBatchRequest;
import org.onosproject.net.flow.FlowRuleEvent;
import org.onosproject.net.flow.FlowRuleExtPayLoad;
import org.onosproject.net.flow.StoredFlowEntry;
+import org.onosproject.net.flow.TableStatisticsEntry;
import org.onosproject.net.flow.criteria.Criterion;
import org.onosproject.net.flow.criteria.EthCriterion;
import org.onosproject.net.flow.criteria.EthTypeCriterion;
@@ -118,7 +118,6 @@ 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.OpticalSignalTypeCriterion;
import org.onosproject.net.flow.criteria.PortCriterion;
import org.onosproject.net.flow.criteria.SctpPortCriterion;
import org.onosproject.net.flow.criteria.TcpPortCriterion;
@@ -302,7 +301,6 @@ public final class KryoNamespaces {
DefaultHostDescription.class,
DefaultFlowEntry.class,
StoredFlowEntry.class,
- FlowRule.Type.class,
DefaultFlowRule.class,
DefaultFlowEntry.class,
DefaultPacketRequest.class,
@@ -339,11 +337,11 @@ public final class KryoNamespaces {
IndexedLambdaCriterion.class,
OchSignalCriterion.class,
OchSignalTypeCriterion.class,
- OpticalSignalTypeCriterion.class,
Criterion.class,
Criterion.Type.class,
DefaultTrafficTreatment.class,
Instructions.DropInstruction.class,
+ Instructions.NoActionInstruction.class,
Instructions.OutputInstruction.class,
Instructions.GroupInstruction.class,
Instructions.TableTypeTransition.class,
@@ -425,7 +423,9 @@ public final class KryoNamespaces {
DefaultAnnotations.class,
PortStatistics.class,
DefaultPortStatistics.class,
- IntentDomainId.class
+ IntentDomainId.class,
+ TableStatisticsEntry.class,
+ DefaultTableStatisticsEntry.class
)
.register(new DefaultApplicationIdSerializer(), DefaultApplicationId.class)
.register(new URISerializer(), URI.class)
diff --git a/framework/src/onos/docs/external-excludes b/framework/src/onos/docs/external-excludes
index 34329f19..1890de18 100644
--- a/framework/src/onos/docs/external-excludes
+++ b/framework/src/onos/docs/external-excludes
@@ -46,6 +46,9 @@ org.onosproject.pcep*
org.onosproject.aaa
org.onosproject.acl*
org.onosproject.cip*
-org.onos.acl*
+org.onosproject.acl*
org.onosproject.vtn*
+org.onosproject.cord*
+org.onosproject.mfwd*
+org.onosproject.mcast*
org.onosproject.flowanalyzer
diff --git a/framework/src/onos/docs/internal-apps b/framework/src/onos/docs/internal-apps
index 8c4a493f..71aacd03 100644
--- a/framework/src/onos/docs/internal-apps
+++ b/framework/src/onos/docs/internal-apps
@@ -1,6 +1,5 @@
org.onosproject.app.*
-org.onos.acl*
org.onosproject.acl*
org.onosproject.aaa
org.onosproject.fwd
@@ -25,3 +24,7 @@ org.onosproject.cordfabric*
org.onosproject.xosintegration*
org.onosproject.cip*
org.onosproject.vtn*
+org.onosproject.cord*
+org.onosproject.mcast*
+org.onosproject.mfwd*
+org.onosproject.igmp.impl
diff --git a/framework/src/onos/drivers/pom.xml b/framework/src/onos/drivers/pom.xml
index 749a68c4..56a39a8e 100644
--- a/framework/src/onos/drivers/pom.xml
+++ b/framework/src/onos/drivers/pom.xml
@@ -55,8 +55,8 @@
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onos-core-serializers</artifactId>
- <version>1.4.0-SNAPSHOT</version>
- </dependency>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onos-ovsdb-api</artifactId>
@@ -72,6 +72,25 @@
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.scr.annotations</artifactId>
</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>onlab-junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-ovsdb-api</artifactId>
+ <version>${project.version}</version>
+ <classifier>tests</classifier>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/handshaker/OFOpticalSwitch13.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/handshaker/OFOpticalSwitch13.java
new file mode 100644
index 00000000..a62b93c8
--- /dev/null
+++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/handshaker/OFOpticalSwitch13.java
@@ -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.driver.handshaker;
+
+import org.projectfloodlight.openflow.protocol.OFExpPort;
+import org.projectfloodlight.openflow.protocol.OFExpPortDescReply;
+import org.projectfloodlight.openflow.protocol.OFExpPortDescRequest;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
+import org.projectfloodlight.openflow.protocol.OFStatsReply;
+import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
+import org.projectfloodlight.openflow.protocol.OFStatsType;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.stream.Collectors;
+
+import org.onosproject.net.Device;
+import org.onosproject.openflow.controller.OpenFlowOpticalSwitch;
+import org.onosproject.openflow.controller.PortDescPropertyType;
+import org.onosproject.openflow.controller.driver.AbstractOpenFlowSwitch;
+import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeAlreadyStarted;
+import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeCompleted;
+import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeNotStarted;
+import org.projectfloodlight.openflow.protocol.OFObject;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+
+
+/**
+ * Open Flow Optical Switch handshaker - for Open Flow 13.
+ */
+public class OFOpticalSwitch13 extends AbstractOpenFlowSwitch implements OpenFlowOpticalSwitch {
+
+ private final AtomicBoolean driverHandshakeComplete = new AtomicBoolean(false);
+ private List<OFExpPort> expPortDes = new ArrayList<>();
+
+ @Override
+ public Boolean supportNxRole() {
+ return false;
+ }
+
+ @Override
+ public void startDriverHandshake() {
+ log.info("Starting driver handshake for sw {}", getStringId());
+ if (startDriverHandshakeCalled) {
+ throw new SwitchDriverSubHandshakeAlreadyStarted();
+ }
+ startDriverHandshakeCalled = true;
+
+ log.debug("sendHandshakeOFExperimenterPortDescRequest for sw {}", getStringId());
+
+ try {
+ sendHandshakeOFExperimenterPortDescRequest();
+ } catch (IOException e) {
+ log.error("Failed to send handshaker message OFExperimenterPortDescRequestfor sw {}, {}",
+ getStringId(), e.getMessage());
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void processDriverHandshakeMessage(OFMessage m) {
+ if (!startDriverHandshakeCalled) {
+ throw new SwitchDriverSubHandshakeNotStarted();
+ }
+ if (driverHandshakeComplete.get()) {
+ throw new SwitchDriverSubHandshakeCompleted(m);
+ }
+
+ log.debug("processDriverHandshakeMessage for sw {}", getStringId());
+
+ switch (m.getType()) {
+ case STATS_REPLY: // multipart message is reported as STAT
+ processOFMultipartReply((OFStatsReply) m);
+ break;
+ default:
+ log.warn("Received message {} during switch-driver " +
+ "subhandshake " + "from switch {} ... " +
+ "Ignoring message", m,
+ getStringId());
+ }
+ }
+
+ private void processOFMultipartReply(OFStatsReply stats) {
+ log.debug("Received message {} during switch-driver " +
+ "subhandshake " + "from switch {} ... " +
+ stats,
+ getStringId());
+
+ if (stats.getStatsType() == OFStatsType.EXPERIMENTER) {
+ try {
+ OFExpPortDescReply expPortDescReply = (OFExpPortDescReply) stats;
+ expPortDes.addAll(expPortDescReply.getEntries());
+ if (!expPortDescReply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
+ driverHandshakeComplete.set(true);
+ return;
+ }
+ } catch (ClassCastException e) {
+ log.error("Unexspected Experimenter Multipart message type {} "
+ , stats.getClass().getName());
+ }
+ }
+ }
+
+
+ @Override
+ public boolean isDriverHandshakeComplete() {
+ return driverHandshakeComplete.get();
+ }
+
+ private void sendHandshakeOFExperimenterPortDescRequest() throws
+ IOException {
+
+ OFExpPortDescRequest preq = factory()
+ .buildExpPortDescRequest()
+ .setXid(getNextTransactionId())
+ .build();
+
+ log.debug("Sending experimented port description " +
+ "message " +
+ "{}",
+ preq.toString());
+
+ this.sendHandshakeMessage(preq);
+ }
+
+ @Override
+ public Device.Type deviceType() {
+ return Device.Type.ROADM;
+ }
+
+ /*
+ * OduClt ports are reported as regular ETH ports.
+ */
+ @Override
+ public List<OFPortDesc> getPorts() {
+ return ImmutableList.copyOf(
+ ports.stream().flatMap(p -> p.getEntries().stream())
+ .collect(Collectors.toList()));
+ }
+
+ @Override
+ public List<? extends OFObject> getPortsOf(PortDescPropertyType type) {
+ return ImmutableList.copyOf(expPortDes);
+ }
+
+ @Override
+ public Set<PortDescPropertyType> getPortTypes() {
+ return ImmutableSet.of(PortDescPropertyType.OPTICAL_TRANSPORT);
+ }
+
+}
diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/ovsdb/OvsdbControllerConfig.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/ovsdb/OvsdbControllerConfig.java
new file mode 100644
index 00000000..a00d3dbc
--- /dev/null
+++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/ovsdb/OvsdbControllerConfig.java
@@ -0,0 +1,102 @@
+/*
+ * 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.ovsdb;
+
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.TpPort;
+import org.onosproject.net.AnnotationKeys;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.behaviour.ControllerConfig;
+import org.onosproject.net.behaviour.ControllerInfo;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.net.driver.DriverHandler;
+import org.onosproject.ovsdb.controller.OvsdbBridge;
+import org.onosproject.ovsdb.controller.OvsdbClientService;
+import org.onosproject.ovsdb.controller.OvsdbController;
+import org.onosproject.ovsdb.controller.OvsdbNodeId;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static com.google.common.base.Preconditions.checkState;
+import static org.onlab.util.Tools.delay;
+
+/**
+ * Implementation of controller config which allows to get and set controllers.
+ */
+public class OvsdbControllerConfig extends AbstractHandlerBehaviour implements ControllerConfig {
+ @Override
+ public List<ControllerInfo> getControllers() {
+ DriverHandler handler = handler();
+ OvsdbClientService clientService = getOvsdbClientService(handler);
+ Set<ControllerInfo> controllers = clientService.getControllers(
+ handler().data().deviceId());
+ return new ArrayList<>(controllers);
+ }
+
+ @Override
+ public void setControllers(List<ControllerInfo> controllers) {
+ DriverHandler handler = handler();
+ OvsdbClientService clientService = getOvsdbClientService(handler);
+ if (!clientService.getControllers(handler().data().deviceId())
+ .equals(controllers)) {
+ clientService.setControllersWithDeviceId(handler().
+ data().deviceId(), controllers);
+ }
+ }
+
+ // Used for getting OvsdbClientService.
+ private OvsdbClientService getOvsdbClientService(DriverHandler handler) {
+ OvsdbController ovsController = handler.get(OvsdbController.class);
+ DeviceService deviceService = handler.get(DeviceService.class);
+ DeviceId ofDeviceId = handler.data().deviceId();
+ String[] mgmtAddress = deviceService.getDevice(ofDeviceId)
+ .annotations().value(AnnotationKeys.MANAGEMENT_ADDRESS).split(":");
+ String targetIp = mgmtAddress[0];
+ TpPort targetPort = null;
+ if (mgmtAddress.length > 1) {
+ targetPort = TpPort.tpPort(Integer.parseInt(mgmtAddress[1]));
+ }
+
+ List<OvsdbNodeId> nodeIds = ovsController.getNodeIds().stream()
+ .filter(nodeId -> nodeId.getIpAddress().equals(targetIp))
+ .collect(Collectors.toList());
+ if (nodeIds.size() == 0) {
+ //TODO decide what port?
+ ovsController.connect(IpAddress.valueOf(targetIp),
+ targetPort == null ? TpPort.tpPort(6640) : targetPort);
+ delay(1000); //FIXME... connect is async
+ }
+ List<OvsdbClientService> clientServices = ovsController.getNodeIds().stream()
+ .filter(nodeId -> nodeId.getIpAddress().equals(targetIp))
+ .map(ovsController::getOvsdbClient)
+ .filter(cs -> cs.getBridges().stream().anyMatch(b -> dpidMatches(b, ofDeviceId)))
+ .collect(Collectors.toList());
+ checkState(clientServices.size() > 0, "No clientServices found");
+ //FIXME add connection to management address if null --> done ?
+ return clientServices.size() > 0 ? clientServices.get(0) : null;
+ }
+
+ private static boolean dpidMatches(OvsdbBridge bridge, DeviceId deviceId) {
+ String bridgeDpid = "of:" + bridge.datapathId().value();
+ String ofDpid = deviceId.toString();
+ return bridgeDpid.equals(ofDpid);
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/drivers/src/main/resources/onos-drivers.xml b/framework/src/onos/drivers/src/main/resources/onos-drivers.xml
index ac307c28..5059d4bf 100644
--- a/framework/src/onos/drivers/src/main/resources/onos-drivers.xml
+++ b/framework/src/onos/drivers/src/main/resources/onos-drivers.xml
@@ -30,6 +30,8 @@
manufacturer="Nicira, Inc\." hwVersion="Open vSwitch" swVersion="2\..*">
<behaviour api="org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver"
impl="org.onosproject.driver.handshaker.NiciraSwitchHandshaker"/>
+ <behaviour api="org.onosproject.net.behaviour.ControllerConfig"
+ impl="org.onosproject.driver.ovsdb.OvsdbControllerConfig"/>
</driver>
<driver name="ovs-corsa" extends="ovs"
manufacturer="Corsa" hwVersion="emulation" swVersion="0.0.0">
@@ -120,5 +122,10 @@
<behaviour api="org.onosproject.net.behaviour.Pipeliner"
impl="org.onosproject.driver.pipeline.OpenVSwitchPipeline"/>
</driver>
+ <driver name="eci" extends="default"
+ manufacturer="ECI Telecom" hwVersion="optical" swVersion="V_1_0">
+ <behaviour api="org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver"
+ impl="org.onosproject.driver.handshaker.OFOpticalSwitch13"/>
+ </driver>
</drivers>
diff --git a/framework/src/onos/drivers/src/test/java/org/onosproject/driver/ovsdb/OvsdbControllerConfigTest.java b/framework/src/onos/drivers/src/test/java/org/onosproject/driver/ovsdb/OvsdbControllerConfigTest.java
new file mode 100644
index 00000000..4a91efcd
--- /dev/null
+++ b/framework/src/onos/drivers/src/test/java/org/onosproject/driver/ovsdb/OvsdbControllerConfigTest.java
@@ -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.driver.ovsdb;
+
+import com.google.common.collect.ImmutableMap;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.behaviour.ControllerConfig;
+import org.onosproject.net.device.DeviceServiceAdapter;
+import org.onosproject.net.driver.DefaultDriver;
+import org.onosproject.net.driver.DefaultDriverData;
+import org.onosproject.net.driver.DefaultDriverHandler;
+import org.onosproject.ovsdb.controller.driver.OvsdbClientServiceAdapter;
+import org.onosproject.ovsdb.controller.driver.OvsdbControllerAdapter;
+
+/**
+ * Created by Andrea on 10/7/15.
+ */
+public class OvsdbControllerConfigTest {
+
+
+ private static final DeviceId DEVICE_ID = DeviceId.deviceId("foo");
+
+ private DefaultDriver ddc;
+ private DefaultDriverData data;
+ private DefaultDriverHandler handler;
+
+ private TestDeviceService deviceService = new TestDeviceService();
+ private TestOvsdbController controller = new TestOvsdbController();
+ private TestOvsdbClient client = new TestOvsdbClient();
+
+ private OvsdbControllerConfig controllerConfig;
+
+
+ @Before
+ public void setUp() {
+ controllerConfig = new OvsdbControllerConfig();
+
+ ddc = new DefaultDriver("foo.bar", null, "Circus", "lux", "1.2a",
+ ImmutableMap.of(ControllerConfig.class,
+ OvsdbControllerConfig.class),
+ ImmutableMap.of("foo", "bar"));
+ data = new DefaultDriverData(ddc, DEVICE_ID);
+ handler = new DefaultDriverHandler(data);
+ //handler.controllerConfig.setHandler(handler);
+ //TODO setTestService directory on handler
+ //TODO setup ovsdb fake controller with fake ovsdbclient
+ //TODO setup fake device service
+ }
+
+ @Test
+ public void testGetControllers() throws Exception {
+// DriverService driverService = new Driv
+// AbstractBehaviour ab = new AbstractBehaviour();
+// DriverHandler handler = handler();
+// List<ControllerInfo> controllersList =
+// controllerConfig.getControllers(DeviceId.deviceId("0000000000000018"));
+// log.info("controllers " + controllersList);
+
+ }
+
+ @Test
+ public void testSetControllers() throws Exception {
+
+ }
+
+
+ private class TestDeviceService extends DeviceServiceAdapter {
+
+ }
+
+ private class TestOvsdbController extends OvsdbControllerAdapter {
+
+
+ }
+
+ private class TestOvsdbClient extends OvsdbClientServiceAdapter {
+
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/config/basics/InterfaceConfig.java b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/config/basics/InterfaceConfig.java
index af2b47d8..592336c2 100644
--- a/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/config/basics/InterfaceConfig.java
+++ b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/config/basics/InterfaceConfig.java
@@ -17,13 +17,15 @@
package org.onosproject.incubator.net.config.basics;
import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.annotations.Beta;
import com.google.common.collect.Sets;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
-import org.onosproject.net.config.Config;
import org.onosproject.incubator.net.intf.Interface;
import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.config.Config;
import org.onosproject.net.host.InterfaceIpAddress;
import java.util.Set;
@@ -37,7 +39,6 @@ public class InterfaceConfig extends Config<ConnectPoint> {
public static final String MAC = "mac";
public static final String VLAN = "vlan";
- public static final String IP_MISSING_ERROR = "Must have at least one IP address";
public static final String MAC_MISSING_ERROR = "Must have a MAC address for each interface";
public static final String CONFIG_VALUE_ERROR = "Error parsing config value";
@@ -53,9 +54,6 @@ public class InterfaceConfig extends Config<ConnectPoint> {
try {
for (JsonNode intfNode : array) {
Set<InterfaceIpAddress> ips = getIps(intfNode);
- if (ips.isEmpty()) {
- throw new ConfigException(IP_MISSING_ERROR);
- }
if (intfNode.path(MAC).isMissingNode()) {
throw new ConfigException(MAC_MISSING_ERROR);
@@ -63,10 +61,7 @@ public class InterfaceConfig extends Config<ConnectPoint> {
MacAddress mac = MacAddress.valueOf(intfNode.path(MAC).asText());
- VlanId vlan = VlanId.NONE;
- if (!intfNode.path(VLAN).isMissingNode()) {
- vlan = VlanId.vlanId(Short.valueOf(intfNode.path(VLAN).asText()));
- }
+ VlanId vlan = getVlan(intfNode);
interfaces.add(new Interface(subject, ips, mac, vlan));
}
@@ -77,13 +72,64 @@ public class InterfaceConfig extends Config<ConnectPoint> {
return interfaces;
}
+ /**
+ * Adds an interface to the config.
+ *
+ * @param intf interface to add
+ */
+ public void addInterface(Interface intf) {
+ ObjectNode intfNode = array.addObject();
+ intfNode.put(MAC, intf.mac().toString());
+
+ if (!intf.ipAddresses().isEmpty()) {
+ intfNode.set(IPS, putIps(intf.ipAddresses()));
+ }
+
+ if (!intf.vlan().equals(VlanId.NONE)) {
+ intfNode.put(VLAN, intf.vlan().toString());
+ }
+ }
+
+ /**
+ * Removes an interface from the config.
+ *
+ * @param intf interface to remove
+ */
+ public void removeInterface(Interface intf) {
+ for (int i = 0; i < array.size(); i++) {
+ if (intf.vlan().equals(getVlan(node))) {
+ array.remove(i);
+ break;
+ }
+ }
+ }
+
+ private VlanId getVlan(JsonNode node) {
+ VlanId vlan = VlanId.NONE;
+ if (!node.path(VLAN).isMissingNode()) {
+ vlan = VlanId.vlanId(Short.valueOf(node.path(VLAN).asText()));
+ }
+ return vlan;
+ }
+
private Set<InterfaceIpAddress> getIps(JsonNode node) {
Set<InterfaceIpAddress> ips = Sets.newHashSet();
JsonNode ipsNode = node.get(IPS);
- ipsNode.forEach(jsonNode -> ips.add(InterfaceIpAddress.valueOf(jsonNode.asText())));
+ if (ipsNode != null) {
+ ipsNode.forEach(jsonNode ->
+ ips.add(InterfaceIpAddress.valueOf(jsonNode.asText())));
+ }
return ips;
}
+ private ArrayNode putIps(Set<InterfaceIpAddress> intfIpAddresses) {
+ ArrayNode ipArray = mapper.createArrayNode();
+
+ intfIpAddresses.forEach(i -> ipArray.add(i.toString()));
+
+ return ipArray;
+ }
+
}
diff --git a/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/domain/DomainIntentResource.java b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/domain/DomainIntentResource.java
new file mode 100644
index 00000000..ea1660e7
--- /dev/null
+++ b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/domain/DomainIntentResource.java
@@ -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.incubator.net.domain;
+
+import org.onosproject.core.ApplicationId;
+import org.onosproject.incubator.net.tunnel.DomainTunnelId;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.Path;
+
+/**
+ * A variant of intent resource specialized for use on the intra-domain level. It contains a lower level path.
+ */
+public class DomainIntentResource extends IntentResource {
+
+ private final Path domainPath;
+
+ private final DomainTunnelId domainTunnelId;
+
+ private final IntentDomainId intentDomainId;
+
+ /**
+ * Constructor for a domain intent resource.
+ *
+ * @param primitive the primitive associated with this resource
+ * @param domainTunnelId the id of this tunnel (used as a sorting mechanism)
+ * @param domainId the ID of the intent domain containing this tunnel
+ * @param appId the id of the application which created this tunnel
+ * @param ingress the fist connect point associated with this tunnel (order is irrelevant as long as it is
+ * consistent with the path)
+ * @param egress the second connect point associated with this tunnel (order is irrelevant as long as it is
+ * consistent with the path)
+ * @param path the path followed through the domain
+ */
+ public DomainIntentResource(IntentPrimitive primitive, DomainTunnelId domainTunnelId, IntentDomainId domainId,
+ ApplicationId appId, ConnectPoint ingress, ConnectPoint egress, Path path) {
+ super(primitive, appId, ingress, egress);
+
+ this.domainPath = path;
+ this.domainTunnelId = domainTunnelId;
+ this.intentDomainId = domainId;
+ }
+
+ /**
+ * Returns the domain path associated with this resource at creation.
+ *
+ * @return this resource's domain level path or if this resource backs a network tunnel then null.
+ */
+ public Path path() {
+ return domainPath;
+ }
+
+ /**
+ * Returns the tunnel ID associated with this domain at creation.
+ *
+ * @return this resource's tunnel ID.
+ */
+ public DomainTunnelId tunnelId() {
+ return domainTunnelId;
+ }
+
+ /**
+ * Returns the domain ID associated with this resource at creation.
+ *
+ * @return this resource's domain ID.
+ */
+ public IntentDomainId domainId() {
+ return intentDomainId;
+ }
+
+}
diff --git a/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/domain/IntentDomainProvider.java b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/domain/IntentDomainProvider.java
index 51265f71..a19add60 100644
--- a/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/domain/IntentDomainProvider.java
+++ b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/domain/IntentDomainProvider.java
@@ -34,51 +34,51 @@ public interface IntentDomainProvider {
*
* @param domain intent domain for the request
* @param primitive intent primitive
- * @return request contexts that contain resources to satisfy the intent
+ * @return intent resources that specify paths that satisfy the request.
*/
//TODO Consider an iterable and/or holds (only hold one or two reservation(s) at a time)
- List<RequestContext> request(IntentDomain domain, IntentPrimitive primitive);
+ List<DomainIntentResource> request(IntentDomain domain, IntentPrimitive primitive);
/**
* Request that the provider attempt to modify an existing resource to satisfy
* a new intent primitive. The application must apply the context before
* the intent resource can be used.
*
- * @param resource existing resource
- * @param newPrimitive intent primitive
+ * @param oldResource the resource to be replaced
+ * @param newResource the resource to be applied
* @return request contexts that contain resources to satisfy the intent
*/
- List<RequestContext> modify(IntentResource resource, IntentPrimitive newPrimitive);
+ DomainIntentResource modify(DomainIntentResource oldResource, DomainIntentResource newResource);
/**
* Requests that the provider release an intent resource.
*
* @param resource intent resource
*/
- void release(IntentResource resource);
+ void release(DomainIntentResource resource);
/**
- * Requests that the provider apply the intent resource in the request context.
+ * Requests that the provider apply the path from the intent resource.
*
- * @param context request context
+ * @param domainIntentResource request context
* @return intent resource that satisfies the intent
*/
- IntentResource apply(RequestContext context);
+ DomainIntentResource apply(DomainIntentResource domainIntentResource);
/**
- * Requests that the provider cancel the request. Requests that are not applied
+ * Requests that the provider cancel the path. Requests that are not applied
* will be eventually timed out by the provider.
*
- * @param context request context
+ * @param domainIntentResource the intent resource whose path should be cancelled.
*/
- void cancel(RequestContext context);
+ void cancel(DomainIntentResource domainIntentResource);
/**
* Returns all intent resources held by the provider.
*
* @return set of intent resources
*/
- Set<IntentResource> getResources();
+ Set<DomainIntentResource> getResources();
}
diff --git a/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/domain/IntentResource.java b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/domain/IntentResource.java
index 9cd9aac0..627c863f 100644
--- a/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/domain/IntentResource.java
+++ b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/domain/IntentResource.java
@@ -16,53 +16,73 @@
package org.onosproject.incubator.net.domain;
import com.google.common.annotations.Beta;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.ConnectPoint;
+
/**
* The abstract base class for the resource that satisfies an intent primitive.
*/
@Beta
-public class IntentResource {
+public abstract class IntentResource {
private final IntentPrimitive primitive;
- private final long tunnelId;
- private final IntentDomainId domainId;
+
+ private final ApplicationId appId;
+ private final ConnectPoint ingress;
+ private final ConnectPoint egress;
+
+ //* QUESTIONABLE ADDITIONS *//
// TODO add other common fields
//String ingressTag;
//String egressTag;
//etc.
- public IntentResource(IntentPrimitive primitive, long tunnelId, IntentDomainId domainId) {
+ public IntentResource(IntentPrimitive primitive, ApplicationId appId,
+ ConnectPoint ingress, ConnectPoint egress) {
+ this.appId = appId;
+ this.ingress = ingress;
+ this.egress = egress;
this.primitive = primitive;
- this.tunnelId = tunnelId;
- this.domainId = domainId;
}
+ //TODO when is same package tunnelID should be of type tunnelID and netTunnelId not long.
+
+
/**
- * Returns the intent primitive associated with this resource as creation.
+ * Returns the intent primitive associated with this resource at creation.
*
- * @return this resource's intent primitive
+ * @return this resource's intent primitive.
*/
public IntentPrimitive primitive() {
return primitive;
}
/**
- * Returns the tunnel ID associated with this resource as creation.
+ * Returns the application ID associated with this resource at creation.
*
- * @return this resource's tunnel ID
+ * @return this resource's application ID.
*/
- public long tunnelId() {
- return tunnelId;
+ public ApplicationId appId() {
+ return appId;
}
/**
- * Returns the domain ID associated with this resource as creation.
+ * Returns the ingress connect point associated with this resource at creation.
*
- * @return this resource's domain ID
+ * @return this resource's ingress connect point.
*/
- public IntentDomainId domainId() {
- return domainId;
+ public ConnectPoint ingress() {
+ return ingress;
}
+ /**
+ * Returns the egress connect point associated with this resource at creation.
+ *
+ * @return this resource's connect point.
+ */
+ public ConnectPoint egress() {
+ return egress;
+ }
}
diff --git a/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/domain/NetworkIntentResource.java b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/domain/NetworkIntentResource.java
new file mode 100644
index 00000000..ac4445b4
--- /dev/null
+++ b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/domain/NetworkIntentResource.java
@@ -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.
+ */
+
+package org.onosproject.incubator.net.domain;
+
+import org.onosproject.core.ApplicationId;
+import org.onosproject.incubator.net.tunnel.NetworkTunnelId;
+import org.onosproject.net.ConnectPoint;
+
+/**
+ * A variant of intent resource specialized for use on the inter-domain level. It contains a higher level path.
+ */
+public class NetworkIntentResource extends IntentResource {
+
+ private final org.onlab.graph.Path<DomainVertex, DomainEdge> netPath;
+
+ private NetworkTunnelId networkTunnelId;
+
+ /**
+ * Constructor for a network intent resource.
+ *
+ * @param primitive the primitive associated with this resource
+ * @param networkTunnelId the id of this tunnel (used as a sorting mechanism)
+ * @param appId the id of the application which created this tunnel
+ * @param ingress the fist connect point associated with this tunnel (order is irrelevant as long as it is
+ * consistent with the path)
+ * @param egress the second connect point associated with this tunnel (order is irrelevant as long as it is
+ * consistent with the path)
+ * @param path the path followed through the graph of domain vertices and domain edges
+ */
+ public NetworkIntentResource(IntentPrimitive primitive, NetworkTunnelId networkTunnelId, ApplicationId appId,
+ ConnectPoint ingress, ConnectPoint egress,
+ org.onlab.graph.Path<DomainVertex, DomainEdge> path) {
+ super(primitive, appId, ingress, egress);
+
+ this.networkTunnelId = networkTunnelId;
+ this.netPath = path;
+ }
+
+ /**
+ * Returns the network path associated with this resource at creation.
+ *
+ * @return this resource's network lever path or if this resource backs a domain level tunnel then null.
+ */
+ public org.onlab.graph.Path<DomainVertex, DomainEdge> path() {
+ return netPath;
+ }
+
+ /**
+ * Returns ths network ID associated with this network tunnel at creation.
+ *
+ * @return thsi resource's tunnel ID.
+ */
+ public NetworkTunnelId tunnelId() {
+ return this.networkTunnelId;
+ }
+}
diff --git a/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/intf/InterfaceAdminService.java b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/intf/InterfaceAdminService.java
new file mode 100644
index 00000000..56d5aecc
--- /dev/null
+++ b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/intf/InterfaceAdminService.java
@@ -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.incubator.net.intf;
+
+import org.onlab.packet.VlanId;
+import org.onosproject.net.ConnectPoint;
+
+/**
+ * Provides a means to modify the interfaces configuration.
+ */
+public interface InterfaceAdminService {
+ /**
+ * Adds a new interface configuration to the system.
+ *
+ * @param intf interface to add
+ */
+ void add(Interface intf);
+
+ /**
+ * Removes an interface configuration from the system.
+ *
+ * @param connectPoint connect point of the interface
+ * @param vlanId vlan id
+ */
+ void remove(ConnectPoint connectPoint, VlanId vlanId);
+}
diff --git a/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/tunnel/DomainTunnelId.java b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/tunnel/DomainTunnelId.java
new file mode 100644
index 00000000..430823ca
--- /dev/null
+++ b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/tunnel/DomainTunnelId.java
@@ -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.incubator.net.tunnel;
+
+/**
+ * A wrapper class for a long used to identify domain level tunnels.
+ */
+public final class DomainTunnelId {
+
+ private final long value;
+
+ /**
+ * Creates a tunnel identifier from the specified tunnel.
+ *
+ * @param value long value
+ * @return domain tunnel identifier
+ */
+ public static DomainTunnelId valueOf(long value) {
+ return new DomainTunnelId(value);
+ }
+
+ /**
+ * Creates a tunnel identifier from the specified tunnel.
+ *
+ * @param value long value as a string
+ * @return domain tunnel identifier
+ */
+ public static DomainTunnelId valueOf(String value) {
+ return new DomainTunnelId(Long.parseLong(value));
+ }
+
+ /**
+ * Constructor for serializer.
+ */
+ protected DomainTunnelId() {
+ this.value = 0;
+ }
+
+ /**
+ * Constructs the Domain ID corresponding to a given long value.
+ *
+ * @param value the underlying value of this domain ID
+ */
+ public DomainTunnelId(long value) {
+ this.value = value;
+ }
+
+ /**
+ * Returns the backing value of this domain ID.
+ *
+ * @return the long value
+ */
+ public long id() {
+ return value;
+ }
+
+ @Override
+ public int hashCode() {
+ return Long.hashCode(value);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof DomainTunnelId)) {
+ return false;
+ }
+ DomainTunnelId that = (DomainTunnelId) obj;
+ return this.value == that.value;
+ }
+
+ @Override
+ public String toString() {
+ return "0x" + Long.toHexString(value);
+ }
+}
diff --git a/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/tunnel/NetworkTunnelId.java b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/tunnel/NetworkTunnelId.java
new file mode 100644
index 00000000..a3de7883
--- /dev/null
+++ b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/tunnel/NetworkTunnelId.java
@@ -0,0 +1,89 @@
+/*
+ * 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.incubator.net.tunnel;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * Representation of a Network Tunnel Id.
+ */
+@Beta
+public final class NetworkTunnelId {
+ private final long value;
+
+ /**
+ * Creates an tunnel identifier from the specified tunnel.
+ *
+ * @param value long value
+ * @return tunnel identifier
+ */
+ public static NetworkTunnelId valueOf(long value) {
+ return new NetworkTunnelId(value);
+ }
+
+ public static NetworkTunnelId valueOf(String value) {
+ return new NetworkTunnelId(Long.parseLong(value));
+ }
+
+ /**
+ * Constructor for serializer.
+ */
+ NetworkTunnelId() {
+ this.value = 0;
+ }
+
+ /**
+ * Constructs the ID corresponding to a given long value.
+ *
+ * @param value the underlying value of this ID
+ */
+ public NetworkTunnelId(long value) {
+ this.value = value;
+ }
+
+ /**
+ * Returns the backing value.
+ *
+ * @return the value
+ */
+ public long id() {
+ return value;
+ }
+
+ @Override
+ public int hashCode() {
+ return Long.hashCode(value);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof NetworkTunnelId)) {
+ return false;
+ }
+ NetworkTunnelId that = (NetworkTunnelId) obj;
+ return this.value == that.value;
+ }
+
+ @Override
+ public String toString() {
+ return "0x" + Long.toHexString(value);
+ }
+
+}
diff --git a/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/DefaultVirtualDevice.java b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/DefaultVirtualDevice.java
new file mode 100644
index 00000000..54a22a46
--- /dev/null
+++ b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/DefaultVirtualDevice.java
@@ -0,0 +1,75 @@
+/*
+ * 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.incubator.net.virtual;
+
+import org.onlab.packet.ChassisId;
+import org.onosproject.net.DefaultDevice;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.provider.ProviderId;
+
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.*;
+
+/**
+ * Default representation of a virtual device.
+ */
+public class DefaultVirtualDevice extends DefaultDevice implements VirtualDevice {
+
+ private static final String VIRTUAL = "virtual";
+ private static final ProviderId PID = new ProviderId(VIRTUAL, VIRTUAL);
+
+ private final NetworkId networkId;
+
+ /**
+ * Creates a network element attributed to the specified provider.
+ *
+ * @param networkId network identifier
+ * @param id device identifier
+ */
+ public DefaultVirtualDevice(NetworkId networkId, DeviceId id) {
+ super(PID, id, Type.VIRTUAL, VIRTUAL, VIRTUAL, VIRTUAL, VIRTUAL,
+ new ChassisId(0));
+ this.networkId = networkId;
+ }
+
+ @Override
+ public NetworkId networkId() {
+ return networkId;
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * super.hashCode() + Objects.hash(networkId);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof DefaultVirtualDevice) {
+ DefaultVirtualDevice that = (DefaultVirtualDevice) obj;
+ return super.equals(that) && Objects.equals(this.networkId, that.networkId);
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(this).add("networkId", networkId).toString();
+ }
+}
diff --git a/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/DefaultVirtualNetwork.java b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/DefaultVirtualNetwork.java
new file mode 100644
index 00000000..c1141912
--- /dev/null
+++ b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/DefaultVirtualNetwork.java
@@ -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.incubator.net.virtual;
+
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Default implementation of the virtual network descriptor.
+ */
+public class DefaultVirtualNetwork implements VirtualNetwork {
+
+ private final NetworkId id;
+ private final TenantId tenantId;
+
+ /**
+ * Creates a new virtual network descriptor.
+ *
+ * @param id network identifier
+ * @param tenantId tenant identifier
+ */
+ public DefaultVirtualNetwork(NetworkId id, TenantId tenantId) {
+ this.id = id;
+ this.tenantId = tenantId;
+ }
+
+ @Override
+ public NetworkId id() {
+ return id;
+ }
+
+ @Override
+ public TenantId tenantId() {
+ return tenantId;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, tenantId);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof DefaultVirtualNetwork) {
+ DefaultVirtualNetwork that = (DefaultVirtualNetwork) obj;
+ return Objects.equals(this.id, that.id)
+ && Objects.equals(this.tenantId, that.tenantId);
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(this)
+ .add("id", id)
+ .add("tenantId", tenantId)
+ .toString();
+ }
+}
diff --git a/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualElement.java b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualElement.java
index 1c74b92a..791b8e24 100644
--- a/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualElement.java
+++ b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualElement.java
@@ -24,13 +24,6 @@ import com.google.common.annotations.Beta;
public interface VirtualElement {
/**
- * Returns the identifier of the tenant to which this virtual element belongs.
- *
- * @return tenant identifier
- */
- TenantId tenantId();
-
- /**
* Returns the network identifier to which this virtual element belongs.
*
* @return network identifier
diff --git a/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkAdminService.java b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkAdminService.java
index 1e3648b5..07c399c0 100644
--- a/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkAdminService.java
+++ b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkAdminService.java
@@ -16,14 +16,11 @@
package org.onosproject.incubator.net.virtual;
import com.google.common.annotations.Beta;
-import org.onosproject.incubator.net.tunnel.Tunnel;
+import org.onosproject.incubator.net.tunnel.TunnelId;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
-import org.onosproject.net.device.DeviceDescription;
-import org.onosproject.net.device.PortDescription;
-import org.onosproject.net.link.LinkDescription;
import java.util.Set;
@@ -76,12 +73,12 @@ public interface VirtualNetworkAdminService extends VirtualNetworkService {
* Creates a new virtual device within the specified network. The device id
* must be unique within the bounds of the network.
*
- * @param networkId network identifier
- * @param description device description
+ * @param networkId network identifier
+ * @param deviceId device identifier
* @return newly created device
* @throws org.onlab.util.ItemNotFoundException if no such network found
*/
- VirtualDevice createVirtualDevice(NetworkId networkId, DeviceDescription description);
+ VirtualDevice createVirtualDevice(NetworkId networkId, DeviceId deviceId);
/**
* Removes the specified virtual device and all its ports and affiliated links.
@@ -96,14 +93,16 @@ public interface VirtualNetworkAdminService extends VirtualNetworkService {
/**
* Creates a new virtual link within the specified network.
*
- * @param networkId network identifier
- * @param description link description
- * @param realizedBy tunnel using which this link is realized
+ * @param networkId network identifier
+ * @param src source connection point
+ * @param dst destination connection point
+ * @param realizedBy identifier of the tunnel using which this link is realized
* @return newly created virtual link
* @throws org.onlab.util.ItemNotFoundException if no such network found
*/
- VirtualLink createVirtualLink(NetworkId networkId, LinkDescription description,
- Tunnel realizedBy);
+ VirtualLink createVirtualLink(NetworkId networkId,
+ ConnectPoint src, ConnectPoint dst,
+ TunnelId realizedBy);
// TODO: Discuss whether we should provide an alternate createVirtualLink
// which is backed by a Path instead; I'm leaning towards not doing that.
@@ -119,20 +118,17 @@ public interface VirtualNetworkAdminService extends VirtualNetworkService {
void removeVirtualLink(NetworkId networkId, ConnectPoint src, ConnectPoint dst);
/**
- * Creates a new virtual port on the specified device. Note that the port
- * description can only request the resources which the underlying port
- * port is capable of providing. It is, however, permissible to request
- * only portion of those resources.
+ * Creates a new virtual port on the specified device.
*
- * @param networkId network identifier
- * @param deviceId device identifier
- * @param description port description
- * @param realizedBy underlying port using which this virtual port is realized
+ * @param networkId network identifier
+ * @param deviceId device identifier
+ * @param portNumber port number
+ * @param realizedBy underlying port using which this virtual port is realized
* @return newly created port
* @throws org.onlab.util.ItemNotFoundException if no such network or device found
*/
VirtualPort createVirtualPort(NetworkId networkId, DeviceId deviceId,
- PortDescription description, Port realizedBy);
+ PortNumber portNumber, Port realizedBy);
/**
* Removes the specified virtual port.
diff --git a/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkEvent.java b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkEvent.java
new file mode 100644
index 00000000..7e076e09
--- /dev/null
+++ b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkEvent.java
@@ -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.incubator.net.virtual;
+
+import org.onosproject.event.AbstractEvent;
+
+/**
+ * Describes virtual network event.
+ */
+public class VirtualNetworkEvent extends AbstractEvent<VirtualNetworkEvent.Type, NetworkId> {
+
+ /**
+ * Type of virtual network events.
+ */
+ public enum Type {
+ /**
+ * Signifies that a new tenant identifier was registered.
+ */
+ TENANT_REGISTERED,
+ /**
+ * Signifies that a tenant identifier was unregistered.
+ */
+ TENANT_UNREGISTERED,
+ /**
+ * Signifies that a new virtual network was added.
+ */
+ NETWORK_ADDED,
+ /**
+ * Signifies that a virtual network was updated.
+ */
+ NETWORK_UPDATED,
+ /**
+ * Signifies that a virtual network was removed.
+ */
+ NETWORK_REMOVED
+ }
+
+ /**
+ * Creates an event of a given type and for the specified subject and the
+ * current time.
+ *
+ * @param type event type
+ * @param subject event subject
+ */
+ public VirtualNetworkEvent(Type type, NetworkId subject) {
+ super(type, subject);
+ }
+
+ /**
+ * Creates an event of a given type and for the specified subject and time.
+ *
+ * @param type device event type
+ * @param subject event subject
+ * @param time occurrence time
+ */
+ public VirtualNetworkEvent(Type type, NetworkId subject, long time) {
+ super(type, subject, time);
+ }
+}
diff --git a/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkListener.java b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkListener.java
new file mode 100644
index 00000000..707ca8a7
--- /dev/null
+++ b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkListener.java
@@ -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.incubator.net.virtual;
+
+import org.onosproject.event.EventListener;
+
+/**
+ * Represents entity capable of receiving virtual network events.
+ */
+public interface VirtualNetworkListener extends EventListener<VirtualNetworkEvent> {
+}
diff --git a/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkProvider.java b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkProvider.java
new file mode 100644
index 00000000..8e5b19a5
--- /dev/null
+++ b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkProvider.java
@@ -0,0 +1,31 @@
+package org.onosproject.incubator.net.virtual;
+
+import org.onosproject.incubator.net.tunnel.TunnelId;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.provider.Provider;
+
+/**
+ * Entity capable of providing traffic isolation constructs for use in
+ * implementation of virtual devices and virtual links.
+ */
+public interface VirtualNetworkProvider extends Provider {
+
+ /**
+ * Creates a network tunnel for all traffic from the specified source
+ * connection point to the indicated destination connection point.
+ *
+ * @param networkId virtual network identifier
+ * @param src source connection point
+ * @param dst destination connection point
+ */
+ TunnelId createTunnel(NetworkId networkId, ConnectPoint src, ConnectPoint dst);
+
+ /**
+ * Destroys the specified network tunnel.
+ *
+ * @param networkId virtual network identifier
+ * @param tunnelId tunnel identifier
+ */
+ void destroyTunnel(NetworkId networkId, TunnelId tunnelId);
+
+}
diff --git a/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkProviderRegistry.java b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkProviderRegistry.java
new file mode 100644
index 00000000..4e893165
--- /dev/null
+++ b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkProviderRegistry.java
@@ -0,0 +1,25 @@
+/*
+ * 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.incubator.net.virtual;
+
+import org.onosproject.net.provider.ProviderRegistry;
+
+/**
+ * Abstraction of a virtual network provider registry.
+ */
+public interface VirtualNetworkProviderRegistry
+ extends ProviderRegistry<VirtualNetworkProvider, VirtualNetworkProviderService> {
+}
diff --git a/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkProviderService.java b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkProviderService.java
new file mode 100644
index 00000000..cba933c9
--- /dev/null
+++ b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkProviderService.java
@@ -0,0 +1,11 @@
+package org.onosproject.incubator.net.virtual;
+
+import org.onosproject.net.provider.ProviderService;
+
+/**
+ * Service through which virtual network providers can inject information into
+ * the core.
+ */
+public interface VirtualNetworkProviderService extends ProviderService<VirtualNetworkProvider> {
+ // TODO: Add methods for notification of core about damaged tunnels, etc.
+}
diff --git a/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkStore.java b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkStore.java
new file mode 100644
index 00000000..49ad2f2b
--- /dev/null
+++ b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkStore.java
@@ -0,0 +1,161 @@
+/*
+ * 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.incubator.net.virtual;
+
+import org.onosproject.incubator.net.tunnel.TunnelId;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.store.Store;
+
+import java.util.Set;
+
+/**
+ * Mechanism for distributing and storing virtual network model information.
+ */
+public interface VirtualNetworkStore
+ extends Store<VirtualNetworkEvent, VirtualNetworkStoreDelegate> {
+
+ /**
+ * Adds a new tenant ID to the store.
+ *
+ * @param tenantId tenant identifier
+ */
+ void addTenantId(TenantId tenantId);
+
+ /**
+ * Removes the specified tenant ID from the store.
+ *
+ * @param tenantId tenant identifier
+ */
+ void removeTenantId(TenantId tenantId);
+
+ /**
+ * Returns set of registered tenant IDs.
+ *
+ * @return set of tenant identifiers
+ */
+ Set<TenantId> getTenantIds();
+
+ /**
+ * Adds a new virtual network for the specified tenant to the store.
+ *
+ * @param tenantId tenant identifier
+ * @return the virtual network
+ */
+ VirtualNetwork addNetwork(TenantId tenantId);
+
+ /**
+ * Removes the specified virtual network from the store.
+ *
+ * @param networkId network identifier
+ */
+ void removeNetwork(NetworkId networkId);
+
+ /**
+ * Adds a new virtual device to the store. This device will have no ports.
+ *
+ * @param networkId network identifier
+ * @param deviceId device identifier
+ * @return the virtual device
+ */
+ VirtualDevice addDevice(NetworkId networkId, DeviceId deviceId);
+
+ /**
+ * Renmoves the specified virtual device from the given network.
+ *
+ * @param networkId network identifier
+ * @param deviceId device identifier
+ */
+ void removeDevice(NetworkId networkId, DeviceId deviceId);
+
+ /**
+ * Adds a new virtual link.
+ *
+ * @param networkId network identifier
+ * @param src source end-point of the link
+ * @param dst destination end-point of the link
+ * @param realizedBy underlying tunnel using which this link is realized
+ * @return the virtual link
+ */
+ VirtualLink addLink(NetworkId networkId, ConnectPoint src, ConnectPoint dst,
+ TunnelId realizedBy);
+
+ /**
+ * Removes the specified link from the store.
+ *
+ * @param networkId network identifier
+ * @param src source connection point
+ * @param dst destination connection point
+ */
+ void removeLink(NetworkId networkId, ConnectPoint src, ConnectPoint dst);
+
+ /**
+ * Adds a new virtual port to the network.
+ *
+ * @param networkId network identifier
+ * @param deviceId device identifier
+ * @param portNumber port number
+ * @param realizedBy underlying port which realizes the virtual port
+ * @return the virtual port
+ */
+ VirtualPort addPort(NetworkId networkId, DeviceId deviceId,
+ PortNumber portNumber, Port realizedBy);
+
+ /**
+ * Removes the specified port from the given device and network.
+ *
+ * @param networkId network identifier
+ * @param deviceId device identifier
+ * @param portNumber port number
+ */
+ void removePort(NetworkId networkId, DeviceId deviceId, PortNumber portNumber);
+
+ /**
+ * Returns the list of networks.
+ *
+ * @param tenantId tenant identifier
+ * @return set of virtual networks
+ */
+ Set<VirtualNetwork> getNetworks(TenantId tenantId);
+
+ /**
+ * Returns the list of devices in the specified virtual network.
+ *
+ * @param networkId network identifier
+ * @return set of virtual devices
+ */
+ Set<VirtualDevice> getDevices(NetworkId networkId);
+
+ /**
+ * Returns the list of virtual links in the specified virtual network.
+ *
+ * @param networkId network identifier
+ * @return set of virtual links
+ */
+ Set<VirtualLink> getLinks(NetworkId networkId);
+
+ /**
+ * Returns the list of ports of the specified virtual device.
+ *
+ * @param networkId network identifier
+ * @param deviceId device identifier
+ * @return set of virtual networks
+ */
+ Set<VirtualPort> getPorts(NetworkId networkId, DeviceId deviceId);
+
+}
diff --git a/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkStoreDelegate.java b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkStoreDelegate.java
new file mode 100644
index 00000000..e57c3d3a
--- /dev/null
+++ b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkStoreDelegate.java
@@ -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.incubator.net.virtual;
+
+import org.onosproject.store.StoreDelegate;
+
+/**
+ * Network configuration store delegate abstraction.
+ */
+public interface VirtualNetworkStoreDelegate extends StoreDelegate<VirtualNetworkEvent> {
+}
diff --git a/framework/src/onos/incubator/net/src/main/java/org/onosproject/incubator/net/intf/impl/InterfaceManager.java b/framework/src/onos/incubator/net/src/main/java/org/onosproject/incubator/net/intf/impl/InterfaceManager.java
index f82cdbf2..0439d038 100644
--- a/framework/src/onos/incubator/net/src/main/java/org/onosproject/incubator/net/intf/impl/InterfaceManager.java
+++ b/framework/src/onos/incubator/net/src/main/java/org/onosproject/incubator/net/intf/impl/InterfaceManager.java
@@ -29,6 +29,7 @@ import org.onlab.packet.VlanId;
import org.onosproject.incubator.net.config.basics.ConfigException;
import org.onosproject.incubator.net.config.basics.InterfaceConfig;
import org.onosproject.incubator.net.intf.Interface;
+import org.onosproject.incubator.net.intf.InterfaceAdminService;
import org.onosproject.incubator.net.intf.InterfaceService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.config.NetworkConfigEvent;
@@ -50,7 +51,8 @@ import static java.util.stream.Collectors.toSet;
*/
@Service
@Component(immediate = true)
-public class InterfaceManager implements InterfaceService {
+public class InterfaceManager implements InterfaceService,
+ InterfaceAdminService {
private final Logger log = LoggerFactory.getLogger(getClass());
@@ -153,6 +155,54 @@ public class InterfaceManager implements InterfaceService {
interfaces.remove(port);
}
+ @Override
+ public void add(Interface intf) {
+ if (interfaces.containsKey(intf.connectPoint())) {
+ boolean conflict = interfaces.get(intf.connectPoint()).stream()
+ .filter(i -> i.connectPoint().equals(intf.connectPoint()))
+ .filter(i -> i.mac().equals(intf.mac()))
+ .filter(i -> i.vlan().equals(intf.vlan()))
+ .findAny().isPresent();
+
+ if (conflict) {
+ log.error("Can't add interface because it conflicts with existing config");
+ return;
+ }
+ }
+
+ InterfaceConfig config =
+ configService.addConfig(intf.connectPoint(), CONFIG_CLASS);
+
+ config.addInterface(intf);
+
+ configService.applyConfig(intf.connectPoint(), CONFIG_CLASS, config.node());
+ }
+
+ @Override
+ public void remove(ConnectPoint connectPoint, VlanId vlanId) {
+ Optional<Interface> intf = interfaces.get(connectPoint).stream()
+ .filter(i -> i.vlan().equals(vlanId))
+ .findAny();
+
+ if (!intf.isPresent()) {
+ log.error("Can't find interface {}/{} to remove", connectPoint, vlanId);
+ return;
+ }
+
+ InterfaceConfig config = configService.addConfig(intf.get().connectPoint(), CONFIG_CLASS);
+ config.removeInterface(intf.get());
+
+ try {
+ if (config.getInterfaces().isEmpty()) {
+ configService.removeConfig(connectPoint, CONFIG_CLASS);
+ } else {
+ configService.applyConfig(intf.get().connectPoint(), CONFIG_CLASS, config.node());
+ }
+ } catch (ConfigException e) {
+ log.error("Error reading interfaces JSON", e);
+ }
+ }
+
/**
* Listener for network config events.
*/
diff --git a/framework/src/onos/incubator/net/src/main/java/org/onosproject/incubator/net/mcast/impl/MulticastData.java b/framework/src/onos/incubator/net/src/main/java/org/onosproject/incubator/net/mcast/impl/MulticastData.java
new file mode 100644
index 00000000..946d8c6e
--- /dev/null
+++ b/framework/src/onos/incubator/net/src/main/java/org/onosproject/incubator/net/mcast/impl/MulticastData.java
@@ -0,0 +1,85 @@
+/*
+ * 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.incubator.net.mcast.impl;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import org.onosproject.net.ConnectPoint;
+
+import java.util.Collections;
+import java.util.List;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Simple entity maintaining a mapping between a source and a collection of sink
+ * connect points.
+ */
+public final class MulticastData {
+
+ private final ConnectPoint source;
+ private final List<ConnectPoint> sinks;
+ private final boolean isEmpty;
+
+ private MulticastData() {
+ this.source = null;
+ this.sinks = Collections.EMPTY_LIST;
+ isEmpty = true;
+ }
+
+ public MulticastData(ConnectPoint source, List<ConnectPoint> sinks) {
+ this.source = checkNotNull(source, "Multicast source cannot be null.");
+ this.sinks = checkNotNull(sinks, "List of sinks cannot be null.");
+ isEmpty = false;
+ }
+
+ public MulticastData(ConnectPoint source, ConnectPoint sink) {
+ this.source = checkNotNull(source, "Multicast source cannot be null.");
+ this.sinks = Lists.newArrayList(checkNotNull(sink, "Sink cannot be null."));
+ isEmpty = false;
+ }
+
+ public MulticastData(ConnectPoint source) {
+ this.source = checkNotNull(source, "Multicast source cannot be null.");
+ this.sinks = Lists.newArrayList();
+ isEmpty = false;
+ }
+
+ public ConnectPoint source() {
+ return source;
+ }
+
+ public List<ConnectPoint> sinks() {
+ return ImmutableList.copyOf(sinks);
+ }
+
+ public void appendSink(ConnectPoint sink) {
+ sinks.add(sink);
+ }
+
+ public boolean removeSink(ConnectPoint sink) {
+ return sinks.remove(sink);
+ }
+
+ public boolean isEmpty() {
+ return isEmpty;
+ }
+
+ public static MulticastData empty() {
+ return new MulticastData();
+ }
+
+}
diff --git a/framework/src/onos/incubator/net/src/main/java/org/onosproject/incubator/net/mcast/impl/MulticastRouteManager.java b/framework/src/onos/incubator/net/src/main/java/org/onosproject/incubator/net/mcast/impl/MulticastRouteManager.java
new file mode 100644
index 00000000..f73dfe44
--- /dev/null
+++ b/framework/src/onos/incubator/net/src/main/java/org/onosproject/incubator/net/mcast/impl/MulticastRouteManager.java
@@ -0,0 +1,174 @@
+/*
+ * 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.incubator.net.mcast.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.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+import org.onlab.packet.IpPrefix;
+import org.onlab.util.KryoNamespace;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.event.AbstractListenerManager;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.mcast.McastEvent;
+import org.onosproject.net.mcast.McastListener;
+import org.onosproject.net.mcast.McastRoute;
+import org.onosproject.net.mcast.MulticastRouteService;
+import org.onosproject.store.service.ConsistentMap;
+import org.onosproject.store.service.Serializer;
+import org.onosproject.store.service.StorageService;
+import org.onosproject.store.service.Versioned;
+import org.slf4j.Logger;
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * An implementation of a multicast route table.
+ */
+@Component(immediate = true)
+@Service
+public class MulticastRouteManager
+ extends AbstractListenerManager<McastEvent, McastListener>
+ implements MulticastRouteService {
+ //TODO: add MulticastRouteAdminService
+
+ private static final String MCASTRIB = "mcast-rib-table";
+
+ private Logger log = getLogger(getClass());
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ private StorageService storageService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ private CoreService coreService;
+
+
+ protected ApplicationId appId;
+ protected ConsistentMap<McastRoute, MulticastData> mcastRoutes;
+
+ @Activate
+ public void activate() {
+
+ eventDispatcher.addSink(McastEvent.class, listenerRegistry);
+
+ appId = coreService.registerApplication("org.onosproject.mcastrib");
+
+ mcastRoutes = storageService.<McastRoute, MulticastData>consistentMapBuilder()
+ .withApplicationId(appId)
+ .withName(MCASTRIB)
+ .withSerializer(Serializer.using(KryoNamespace.newBuilder().register(
+ MulticastData.class,
+ McastRoute.class,
+ McastRoute.Type.class,
+ IpPrefix.class,
+ List.class,
+ ConnectPoint.class
+ ).build())).build();
+
+ log.info("Started");
+ }
+
+ @Deactivate
+ public void deactivate() {
+ log.info("Stopped");
+ }
+
+ @Override
+ public void add(McastRoute route) {
+ mcastRoutes.put(route, MulticastData.empty());
+ post(new McastEvent(McastEvent.Type.ROUTE_ADDED, route, null, null));
+ }
+
+ @Override
+ public void remove(McastRoute route) {
+ mcastRoutes.remove(route);
+ post(new McastEvent(McastEvent.Type.ROUTE_REMOVED, route, null, null));
+ }
+
+ @Override
+ public void addSource(McastRoute route, ConnectPoint connectPoint) {
+ Versioned<MulticastData> d = mcastRoutes.compute(route, (k, v) -> {
+ if (v.isEmpty()) {
+ return new MulticastData(connectPoint);
+ } else {
+ log.warn("Route {} is already in use.", route);
+ return v;
+ }
+ });
+
+ if (d != null) {
+ post(new McastEvent(McastEvent.Type.SOURCE_ADDED,
+ route, null, connectPoint));
+ }
+ }
+
+ @Override
+ public void addSink(McastRoute route, ConnectPoint connectPoint) {
+ AtomicReference<ConnectPoint> source = new AtomicReference<>();
+ mcastRoutes.compute(route, (k, v) -> {
+ if (!v.isEmpty()) {
+ v.appendSink(connectPoint);
+ source.set(v.source());
+ } else {
+ log.warn("Route {} does not exist");
+ }
+ return v;
+ });
+
+ if (source.get() != null) {
+ post(new McastEvent(McastEvent.Type.SINK_ADDED, route,
+ connectPoint, source.get()));
+ }
+ }
+
+
+ @Override
+ public void removeSink(McastRoute route, ConnectPoint connectPoint) {
+ AtomicReference<ConnectPoint> source = new AtomicReference<>();
+ mcastRoutes.compute(route, (k, v) -> {
+ if (v.removeSink(connectPoint)) {
+ source.set(v.source());
+ }
+ return v;
+ });
+
+ if (source.get() != null) {
+ post(new McastEvent(McastEvent.Type.SINK_REMOVED, route,
+ connectPoint, source.get()));
+ }
+ }
+
+ @Override
+ public ConnectPoint fetchSource(McastRoute route) {
+ MulticastData d = mcastRoutes.asJavaMap().getOrDefault(route,
+ MulticastData.empty());
+ return d.source();
+ }
+
+ @Override
+ public List<ConnectPoint> fetchSinks(McastRoute route) {
+ MulticastData d = mcastRoutes.asJavaMap().getOrDefault(route,
+ MulticastData.empty());
+ return d.sinks();
+ }
+}
diff --git a/framework/src/onos/incubator/net/src/main/java/org/onosproject/incubator/net/mcast/impl/package-info.java b/framework/src/onos/incubator/net/src/main/java/org/onosproject/incubator/net/mcast/impl/package-info.java
new file mode 100644
index 00000000..464cf701
--- /dev/null
+++ b/framework/src/onos/incubator/net/src/main/java/org/onosproject/incubator/net/mcast/impl/package-info.java
@@ -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.
+ */
+
+/**
+ * An implementation of a multicast RIB.
+ */
+package org.onosproject.incubator.net.mcast.impl; \ No newline at end of file
diff --git a/framework/src/onos/incubator/net/src/main/java/org/onosproject/incubator/net/meter/impl/MeterManager.java b/framework/src/onos/incubator/net/src/main/java/org/onosproject/incubator/net/meter/impl/MeterManager.java
index 575a7153..5c5c11cd 100644
--- a/framework/src/onos/incubator/net/src/main/java/org/onosproject/incubator/net/meter/impl/MeterManager.java
+++ b/framework/src/onos/incubator/net/src/main/java/org/onosproject/incubator/net/meter/impl/MeterManager.java
@@ -15,6 +15,7 @@
*/
package org.onosproject.incubator.net.meter.impl;
+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;
@@ -27,6 +28,7 @@ import org.onosproject.net.meter.Meter;
import org.onosproject.net.meter.MeterEvent;
import org.onosproject.net.meter.MeterFailReason;
import org.onosproject.net.meter.MeterId;
+import org.onosproject.net.meter.MeterKey;
import org.onosproject.net.meter.MeterListener;
import org.onosproject.net.meter.MeterOperation;
import org.onosproject.net.meter.MeterProvider;
@@ -61,7 +63,7 @@ public class MeterManager extends AbstractListenerProviderRegistry<MeterEvent, M
MeterProvider, MeterProviderService>
implements MeterService, MeterProviderRegistry {
- private final String meterIdentifier = "meter-id-counter";
+ private static final String METERCOUNTERIDENTIFIER = "meter-id-counter-%s";
private final Logger log = getLogger(getClass());
private final MeterStoreDelegate delegate = new InternalMeterStoreDelegate();
@@ -71,15 +73,13 @@ public class MeterManager extends AbstractListenerProviderRegistry<MeterEvent, M
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected MeterStore store;
- private AtomicCounter meterIdCounter;
+ private Map<DeviceId, AtomicCounter> meterIdCounters
+ = Maps.newConcurrentMap();
private TriConsumer<MeterRequest, MeterStoreResult, Throwable> onComplete;
@Activate
public void activate() {
- meterIdCounter = storageService.atomicCounterBuilder()
- .withName(meterIdentifier)
- .build();
store.setDelegate(delegate);
@@ -115,11 +115,13 @@ public class MeterManager extends AbstractListenerProviderRegistry<MeterEvent, M
@Override
public Meter submit(MeterRequest request) {
+ MeterId id = allocateMeterId(request.deviceId());
+
Meter.Builder mBuilder = DefaultMeter.builder()
.forDevice(request.deviceId())
.fromApp(request.appId())
.withBands(request.bands())
- .withId(allocateMeterId())
+ .withId(id)
.withUnit(request.unit());
if (request.isBurst()) {
@@ -152,8 +154,9 @@ public class MeterManager extends AbstractListenerProviderRegistry<MeterEvent, M
}
@Override
- public Meter getMeter(MeterId id) {
- return store.getMeter(id);
+ public Meter getMeter(DeviceId deviceId, MeterId id) {
+ MeterKey key = MeterKey.key(deviceId, id);
+ return store.getMeter(key);
}
@Override
@@ -161,9 +164,21 @@ public class MeterManager extends AbstractListenerProviderRegistry<MeterEvent, M
return store.getAllMeters();
}
- private MeterId allocateMeterId() {
- // FIXME: This will break one day.
- return MeterId.meterId((int) meterIdCounter.incrementAndGet());
+ private MeterId allocateMeterId(DeviceId deviceId) {
+ long id = meterIdCounters.compute(deviceId, (k, v) -> {
+ if (v == null) {
+ return allocateCounter(k);
+ }
+ return v;
+ }).incrementAndGet();
+
+ return MeterId.meterId((int) id);
+ }
+
+ private AtomicCounter allocateCounter(DeviceId deviceId) {
+ return storageService.atomicCounterBuilder()
+ .withName(String.format(METERCOUNTERIDENTIFIER, deviceId))
+ .build();
}
private class InternalMeterProviderService
diff --git a/framework/src/onos/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkManager.java b/framework/src/onos/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkManager.java
new file mode 100644
index 00000000..fe9f8841
--- /dev/null
+++ b/framework/src/onos/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkManager.java
@@ -0,0 +1,223 @@
+/*
+ * 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.incubator.net.virtual.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.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+import org.onosproject.incubator.net.tunnel.TunnelId;
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.incubator.net.virtual.TenantId;
+import org.onosproject.incubator.net.virtual.VirtualDevice;
+import org.onosproject.incubator.net.virtual.VirtualLink;
+import org.onosproject.incubator.net.virtual.VirtualNetwork;
+import org.onosproject.incubator.net.virtual.VirtualNetworkAdminService;
+import org.onosproject.incubator.net.virtual.VirtualNetworkEvent;
+import org.onosproject.incubator.net.virtual.VirtualNetworkListener;
+import org.onosproject.incubator.net.virtual.VirtualNetworkProvider;
+import org.onosproject.incubator.net.virtual.VirtualNetworkProviderRegistry;
+import org.onosproject.incubator.net.virtual.VirtualNetworkProviderService;
+import org.onosproject.incubator.net.virtual.VirtualNetworkService;
+import org.onosproject.incubator.net.virtual.VirtualNetworkStore;
+import org.onosproject.incubator.net.virtual.VirtualNetworkStoreDelegate;
+import org.onosproject.incubator.net.virtual.VirtualPort;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.provider.AbstractListenerProviderRegistry;
+import org.onosproject.net.provider.AbstractProviderService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Implementation of the virtual network service.
+ */
+@Component(immediate = true)
+@Service
+public class VirtualNetworkManager
+ extends AbstractListenerProviderRegistry<VirtualNetworkEvent, VirtualNetworkListener,
+ VirtualNetworkProvider, VirtualNetworkProviderService>
+ implements VirtualNetworkService, VirtualNetworkAdminService, VirtualNetworkProviderRegistry {
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ private static final String TENANT_NULL = "Tenant ID cannot be null";
+ private static final String NETWORK_NULL = "Network ID cannot be null";
+ private static final String DEVICE_NULL = "Device ID cannot be null";
+ private static final String LINK_POINT_NULL = "Link end-point cannot be null";
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected VirtualNetworkStore store;
+
+ private VirtualNetworkStoreDelegate delegate = new InternalStoreDelegate();
+
+ // TODO: figure out how to coordinate "implementation" of a virtual network in a cluster
+
+ @Activate
+ protected void activate() {
+ store.setDelegate(delegate);
+ log.info("Started");
+ }
+
+ @Deactivate
+ protected void deactivate() {
+ store.unsetDelegate(delegate);
+ log.info("Stopped");
+ }
+
+ @Override
+ public void registerTenantId(TenantId tenantId) {
+ checkNotNull(tenantId, TENANT_NULL);
+ store.addTenantId(tenantId);
+ }
+
+ @Override
+ public void unregisterTenantId(TenantId tenantId) {
+ checkNotNull(tenantId, TENANT_NULL);
+ store.removeTenantId(tenantId);
+ }
+
+ @Override
+ public Set<TenantId> getTenantIds() {
+ return store.getTenantIds();
+ }
+
+ @Override
+ public VirtualNetwork createVirtualNetwork(TenantId tenantId) {
+ checkNotNull(tenantId, TENANT_NULL);
+ return store.addNetwork(tenantId);
+ }
+
+ @Override
+ public void removeVirtualNetwork(NetworkId networkId) {
+ checkNotNull(networkId, NETWORK_NULL);
+ store.removeNetwork(networkId);
+ }
+
+ @Override
+ public VirtualDevice createVirtualDevice(NetworkId networkId, DeviceId deviceId) {
+ checkNotNull(networkId, NETWORK_NULL);
+ checkNotNull(deviceId, DEVICE_NULL);
+ return store.addDevice(networkId, deviceId);
+ }
+
+ @Override
+ public void removeVirtualDevice(NetworkId networkId, DeviceId deviceId) {
+ checkNotNull(networkId, NETWORK_NULL);
+ checkNotNull(deviceId, DEVICE_NULL);
+ store.removeDevice(networkId, deviceId);
+ }
+
+ @Override
+ public VirtualLink createVirtualLink(NetworkId networkId,
+ ConnectPoint src, ConnectPoint dst,
+ TunnelId realizedBy) {
+ checkNotNull(networkId, NETWORK_NULL);
+ checkNotNull(src, LINK_POINT_NULL);
+ checkNotNull(dst, LINK_POINT_NULL);
+ checkNotNull(realizedBy, "Tunnel ID cannot be null");
+ return store.addLink(networkId, src, dst, realizedBy);
+ }
+
+ @Override
+ public void removeVirtualLink(NetworkId networkId, ConnectPoint src, ConnectPoint dst) {
+ checkNotNull(networkId, NETWORK_NULL);
+ checkNotNull(src, LINK_POINT_NULL);
+ checkNotNull(dst, LINK_POINT_NULL);
+ store.removeLink(networkId, src, dst);
+ }
+
+ @Override
+ public VirtualPort createVirtualPort(NetworkId networkId, DeviceId deviceId,
+ PortNumber portNumber, Port realizedBy) {
+ checkNotNull(networkId, NETWORK_NULL);
+ checkNotNull(deviceId, DEVICE_NULL);
+ checkNotNull(portNumber, "Port description cannot be null");
+ return store.addPort(networkId, deviceId, portNumber, realizedBy);
+ }
+
+ @Override
+ public void removeVirtualPort(NetworkId networkId, DeviceId deviceId, PortNumber portNumber) {
+ checkNotNull(networkId, NETWORK_NULL);
+ checkNotNull(deviceId, DEVICE_NULL);
+ checkNotNull(portNumber, "Port number cannot be null");
+ store.removePort(networkId, deviceId, portNumber);
+ }
+
+ @Override
+ public Set<VirtualNetwork> getVirtualNetworks(TenantId tenantId) {
+ checkNotNull(tenantId, TENANT_NULL);
+ return store.getNetworks(tenantId);
+ }
+
+ @Override
+ public Set<VirtualDevice> getVirtualDevices(NetworkId networkId) {
+ checkNotNull(networkId, NETWORK_NULL);
+ return store.getDevices(networkId);
+ }
+
+ @Override
+ public Set<VirtualLink> getVirtualLinks(NetworkId networkId) {
+ checkNotNull(networkId, NETWORK_NULL);
+ return store.getLinks(networkId);
+ }
+
+ @Override
+ public Set<VirtualPort> getVirtualPorts(NetworkId networkId, DeviceId deviceId) {
+ checkNotNull(networkId, NETWORK_NULL);
+ checkNotNull(deviceId, DEVICE_NULL);
+ return store.getPorts(networkId, deviceId);
+ }
+
+ @Override
+ public <T> T get(NetworkId networkId, Class<T> serviceClass) {
+ checkNotNull(networkId, NETWORK_NULL);
+ return null;
+ }
+
+ @Override
+ protected VirtualNetworkProviderService createProviderService(VirtualNetworkProvider provider) {
+ return new InternalVirtualNetworkProviderService(provider);
+ }
+
+ // Service issued to registered virtual network providers so that they
+ // can interact with the core.
+ private class InternalVirtualNetworkProviderService
+ extends AbstractProviderService<VirtualNetworkProvider>
+ implements VirtualNetworkProviderService {
+ InternalVirtualNetworkProviderService(VirtualNetworkProvider provider) {
+ super(provider);
+ }
+ }
+
+ // Auxiliary store delegate to receive notification about changes in
+ // the virtual network configuration store state - by the store itself.
+ private class InternalStoreDelegate implements VirtualNetworkStoreDelegate {
+ @Override
+ public void notify(VirtualNetworkEvent event) {
+ post(event);
+ }
+ }
+
+}
diff --git a/framework/src/onos/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/package-info.java b/framework/src/onos/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/package-info.java
new file mode 100644
index 00000000..da4be5aa
--- /dev/null
+++ b/framework/src/onos/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/package-info.java
@@ -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.
+ */
+
+/**
+ * Implementation of the virtual network subsystem.
+ */
+package org.onosproject.incubator.net.virtual.impl; \ No newline at end of file
diff --git a/framework/src/onos/incubator/net/src/test/java/org/onosproject/incubator/net/mcast/impl/MulticastRouteManagerTest.java b/framework/src/onos/incubator/net/src/test/java/org/onosproject/incubator/net/mcast/impl/MulticastRouteManagerTest.java
new file mode 100644
index 00000000..545e21d0
--- /dev/null
+++ b/framework/src/onos/incubator/net/src/test/java/org/onosproject/incubator/net/mcast/impl/MulticastRouteManagerTest.java
@@ -0,0 +1,200 @@
+/*
+ * 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.incubator.net.mcast.impl;
+
+import com.google.common.collect.Lists;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.junit.TestUtils;
+import org.onlab.packet.IpPrefix;
+import org.onosproject.common.event.impl.TestEventDispatcher;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.core.DefaultApplicationId;
+import org.onosproject.core.IdGenerator;
+import org.onosproject.core.Version;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.mcast.McastEvent;
+import org.onosproject.net.mcast.McastListener;
+import org.onosproject.net.mcast.McastRoute;
+import org.onosproject.store.service.TestStorageService;
+
+import java.util.List;
+import java.util.Set;
+
+import static junit.framework.Assert.fail;
+import static junit.framework.TestCase.assertEquals;
+import static org.onosproject.net.NetTestTools.did;
+import static org.onosproject.net.NetTestTools.injectEventDispatcher;
+
+/**
+ * Tests for the multicast RIB.
+ */
+public class MulticastRouteManagerTest {
+
+ McastRoute r1 = new McastRoute(IpPrefix.valueOf("1.1.1.1/8"),
+ IpPrefix.valueOf("1.1.1.2/8"),
+ McastRoute.Type.IGMP);
+
+ McastRoute r11 = new McastRoute(IpPrefix.valueOf("1.1.1.1/8"),
+ IpPrefix.valueOf("1.1.1.2/8"),
+ McastRoute.Type.STATIC);
+
+ McastRoute r2 = new McastRoute(IpPrefix.valueOf("2.2.2.1/8"),
+ IpPrefix.valueOf("2.2.2.2/8"),
+ McastRoute.Type.PIM);
+
+ ConnectPoint cp1 = new ConnectPoint(did("1"), PortNumber.portNumber(1));
+
+ ConnectPoint cp2 = new ConnectPoint(did("2"), PortNumber.portNumber(2));
+
+ private TestMulticastListener listener = new TestMulticastListener();
+
+ private MulticastRouteManager manager;
+
+ private List<McastEvent> events;
+
+ @Before
+ public void setUp() throws Exception {
+ manager = new MulticastRouteManager();
+ injectEventDispatcher(manager, new TestEventDispatcher());
+ TestUtils.setField(manager, "storageService", new TestStorageService());
+ TestUtils.setField(manager, "coreService", new TestCoreService());
+ events = Lists.newArrayList();
+ manager.activate();
+ manager.addListener(listener);
+ }
+
+ @After
+ public void tearDown() {
+ manager.removeListener(listener);
+ manager.deactivate();
+ }
+
+ @Test
+ public void testAdd() {
+ manager.add(r1);
+
+ assertEquals("Add failed", manager.mcastRoutes.size(), 1);
+ validateEvents(McastEvent.Type.ROUTE_ADDED);
+ }
+
+ @Test
+ public void testRemove() {
+ manager.add(r1);
+
+ manager.remove(r1);
+
+ assertEquals("Remove failed", manager.mcastRoutes.size(), 0);
+ validateEvents(McastEvent.Type.ROUTE_ADDED, McastEvent.Type.ROUTE_REMOVED);
+ }
+
+ @Test
+ public void testAddSource() {
+ manager.add(r1);
+
+ manager.addSource(r1, cp1);
+
+ validateEvents(McastEvent.Type.ROUTE_ADDED, McastEvent.Type.SOURCE_ADDED);
+ assertEquals("Route is not equal", cp1, manager.fetchSource(r1));
+ }
+
+ @Test
+ public void testAddSink() {
+ manager.add(r1);
+
+ manager.addSource(r1, cp1);
+ manager.addSink(r1, cp1);
+
+ validateEvents(McastEvent.Type.ROUTE_ADDED,
+ McastEvent.Type.SOURCE_ADDED,
+ McastEvent.Type.SINK_ADDED);
+ assertEquals("Route is not equal", Lists.newArrayList(cp1), manager.fetchSinks(r1));
+ }
+
+ @Test
+ public void testRemoveSink() {
+ manager.add(r1);
+
+ manager.addSource(r1, cp1);
+ manager.addSink(r1, cp1);
+ manager.addSink(r1, cp2);
+ manager.removeSink(r1, cp2);
+
+ validateEvents(McastEvent.Type.ROUTE_ADDED,
+ McastEvent.Type.SOURCE_ADDED,
+ McastEvent.Type.SINK_ADDED,
+ McastEvent.Type.SINK_ADDED,
+ McastEvent.Type.SINK_REMOVED);
+ assertEquals("Route is not equal", Lists.newArrayList(cp1), manager.fetchSinks(r1));
+ }
+
+ private void validateEvents(McastEvent.Type... evs) {
+ if (events.size() != evs.length) {
+ fail(String.format("Mismatch number of events# obtained -> %s : expected %s",
+ events, evs));
+ }
+
+ for (int i = 0; i < evs.length; i++) {
+ if (evs[i] != events.get(i).type()) {
+ fail(String.format("Mismtached events# obtained -> %s : expected %s",
+ events, evs));
+ }
+ }
+ }
+
+ class TestMulticastListener implements McastListener {
+
+ @Override
+ public void event(McastEvent event) {
+ events.add(event);
+ }
+ }
+
+ private class TestCoreService implements CoreService {
+ @Override
+ public Version version() {
+ return null;
+ }
+
+ @Override
+ public Set<ApplicationId> getAppIds() {
+ return null;
+ }
+
+ @Override
+ public ApplicationId getAppId(Short id) {
+ return null;
+ }
+
+ @Override
+ public ApplicationId getAppId(String name) {
+ return null;
+ }
+
+ @Override
+ public ApplicationId registerApplication(String identifier) {
+ return new DefaultApplicationId(0, identifier);
+ }
+
+ @Override
+ public IdGenerator getIdGenerator(String topic) {
+ return null;
+ }
+ }
+}
diff --git a/framework/src/onos/incubator/net/src/test/java/org/onosproject/incubator/net/meter/impl/MeterManagerTest.java b/framework/src/onos/incubator/net/src/test/java/org/onosproject/incubator/net/meter/impl/MeterManagerTest.java
index e0c0c868..76caebcb 100644
--- a/framework/src/onos/incubator/net/src/test/java/org/onosproject/incubator/net/meter/impl/MeterManagerTest.java
+++ b/framework/src/onos/incubator/net/src/test/java/org/onosproject/incubator/net/meter/impl/MeterManagerTest.java
@@ -130,7 +130,7 @@ public class MeterManagerTest {
m2 = DefaultMeter.builder()
.forDevice(did("2"))
.fromApp(APP_ID)
- .withId(MeterId.meterId(2))
+ .withId(MeterId.meterId(1))
.withUnit(Meter.Unit.KB_PER_SEC)
.withBands(Collections.singletonList(band))
.build();
@@ -167,7 +167,7 @@ public class MeterManagerTest {
assertTrue("The meter was not added", manager.getAllMeters().size() == 1);
- assertThat(manager.getMeter(MeterId.meterId(1)), is(m1));
+ assertThat(manager.getMeter(did("1"), MeterId.meterId(1)), is(m1));
}
@Test
@@ -175,7 +175,7 @@ public class MeterManagerTest {
manager.submit(m1Request.add());
manager.withdraw(m1Request.remove(), m1.id());
- assertThat(manager.getMeter(MeterId.meterId(1)).state(),
+ assertThat(manager.getMeter(did("1"), MeterId.meterId(1)).state(),
is(MeterState.PENDING_REMOVE));
providerService.pushMeterMetrics(m1.deviceId(), Collections.emptyList());
@@ -184,7 +184,16 @@ public class MeterManagerTest {
}
+ @Test
+ public void testMultipleDevice() {
+ manager.submit(m1Request.add());
+ manager.submit(m2Request.add());
+ assertTrue("The meters were not added", manager.getAllMeters().size() == 2);
+
+ assertThat(manager.getMeter(did("1"), MeterId.meterId(1)), is(m1));
+ assertThat(manager.getMeter(did("2"), MeterId.meterId(1)), is(m2));
+ }
public class TestApplicationId extends DefaultApplicationId {
public TestApplicationId(int id, String name) {
diff --git a/framework/src/onos/incubator/store/src/main/java/org/onosproject/incubator/store/meter/impl/DistributedMeterStore.java b/framework/src/onos/incubator/store/src/main/java/org/onosproject/incubator/store/meter/impl/DistributedMeterStore.java
index 32890cb1..62a94675 100644
--- a/framework/src/onos/incubator/store/src/main/java/org/onosproject/incubator/store/meter/impl/DistributedMeterStore.java
+++ b/framework/src/onos/incubator/store/src/main/java/org/onosproject/incubator/store/meter/impl/DistributedMeterStore.java
@@ -33,6 +33,7 @@ import org.onosproject.net.meter.Meter;
import org.onosproject.net.meter.MeterEvent;
import org.onosproject.net.meter.MeterFailReason;
import org.onosproject.net.meter.MeterId;
+import org.onosproject.net.meter.MeterKey;
import org.onosproject.net.meter.MeterOperation;
import org.onosproject.net.meter.MeterState;
import org.onosproject.net.meter.MeterStore;
@@ -78,12 +79,12 @@ public class DistributedMeterStore extends AbstractStore<MeterEvent, MeterStoreD
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
private ClusterService clusterService;
- private ConsistentMap<MeterId, MeterData> meters;
+ private ConsistentMap<MeterKey, MeterData> meters;
private NodeId local;
- private MapEventListener mapListener = new InternalMapEventListener();
+ private MapEventListener<MeterKey, MeterData> mapListener = new InternalMapEventListener();
- private Map<MeterId, CompletableFuture<MeterStoreResult>> futures =
+ private Map<MeterKey, CompletableFuture<MeterStoreResult>> futures =
Maps.newConcurrentMap();
@Activate
@@ -92,9 +93,10 @@ public class DistributedMeterStore extends AbstractStore<MeterEvent, MeterStoreD
local = clusterService.getLocalNode().id();
- meters = storageService.<MeterId, MeterData>consistentMapBuilder()
+ meters = storageService.<MeterKey, MeterData>consistentMapBuilder()
.withName(METERSTORE)
.withSerializer(Serializer.using(Arrays.asList(KryoNamespaces.API),
+ MeterKey.class,
MeterData.class,
DefaultMeter.class,
DefaultBand.class,
@@ -120,11 +122,12 @@ public class DistributedMeterStore extends AbstractStore<MeterEvent, MeterStoreD
@Override
public CompletableFuture<MeterStoreResult> storeMeter(Meter meter) {
CompletableFuture<MeterStoreResult> future = new CompletableFuture<>();
- futures.put(meter.id(), future);
+ MeterKey key = MeterKey.key(meter.deviceId(), meter.id());
+ futures.put(key, future);
MeterData data = new MeterData(meter, null, local);
try {
- meters.put(meter.id(), data);
+ meters.put(key, data);
} catch (StorageException e) {
future.completeExceptionally(e);
}
@@ -136,14 +139,15 @@ public class DistributedMeterStore extends AbstractStore<MeterEvent, MeterStoreD
@Override
public CompletableFuture<MeterStoreResult> deleteMeter(Meter meter) {
CompletableFuture<MeterStoreResult> future = new CompletableFuture<>();
- futures.put(meter.id(), future);
+ MeterKey key = MeterKey.key(meter.deviceId(), meter.id());
+ futures.put(key, future);
MeterData data = new MeterData(meter, null, local);
// update the state of the meter. It will be pruned by observing
// that it has been removed from the dataplane.
try {
- if (meters.computeIfPresent(meter.id(), (k, v) -> data) == null) {
+ if (meters.computeIfPresent(key, (k, v) -> data) == null) {
future.complete(MeterStoreResult.success());
}
} catch (StorageException e) {
@@ -157,11 +161,12 @@ public class DistributedMeterStore extends AbstractStore<MeterEvent, MeterStoreD
@Override
public CompletableFuture<MeterStoreResult> updateMeter(Meter meter) {
CompletableFuture<MeterStoreResult> future = new CompletableFuture<>();
- futures.put(meter.id(), future);
+ MeterKey key = MeterKey.key(meter.deviceId(), meter.id());
+ futures.put(key, future);
MeterData data = new MeterData(meter, null, local);
try {
- if (meters.computeIfPresent(meter.id(), (k, v) -> data) == null) {
+ if (meters.computeIfPresent(key, (k, v) -> data) == null) {
future.complete(MeterStoreResult.fail(MeterFailReason.INVALID_METER));
}
} catch (StorageException e) {
@@ -172,7 +177,8 @@ public class DistributedMeterStore extends AbstractStore<MeterEvent, MeterStoreD
@Override
public void updateMeterState(Meter meter) {
- meters.computeIfPresent(meter.id(), (id, v) -> {
+ MeterKey key = MeterKey.key(meter.deviceId(), meter.id());
+ meters.computeIfPresent(key, (k, v) -> {
DefaultMeter m = (DefaultMeter) v.meter();
m.setState(meter.state());
m.setProcessedPackets(meter.packetsSeen());
@@ -185,8 +191,8 @@ public class DistributedMeterStore extends AbstractStore<MeterEvent, MeterStoreD
}
@Override
- public Meter getMeter(MeterId meterId) {
- MeterData data = Versioned.valueOrElse(meters.get(meterId), null);
+ public Meter getMeter(MeterKey key) {
+ MeterData data = Versioned.valueOrElse(meters.get(key), null);
return data == null ? null : data.meter();
}
@@ -198,19 +204,22 @@ public class DistributedMeterStore extends AbstractStore<MeterEvent, MeterStoreD
@Override
public void failedMeter(MeterOperation op, MeterFailReason reason) {
- meters.computeIfPresent(op.meter().id(), (k, v) ->
+ MeterKey key = MeterKey.key(op.meter().deviceId(), op.meter().id());
+ meters.computeIfPresent(key, (k, v) ->
new MeterData(v.meter(), reason, v.origin()));
}
@Override
public void deleteMeterNow(Meter m) {
- futures.remove(m.id());
- meters.remove(m.id());
+ MeterKey key = MeterKey.key(m.deviceId(), m.id());
+ futures.remove(key);
+ meters.remove(key);
}
- private class InternalMapEventListener implements MapEventListener<MeterId, MeterData> {
+ private class InternalMapEventListener implements MapEventListener<MeterKey, MeterData> {
@Override
- public void event(MapEvent<MeterId, MeterData> event) {
+ public void event(MapEvent<MeterKey, MeterData> event) {
+ MeterKey key = event.key();
MeterData data = event.value().value();
NodeId master = mastershipService.getMasterFor(data.meter().deviceId());
switch (event.type()) {
@@ -227,17 +236,17 @@ public class DistributedMeterStore extends AbstractStore<MeterEvent, MeterStoreD
} else if (data.reason().isPresent() && local.equals(data.origin())) {
MeterStoreResult msr = MeterStoreResult.fail(data.reason().get());
//TODO: No future -> no friend
- futures.get(data.meter().id()).complete(msr);
+ futures.get(key).complete(msr);
}
break;
case ADDED:
if (local.equals(data.origin()) && data.meter().state() == MeterState.PENDING_ADD) {
- futures.remove(data.meter().id()).complete(MeterStoreResult.success());
+ futures.remove(key).complete(MeterStoreResult.success());
}
break;
case REMOVED:
if (local.equals(data.origin()) && data.meter().state() == MeterState.PENDING_REMOVE) {
- futures.remove(data.meter().id()).complete(MeterStoreResult.success());
+ futures.remove(key).complete(MeterStoreResult.success());
}
break;
default:
diff --git a/framework/src/onos/incubator/store/src/main/java/org/onosproject/incubator/store/virtual/impl/DistributedVirtualNetworkStore.java b/framework/src/onos/incubator/store/src/main/java/org/onosproject/incubator/store/virtual/impl/DistributedVirtualNetworkStore.java
new file mode 100644
index 00000000..69e56c0b
--- /dev/null
+++ b/framework/src/onos/incubator/store/src/main/java/org/onosproject/incubator/store/virtual/impl/DistributedVirtualNetworkStore.java
@@ -0,0 +1,147 @@
+/*
+ * 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.incubator.store.virtual.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.onosproject.incubator.net.tunnel.TunnelId;
+import org.onosproject.incubator.net.virtual.DefaultVirtualDevice;
+import org.onosproject.incubator.net.virtual.DefaultVirtualNetwork;
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.incubator.net.virtual.TenantId;
+import org.onosproject.incubator.net.virtual.VirtualDevice;
+import org.onosproject.incubator.net.virtual.VirtualLink;
+import org.onosproject.incubator.net.virtual.VirtualNetwork;
+import org.onosproject.incubator.net.virtual.VirtualNetworkEvent;
+import org.onosproject.incubator.net.virtual.VirtualNetworkStore;
+import org.onosproject.incubator.net.virtual.VirtualNetworkStoreDelegate;
+import org.onosproject.incubator.net.virtual.VirtualPort;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.store.AbstractStore;
+import org.slf4j.Logger;
+
+import java.util.Set;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Implementation of the network store.
+ */
+@Component(immediate = true)
+@Service
+public class DistributedVirtualNetworkStore
+ extends AbstractStore<VirtualNetworkEvent, VirtualNetworkStoreDelegate>
+ implements VirtualNetworkStore {
+
+ private final Logger log = getLogger(getClass());
+
+ // TODO: track tenants by ID
+ // TODO: track networks by ID and by tenants
+ // TODO: track devices by network ID and device ID
+ // TODO: track devices by network ID
+ // TODO: setup block allocator for network IDs
+
+ // TODO: notify delegate
+
+ @Activate
+ public void activate() {
+ log.info("Started");
+ }
+
+ @Deactivate
+ public void deactivate() {
+ log.info("Stopped");
+ }
+
+ @Override
+ public void addTenantId(TenantId tenantId) {
+ }
+
+ @Override
+ public void removeTenantId(TenantId tenantId) {
+ }
+
+ @Override
+ public Set<TenantId> getTenantIds() {
+ return null;
+ }
+
+ @Override
+ public VirtualNetwork addNetwork(TenantId tenantId) {
+ return new DefaultVirtualNetwork(genNetworkId(), tenantId);
+ }
+
+ private NetworkId genNetworkId() {
+ return NetworkId.networkId(0); // TODO: use a block allocator
+ }
+
+
+ @Override
+ public void removeNetwork(NetworkId networkId) {
+ }
+
+ @Override
+ public VirtualDevice addDevice(NetworkId networkId, DeviceId deviceId) {
+ return new DefaultVirtualDevice(networkId, deviceId);
+ }
+
+ @Override
+ public void removeDevice(NetworkId networkId, DeviceId deviceId) {
+ }
+
+ @Override
+ public VirtualLink addLink(NetworkId networkId, ConnectPoint src, ConnectPoint dst, TunnelId realizedBy) {
+ return null;
+ }
+
+ @Override
+ public void removeLink(NetworkId networkId, ConnectPoint src, ConnectPoint dst) {
+ }
+
+ @Override
+ public VirtualPort addPort(NetworkId networkId, DeviceId deviceId, PortNumber portNumber, Port realizedBy) {
+ return null;
+ }
+
+ @Override
+ public void removePort(NetworkId networkId, DeviceId deviceId, PortNumber portNumber) {
+ }
+
+ @Override
+ public Set<VirtualNetwork> getNetworks(TenantId tenantId) {
+ return null;
+ }
+
+ @Override
+ public Set<VirtualDevice> getDevices(NetworkId networkId) {
+ return null;
+ }
+
+ @Override
+ public Set<VirtualLink> getLinks(NetworkId networkId) {
+ return null;
+ }
+
+ @Override
+ public Set<VirtualPort> getPorts(NetworkId networkId, DeviceId deviceId) {
+ return null;
+ }
+}
diff --git a/framework/src/onos/incubator/store/src/main/java/org/onosproject/incubator/store/virtual/impl/package-info.java b/framework/src/onos/incubator/store/src/main/java/org/onosproject/incubator/store/virtual/impl/package-info.java
new file mode 100644
index 00000000..12fa9091
--- /dev/null
+++ b/framework/src/onos/incubator/store/src/main/java/org/onosproject/incubator/store/virtual/impl/package-info.java
@@ -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.
+ */
+
+/**
+ * Implementation of distributed virtual network store.
+ */
+package org.onosproject.incubator.store.virtual.impl;
diff --git a/framework/src/onos/openflow/api/src/main/java/org/onosproject/openflow/controller/DefaultOpenFlowPacketContext.java b/framework/src/onos/openflow/api/src/main/java/org/onosproject/openflow/controller/DefaultOpenFlowPacketContext.java
index 238c4000..af92a1d0 100644
--- a/framework/src/onos/openflow/api/src/main/java/org/onosproject/openflow/controller/DefaultOpenFlowPacketContext.java
+++ b/framework/src/onos/openflow/api/src/main/java/org/onosproject/openflow/controller/DefaultOpenFlowPacketContext.java
@@ -104,7 +104,7 @@ public final class DefaultOpenFlowPacketContext implements OpenFlowPacketContext
} catch (BufferUnderflowException | NullPointerException |
DeserializationException e) {
Logger log = LoggerFactory.getLogger(getClass());
- log.warn("packet deserialization problem : {}", e.getMessage());
+ log.error("packet deserialization problem : {}", e.getMessage());
return null;
}
}
diff --git a/framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/Controller.java b/framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/Controller.java
index 0c28a6fa..9d355156 100644
--- a/framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/Controller.java
+++ b/framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/Controller.java
@@ -16,6 +16,8 @@
package org.onosproject.openflow.controller.impl;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.group.ChannelGroup;
@@ -37,13 +39,24 @@ import org.projectfloodlight.openflow.protocol.OFVersion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.TrustManagerFactory;
+import java.io.FileInputStream;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.net.InetSocketAddress;
+import java.security.KeyStore;
+import java.util.Dictionary;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import static org.onlab.util.Tools.get;
import static org.onlab.util.Tools.groupedThreads;
import static org.onosproject.net.DeviceId.deviceId;
import static org.onosproject.openflow.controller.Dpid.uri;
@@ -59,14 +72,16 @@ public class Controller {
protected static final OFFactory FACTORY13 = OFFactories.getFactory(OFVersion.OF_13);
protected static final OFFactory FACTORY10 = OFFactories.getFactory(OFVersion.OF_10);
+ private static final boolean TLS_DISABLED = false;
+ private static final short MIN_KS_LENGTH = 6;
protected HashMap<String, String> controllerNodeIPsCache;
private ChannelGroup cg;
// Configuration options
- protected int openFlowPort = 6633;
- protected int workerThreads = 0;
+ protected List<Integer> openFlowPorts = ImmutableList.of(6633, 6653);
+ protected int workerThreads = 16;
// Start time of the controller
protected long systemStartTime;
@@ -75,9 +90,16 @@ public class Controller {
private NioServerSocketChannelFactory execFactory;
+ protected String ksLocation;
+ protected String tsLocation;
+ protected char[] ksPwd;
+ protected char[] tsPwd;
+ private SSLEngine serverSSLEngine;
+
// Perf. related configuration
protected static final int SEND_BUFFER_SIZE = 4 * 1024 * 1024;
private DriverService driverService;
+ private boolean enableOFTLS = TLS_DISABLED;
// ***************
// Getters/Setters
@@ -127,13 +149,15 @@ public class Controller {
bootstrap.setOption("child.sendBufferSize", Controller.SEND_BUFFER_SIZE);
ChannelPipelineFactory pfact =
- new OpenflowPipelineFactory(this, null);
+ new OpenflowPipelineFactory(this, null, serverSSLEngine);
bootstrap.setPipelineFactory(pfact);
- InetSocketAddress sa = new InetSocketAddress(openFlowPort);
cg = new DefaultChannelGroup();
- cg.add(bootstrap.bind(sa));
+ openFlowPorts.forEach(port -> {
+ InetSocketAddress sa = new InetSocketAddress(port);
+ cg.add(bootstrap.bind(sa));
+ log.info("Listening for switch connections on {}", sa);
+ });
- log.info("Listening for switch connections on {}", sa);
} catch (Exception e) {
throw new RuntimeException(e);
}
@@ -155,19 +179,22 @@ public class Controller {
}
}
- public void setConfigParams(Map<String, String> configParams) {
- String ofPort = configParams.get("openflowport");
- if (ofPort != null) {
- this.openFlowPort = Integer.parseInt(ofPort);
+ public void setConfigParams(Dictionary<?, ?> properties) {
+ String ports = get(properties, "openflowPorts");
+ if (!Strings.isNullOrEmpty(ports)) {
+ this.openFlowPorts = Stream.of(ports.split(","))
+ .map(s -> Integer.parseInt(s))
+ .collect(Collectors.toList());
}
+ log.debug("OpenFlow ports set to {}", this.openFlowPorts);
- log.debug("OpenFlow port set to {}", this.openFlowPort);
- String threads = configParams.get("workerthreads");
- this.workerThreads = threads != null ? Integer.parseInt(threads) : 16;
+ String threads = get(properties, "workerThreads");
+ if (!Strings.isNullOrEmpty(threads)) {
+ this.workerThreads = Integer.parseInt(threads);
+ }
log.debug("Number of worker threads set to {}", this.workerThreads);
}
-
/**
* Initialize internal data structures.
*/
@@ -177,6 +204,68 @@ public class Controller {
this.controllerNodeIPsCache = new HashMap<>();
this.systemStartTime = System.currentTimeMillis();
+
+ try {
+ getTLSParameters();
+ if (enableOFTLS) {
+ initSSL();
+ }
+ } catch (Exception ex) {
+ log.error("SSL init failed: {}", ex.getMessage());
+ }
+
+ }
+
+ private void getTLSParameters() {
+ String tempString = System.getProperty("enableOFTLS");
+ enableOFTLS = Strings.isNullOrEmpty(tempString) ? TLS_DISABLED : Boolean.parseBoolean(tempString);
+ log.info("OpenFlow Security is {}", enableOFTLS ? "enabled" : "disabled");
+ if (enableOFTLS) {
+ ksLocation = System.getProperty("javax.net.ssl.keyStore");
+ if (Strings.isNullOrEmpty(ksLocation)) {
+ enableOFTLS = TLS_DISABLED;
+ return;
+ }
+ tsLocation = System.getProperty("javax.net.ssl.trustStore");
+ if (Strings.isNullOrEmpty(tsLocation)) {
+ enableOFTLS = TLS_DISABLED;
+ return;
+ }
+ ksPwd = System.getProperty("javax.net.ssl.keyStorePassword").toCharArray();
+ if (MIN_KS_LENGTH > ksPwd.length) {
+ enableOFTLS = TLS_DISABLED;
+ return;
+ }
+ tsPwd = System.getProperty("javax.net.ssl.trustStorePassword").toCharArray();
+ if (MIN_KS_LENGTH > tsPwd.length) {
+ enableOFTLS = TLS_DISABLED;
+ return;
+ }
+ }
+ }
+
+ private void initSSL() throws Exception {
+
+ TrustManagerFactory tmFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ KeyStore ts = KeyStore.getInstance("JKS");
+ ts.load(new FileInputStream(tsLocation), tsPwd);
+ tmFactory.init(ts);
+
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ KeyStore ks = KeyStore.getInstance("JKS");
+ ks.load(new FileInputStream(ksLocation), ksPwd);
+ kmf.init(ks, ksPwd);
+
+ SSLContext serverContext = SSLContext.getInstance("TLS");
+ serverContext.init(kmf.getKeyManagers(), tmFactory.getTrustManagers(), null);
+
+ serverSSLEngine = serverContext.createSSLEngine();
+
+ serverSSLEngine.setNeedClientAuth(true);
+ serverSSLEngine.setUseClientMode(false);
+ serverSSLEngine.setEnabledProtocols(serverSSLEngine.getSupportedProtocols());
+ serverSSLEngine.setEnabledCipherSuites(serverSSLEngine.getSupportedCipherSuites());
+ serverSSLEngine.setEnableSessionCreation(true);
}
// **************
diff --git a/framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OFChannelHandler.java b/framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OFChannelHandler.java
index 450aa827..1a088ff7 100644
--- a/framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OFChannelHandler.java
+++ b/framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OFChannelHandler.java
@@ -941,7 +941,8 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
void processOFHello(OFChannelHandler h, OFHello m)
throws IOException, SwitchStateException {
// we only expect hello in the WAIT_HELLO state
- illegalMessageReceived(h, m);
+ log.warn("Received Hello outside WAIT_HELLO state; switch {} is not complaint.",
+ h.channel.getRemoteAddress());
}
void processOFBarrierReply(OFChannelHandler h, OFBarrierReply m)
diff --git a/framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImpl.java b/framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImpl.java
index c82078a1..d0429947 100644
--- a/framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImpl.java
+++ b/framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImpl.java
@@ -15,7 +15,6 @@
*/
package org.onosproject.openflow.controller.impl;
-import com.google.common.base.Strings;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
@@ -48,6 +47,8 @@ import org.projectfloodlight.openflow.protocol.OFExperimenter;
import org.projectfloodlight.openflow.protocol.OFFactories;
import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry;
import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
+import org.projectfloodlight.openflow.protocol.OFTableStatsEntry;
+import org.projectfloodlight.openflow.protocol.OFTableStatsReply;
import org.projectfloodlight.openflow.protocol.OFGroupDescStatsEntry;
import org.projectfloodlight.openflow.protocol.OFGroupDescStatsReply;
import org.projectfloodlight.openflow.protocol.OFGroupStatsEntry;
@@ -67,11 +68,8 @@ import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.Collections;
-import java.util.Dictionary;
-import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
-import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
@@ -80,13 +78,12 @@ import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
-import static org.onlab.util.Tools.get;
import static org.onlab.util.Tools.groupedThreads;
@Component(immediate = true)
@Service
public class OpenFlowControllerImpl implements OpenFlowController {
- private static final int DEFAULT_OFPORT = 6633;
+ private static final String DEFAULT_OFPORT = "6633,6653";
private static final int DEFAULT_WORKER_THREADS = 16;
private static final Logger log =
@@ -102,9 +99,9 @@ public class OpenFlowControllerImpl implements OpenFlowController {
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected ComponentConfigService cfgService;
- @Property(name = "openflowPort", intValue = DEFAULT_OFPORT,
- label = "Port number used by OpenFlow protocol; default is 6633")
- private int openflowPort = DEFAULT_OFPORT;
+ @Property(name = "openflowPorts", value = DEFAULT_OFPORT,
+ label = "Port numbers (comma separated) used by OpenFlow protocol; default is 6633,6653")
+ private String openflowPorts = DEFAULT_OFPORT;
@Property(name = "workerThreads", intValue = DEFAULT_WORKER_THREADS,
label = "Number of controller worker threads; default is 16")
@@ -134,6 +131,9 @@ public class OpenFlowControllerImpl implements OpenFlowController {
protected Multimap<Dpid, OFFlowStatsEntry> fullFlowStats =
ArrayListMultimap.create();
+ protected Multimap<Dpid, OFTableStatsEntry> fullTableStats =
+ ArrayListMultimap.create();
+
protected Multimap<Dpid, OFGroupStatsEntry> fullGroupStats =
ArrayListMultimap.create();
@@ -148,8 +148,7 @@ public class OpenFlowControllerImpl implements OpenFlowController {
@Activate
public void activate(ComponentContext context) {
cfgService.registerProperties(getClass());
- Map<String, String> properties = readComponentConfiguration(context);
- ctrl.setConfigParams(properties);
+ ctrl.setConfigParams(context.getProperties());
ctrl.start(agent, driverService);
}
@@ -159,33 +158,10 @@ public class OpenFlowControllerImpl implements OpenFlowController {
ctrl.stop();
}
- /**
- * Extracts properties from the component configuration context.
- *
- * @param context the component context
- */
- private Map<String, String> readComponentConfiguration(ComponentContext context) {
- Dictionary<?, ?> properties = context.getProperties();
- Map<String, String> outProperties = new HashMap<>();
-
- String port = get(properties, "openflowPort");
- if (!Strings.isNullOrEmpty(port)) {
- outProperties.put("openflowport", port);
- }
-
- String thread = get(properties, "workerThreads");
- if (!Strings.isNullOrEmpty(thread)) {
- outProperties.put("workerthreads", thread);
- }
-
- return outProperties;
- }
-
@Modified
public void modified(ComponentContext context) {
- Map<String, String> properties = readComponentConfiguration(context);
ctrl.stop();
- ctrl.setConfigParams(properties);
+ ctrl.setConfigParams(context.getProperties());
ctrl.start(agent, driverService);
}
@@ -259,6 +235,7 @@ public class OpenFlowControllerImpl implements OpenFlowController {
@Override
public void processPacket(Dpid dpid, OFMessage msg) {
Collection<OFFlowStatsEntry> flowStats;
+ Collection<OFTableStatsEntry> tableStats;
Collection<OFGroupStatsEntry> groupStats;
Collection<OFGroupDescStatsEntry> groupDescStats;
Collection<OFPortStatsEntry> portStats;
@@ -302,6 +279,16 @@ public class OpenFlowControllerImpl implements OpenFlowController {
OFFlowStatsReply.Builder rep =
OFFactories.getFactory(msg.getVersion()).buildFlowStatsReply();
rep.setEntries(Lists.newLinkedList(flowStats));
+ rep.setXid(reply.getXid());
+ executorMsgs.submit(new OFMessageHandler(dpid, rep.build()));
+ }
+ break;
+ case TABLE:
+ tableStats = publishTableStats(dpid, (OFTableStatsReply) reply);
+ if (tableStats != null) {
+ OFTableStatsReply.Builder rep =
+ OFFactories.getFactory(msg.getVersion()).buildTableStatsReply();
+ rep.setEntries(Lists.newLinkedList(tableStats));
executorMsgs.submit(new OFMessageHandler(dpid, rep.build()));
}
break;
@@ -423,6 +410,16 @@ public class OpenFlowControllerImpl implements OpenFlowController {
return null;
}
+ private synchronized Collection<OFTableStatsEntry> publishTableStats(Dpid dpid,
+ OFTableStatsReply reply) {
+ //TODO: Get rid of synchronized
+ fullTableStats.putAll(dpid, reply.getEntries());
+ if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
+ return fullTableStats.removeAll(dpid);
+ }
+ return null;
+ }
+
private synchronized Collection<OFGroupStatsEntry> publishGroupStats(Dpid dpid,
OFGroupStatsReply reply) {
//TODO: Get rid of synchronized
diff --git a/framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OpenflowPipelineFactory.java b/framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OpenflowPipelineFactory.java
index c7ba105c..1467520d 100644
--- a/framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OpenflowPipelineFactory.java
+++ b/framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OpenflowPipelineFactory.java
@@ -27,6 +27,10 @@ import org.jboss.netty.handler.timeout.ReadTimeoutHandler;
import org.jboss.netty.util.ExternalResourceReleasable;
import org.jboss.netty.util.HashedWheelTimer;
import org.jboss.netty.util.Timer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.net.ssl.SSLEngine;
/**
* Creates a ChannelPipeline for a server-side openflow channel.
@@ -34,6 +38,9 @@ import org.jboss.netty.util.Timer;
public class OpenflowPipelineFactory
implements ChannelPipelineFactory, ExternalResourceReleasable {
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ private final SSLEngine sslEngine;
protected Controller controller;
protected ThreadPoolExecutor pipelineExecutor;
protected Timer timer;
@@ -41,13 +48,15 @@ public class OpenflowPipelineFactory
protected ReadTimeoutHandler readTimeoutHandler;
public OpenflowPipelineFactory(Controller controller,
- ThreadPoolExecutor pipelineExecutor) {
+ ThreadPoolExecutor pipelineExecutor,
+ SSLEngine sslEngine) {
super();
this.controller = controller;
this.pipelineExecutor = pipelineExecutor;
this.timer = new HashedWheelTimer();
this.idleHandler = new IdleStateHandler(timer, 20, 25, 0);
this.readTimeoutHandler = new ReadTimeoutHandler(timer, 30);
+ this.sslEngine = sslEngine;
}
@Override
@@ -55,6 +64,13 @@ public class OpenflowPipelineFactory
OFChannelHandler handler = new OFChannelHandler(controller);
ChannelPipeline pipeline = Channels.pipeline();
+ if (sslEngine != null) {
+ log.info("OpenFlow SSL enabled.");
+ pipeline.addLast("ssl",
+ new org.jboss.netty.handler.ssl.SslHandler(sslEngine));
+ } else {
+ log.info("OpenFlow SSL disabled");
+ }
pipeline.addLast("ofmessagedecoder", new OFMessageDecoder());
pipeline.addLast("ofmessageencoder", new OFMessageEncoder());
pipeline.addLast("idle", idleHandler);
diff --git a/framework/src/onos/ovsdb/api/pom.xml b/framework/src/onos/ovsdb/api/pom.xml
index 7089216f..c264ae97 100644
--- a/framework/src/onos/ovsdb/api/pom.xml
+++ b/framework/src/onos/ovsdb/api/pom.xml
@@ -48,6 +48,10 @@
</dependency>
<dependency>
<groupId>org.onosproject</groupId>
+ <artifactId>onos-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
<artifactId>onos-ovsdb-rfc</artifactId>
<version>${project.version}</version>
</dependency>
diff --git a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbClientService.java b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbClientService.java
index ab88a24e..f2ff0709 100644
--- a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbClientService.java
+++ b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbClientService.java
@@ -15,19 +15,20 @@
*/
package org.onosproject.ovsdb.controller;
-import java.util.List;
-import java.util.Set;
-
+import com.google.common.util.concurrent.ListenableFuture;
import org.onlab.packet.IpAddress;
-
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.behaviour.ControllerInfo;
import org.onosproject.ovsdb.rfc.jsonrpc.OvsdbRPC;
import org.onosproject.ovsdb.rfc.message.OperationResult;
import org.onosproject.ovsdb.rfc.message.TableUpdates;
import org.onosproject.ovsdb.rfc.notation.Row;
+import org.onosproject.ovsdb.rfc.notation.UUID;
import org.onosproject.ovsdb.rfc.operations.Operation;
import org.onosproject.ovsdb.rfc.schema.DatabaseSchema;
-import com.google.common.util.concurrent.ListenableFuture;
+import java.util.List;
+import java.util.Set;
/**
* Represents to provider facing side of a node.
@@ -85,10 +86,39 @@ public interface OvsdbClientService extends OvsdbRPC {
Set<OvsdbBridge> getBridges();
/**
+ * Gets controllers of the node.
+ *
+ * @return set of controllers; empty if no controller is find
+ */
+ Set<ControllerInfo> getControllers(DeviceId openflowDeviceId);
+
+ /**
+ * Sets the Controllers for the specified bridge.
+ * <p/>
+ * This method will replace the existing controller list with the new controller
+ * list.
+ *
+ * @param bridgeUuid bridge uuid
+ * @param controllers list of controllers
+ */
+ void setControllersWithUUID(UUID bridgeUuid, List<ControllerInfo> controllers);
+
+ /**
+ * Sets the Controllers for the specified device.
+ * <p/>
+ * This method will replace the existing controller list with the new controller
+ * list.
+ *
+ * @param deviceId device id (likely Openflow device)
+ * @param controllers list of controllers
+ */
+ void setControllersWithDeviceId(DeviceId deviceId, List<ControllerInfo> controllers);
+
+ /**
* Creates a port.
*
* @param bridgeName bridge name
- * @param portName port name
+ * @param portName port name
*/
void createPort(String bridgeName, String portName);
@@ -96,7 +126,7 @@ public interface OvsdbClientService extends OvsdbRPC {
* Drops a port.
*
* @param bridgeName bridge name
- * @param portName port name
+ * @param portName port name
*/
void dropPort(String bridgeName, String portName);
@@ -125,7 +155,7 @@ public interface OvsdbClientService extends OvsdbRPC {
/**
* Gets the Port uuid.
*
- * @param portName port name
+ * @param portName port name
* @param bridgeUuid bridge uuid
* @return port uuid, empty if no uuid is find
*/
@@ -143,7 +173,7 @@ public interface OvsdbClientService extends OvsdbRPC {
/**
* Gets the Controller uuid.
*
- * @param controllerName controller name
+ * @param controllerName controller name
* @param controllerTarget controller target
* @return controller uuid, empty if no uuid is find
*/
@@ -169,7 +199,7 @@ public interface OvsdbClientService extends OvsdbRPC {
* Gets the ovsdb table updates.
*
* @param dbName database name
- * @param id random uuid
+ * @param id random uuid
* @return table updates
*/
ListenableFuture<TableUpdates> monitorTables(String dbName, String id);
@@ -177,7 +207,7 @@ public interface OvsdbClientService extends OvsdbRPC {
/**
* Gets the ovsdb config operation result.
*
- * @param dbName database name
+ * @param dbName database name
* @param operations the list of operations
* @return operation results
*/
@@ -187,7 +217,7 @@ public interface OvsdbClientService extends OvsdbRPC {
/**
* Gets the ovsdb database schema from local.
*
- * @param dbName database name
+ * @param dbName database name
* @return database schema
*/
DatabaseSchema getDatabaseSchema(String dbName);
@@ -195,9 +225,9 @@ public interface OvsdbClientService extends OvsdbRPC {
/**
* Gets the ovsdb row from the local ovsdb store.
*
- * @param dbName database name
+ * @param dbName database name
* @param tableName table name
- * @param uuid row uuid
+ * @param uuid row uuid
* @return row ovsdb row
*/
Row getRow(String dbName, String tableName, String uuid);
@@ -205,19 +235,19 @@ public interface OvsdbClientService extends OvsdbRPC {
/**
* Removes the ovsdb row from the local ovsdb store.
*
- * @param dbName database name
+ * @param dbName database name
* @param tableName table name
- * @param uuid row uuid
+ * @param uuid row uuid
*/
void removeRow(String dbName, String tableName, String uuid);
/**
* Updates the local ovsdb store.
*
- * @param dbName database name
+ * @param dbName database name
* @param tableName table name
- * @param uuid row uuid
- * @param row ovsdb row
+ * @param uuid row uuid
+ * @param row ovsdb row
*/
void updateOvsdbStore(String dbName, String tableName, String uuid, Row row);
@@ -228,4 +258,9 @@ public interface OvsdbClientService extends OvsdbRPC {
* @return ovsdb ports
*/
Set<OvsdbPort> getLocalPorts(Iterable<String> ifaceids);
+
+ /**
+ * Disconnects the ovsdb server.
+ */
+ void disconnect();
}
diff --git a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbConstant.java b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbConstant.java
index c1133bbd..e91c928a 100644
--- a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbConstant.java
+++ b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbConstant.java
@@ -60,7 +60,7 @@ public final class OvsdbConstant {
public static final String EXTERNAL_ID_VM_MAC = "attached-mac";
/** Openflow port. */
- public static final int OFPORT = 6633;
+ public static final int OFPORT = 6653;
/** Ovsdb port. */
public static final int OVSDBPORT = 6640;
diff --git a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbController.java b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbController.java
index 9e245240..24bfeae9 100644
--- a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbController.java
+++ b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbController.java
@@ -15,6 +15,9 @@
*/
package org.onosproject.ovsdb.controller;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.TpPort;
+
import java.util.List;
/**
@@ -65,4 +68,12 @@ public interface OvsdbController {
* @return OvsdbClient ovsdb node information
*/
OvsdbClientService getOvsdbClient(OvsdbNodeId nodeId);
+
+ /**
+ * Connect to the ovsdb server with given ip address and port number.
+ *
+ * @param ip ip address
+ * @param port port number
+ */
+ void connect(IpAddress ip, TpPort port);
}
diff --git a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/driver/DefaultOvsdbClient.java b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/driver/DefaultOvsdbClient.java
index 0c64cc0e..3a84d000 100644
--- a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/driver/DefaultOvsdbClient.java
+++ b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/driver/DefaultOvsdbClient.java
@@ -15,19 +15,19 @@
*/
package org.onosproject.ovsdb.controller.driver;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.SettableFuture;
import io.netty.channel.Channel;
-
-import java.net.InetSocketAddress;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.ExecutionException;
-
import org.onlab.packet.IpAddress;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.behaviour.ControllerInfo;
import org.onosproject.ovsdb.controller.OvsdbBridge;
import org.onosproject.ovsdb.controller.OvsdbBridgeName;
import org.onosproject.ovsdb.controller.OvsdbClientService;
@@ -71,14 +71,17 @@ import org.onosproject.ovsdb.rfc.utils.MutationUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.google.common.base.Function;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.SettableFuture;
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.stream.Collectors;
/**
* An representation of an ovsdb client.
@@ -168,9 +171,8 @@ public class DefaultOvsdbClient
/**
* Gets the ovsdb row store.
*
- * @param dbName the ovsdb database name
+ * @param dbName the ovsdb database name
* @param tableName the ovsdb table name
- *
* @return ovsRowStore, empty if row store is find
*/
private OvsdbRowStore getRowStore(String dbName, String tableName) {
@@ -184,9 +186,9 @@ public class DefaultOvsdbClient
/**
* Gets the ovsdb row.
*
- * @param dbName the ovsdb database name
+ * @param dbName the ovsdb database name
* @param tableName the ovsdb table name
- * @param uuid the key of the row
+ * @param uuid the key of the row
* @return row, empty if row is find
*/
@Override
@@ -394,7 +396,7 @@ public class DefaultOvsdbClient
port.setName(portName);
if (portUuid == null) {
insertConfig(OvsdbConstant.PORT, "_uuid", OvsdbConstant.BRIDGE,
- "ports", bridgeUuid, port.getRow());
+ "ports", bridgeUuid, port.getRow());
} else {
updateConfig(OvsdbConstant.PORT, "_uuid", portUuid, port.getRow());
}
@@ -414,7 +416,7 @@ public class DefaultOvsdbClient
if (portUuid != null) {
log.info("Port {} delete", portName);
deleteConfig(OvsdbConstant.PORT, "_uuid", portUuid,
- OvsdbConstant.BRIDGE, "ports");
+ OvsdbConstant.BRIDGE, "ports");
}
}
@@ -455,8 +457,8 @@ public class DefaultOvsdbClient
bridge.setName(bridgeName);
bridgeUuid = insertConfig(OvsdbConstant.BRIDGE, "_uuid",
- OvsdbConstant.DATABASENAME, "bridges",
- ovsUuid, bridge.getRow());
+ OvsdbConstant.DATABASENAME, "bridges",
+ ovsUuid, bridge.getRow());
if (bridgeUuid != null) {
Port port = (Port) TableGenerator.createTable(dbSchema,
@@ -466,7 +468,7 @@ public class DefaultOvsdbClient
port.setName(bridgeName);
insertConfig(OvsdbConstant.PORT, "_uuid", "Bridge", "ports", bridgeUuid,
- port.getRow());
+ port.getRow());
}
}
@@ -475,51 +477,92 @@ public class DefaultOvsdbClient
updateConfig(OvsdbConstant.BRIDGE, "_uuid", bridgeUuid, bridge.getRow());
}
- setController(bridgeUuid);
+ setControllerAuto(bridgeUuid);
log.info("Create bridge success");
}
/**
- * Sets the Controller.
+ * Sets the bridge's controller automatically.
+ * <p/>
+ * The connection is a TCP connection to the local ONOS instance's IP
+ * and the default OpenFlow port.
*
* @param bridgeUuid bridge uuid
*/
- private void setController(String bridgeUuid) {
- String controllerUuid = null;
- String iPAddress = IpAddress.valueOf(((InetSocketAddress) channel
- .localAddress())
- .getAddress()
- .getHostAddress())
- .toString();
+ private void setControllerAuto(String bridgeUuid) {
+ IpAddress ipAddress = IpAddress.valueOf(((InetSocketAddress) channel.localAddress()).getAddress());
+ ControllerInfo controllerInfo = new ControllerInfo(ipAddress, OvsdbConstant.OFPORT, "tcp");
+ log.debug("Automatically setting controller for bridge {} to {}",
+ bridgeUuid, controllerInfo.target());
+ setControllersWithUUID(UUID.uuid(bridgeUuid), ImmutableList.of(controllerInfo));
+ }
- String target = "tcp:" + iPAddress + ":" + OvsdbConstant.OFPORT;
- log.debug("controller IP {}: port {}", iPAddress, OvsdbConstant.OFPORT);
+ @Override
+ public void setControllersWithUUID(UUID bridgeUuid, List<ControllerInfo> controllers) {
DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
- Controller controller = (Controller) TableGenerator
- .createTable(dbSchema, OvsdbTable.CONTROLLER);
-
- if (controller != null) {
- controller.setTarget(target);
- controllerUuid = getControllerUuid(OvsdbConstant.CONTROLLER, target);
- if (controllerUuid == null) {
+ if (dbSchema == null) {
+ log.debug("There is no schema");
+ return;
+ }
+ List<Controller> oldControllers = getControllers(bridgeUuid);
+ if (oldControllers == null) {
+ log.warn("There are no controllers");
+ return;
+ }
- insertConfig(OvsdbConstant.CONTROLLER, "_uuid",
- OvsdbConstant.BRIDGE, "controller", bridgeUuid,
- controller.getRow());
+ Set<UUID> newControllerUuids = new HashSet<>();
+ Set<ControllerInfo> newControllers = new HashSet<>(controllers);
+ List<Controller> removeControllers = new ArrayList<>();
+ oldControllers.forEach(controller -> {
+ ControllerInfo controllerInfo = new ControllerInfo((String) controller.getTargetColumn().data());
+ if (newControllers.contains(controllerInfo)) {
+ newControllers.remove(controllerInfo);
+ newControllerUuids.add(controller.getRow().uuid());
} else {
+ removeControllers.add(controller);
+ }
+ });
+ OvsdbRowStore controllerRowStore = getRowStore(OvsdbConstant.DATABASENAME,
+ OvsdbConstant.CONTROLLER);
+ if (controllerRowStore == null) {
+ log.debug("There is no controller table");
+ return;
+ }
- Bridge bridge = (Bridge) TableGenerator
- .createTable(dbSchema, OvsdbTable.BRIDGE);
- Set<UUID> controllerUuids = new HashSet<>();
- controllerUuids.add(UUID.uuid(controllerUuid));
- bridge.setController(controllerUuids);
- updateConfig(OvsdbConstant.CONTROLLER, "_uuid", bridgeUuid, bridge.getRow());
+ removeControllers.forEach(c -> deleteConfig(OvsdbConstant.CONTROLLER, "_uuid", c.getRow().uuid().value(),
+ OvsdbConstant.BRIDGE, "controller"));
- }
+ newControllers.stream().map(c -> {
+ Controller controller = (Controller) TableGenerator
+ .createTable(dbSchema, OvsdbTable.CONTROLLER);
+ controller.setTarget(c.target());
+ return controller;
+ }).forEach(c -> {
+ String uuid = insertConfig(OvsdbConstant.CONTROLLER, "_uuid",
+ OvsdbConstant.BRIDGE, "controller", bridgeUuid.value(),
+ c.getRow());
+ newControllerUuids.add(UUID.uuid(uuid));
+
+ });
+
+ OvsdbRowStore rowStore = getRowStore(OvsdbConstant.DATABASENAME,
+ OvsdbConstant.BRIDGE);
+ if (rowStore == null) {
+ log.debug("There is no bridge table");
+ return;
}
+ Row bridgeRow = rowStore.getRow(bridgeUuid.value());
+ Bridge bridge = (Bridge) TableGenerator.getTable(dbSchema, bridgeRow, OvsdbTable.BRIDGE);
+ bridge.setController(OvsdbSet.ovsdbSet(newControllerUuids));
+ updateConfig(OvsdbConstant.BRIDGE, "_uuid", bridgeUuid.value(), bridge.getRow());
+ }
+
+ @Override
+ public void setControllersWithDeviceId(DeviceId deviceId, List<ControllerInfo> controllers) {
+ setControllersWithUUID(getBridgeUUID(deviceId), controllers);
}
@Override
@@ -530,7 +573,7 @@ public class DefaultOvsdbClient
return;
}
deleteConfig(OvsdbConstant.BRIDGE, "_uuid", bridgeUUID,
- OvsdbConstant.DATABASENAME, "bridges");
+ OvsdbConstant.DATABASENAME, "bridges");
}
@Override
@@ -554,7 +597,7 @@ public class DefaultOvsdbClient
if (portUuid == null) {
portUuid = insertConfig(OvsdbConstant.PORT, "_uuid", OvsdbConstant.BRIDGE,
- "ports", bridgeUuid, port.getRow());
+ "ports", bridgeUuid, port.getRow());
} else {
updateConfig(OvsdbConstant.PORT, "_uuid", portUuid, port.getRow());
}
@@ -595,7 +638,7 @@ public class DefaultOvsdbClient
options.put("remote_ip", dstIp.toString());
tunInterface.setOptions(options);
updateConfig(OvsdbConstant.INTERFACE, "_uuid", interfaceUuid,
- tunInterface.getRow());
+ tunInterface.getRow());
log.info("Tunnel added success", tunInterface);
}
@@ -619,7 +662,7 @@ public class DefaultOvsdbClient
if (portUUID != null) {
log.info("Delete tunnel");
deleteConfig(OvsdbConstant.PORT, "_uuid", portUUID,
- OvsdbConstant.BRIDGE, "ports");
+ OvsdbConstant.BRIDGE, "ports");
}
return;
@@ -628,16 +671,15 @@ public class DefaultOvsdbClient
/**
* Delete transact config.
*
- * @param childTableName child table name
- * @param childColumnName child column name
- * @param childUuid child row uuid
- * @param parentTableName parent table name
+ * @param childTableName child table name
+ * @param childColumnName child column name
+ * @param childUuid child row uuid
+ * @param parentTableName parent table name
* @param parentColumnName parent column
- *
*/
private void deleteConfig(String childTableName, String childColumnName,
- String childUuid, String parentTableName,
- String parentColumnName) {
+ String childUuid, String parentTableName,
+ String parentColumnName) {
DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
TableSchema childTableSchema = dbSchema.getTableSchema(childTableName);
@@ -672,14 +714,13 @@ public class DefaultOvsdbClient
/**
* Update transact config.
*
- * @param tableName table name
+ * @param tableName table name
* @param columnName column name
- * @param uuid uuid
- * @param row the config data
- *
+ * @param uuid uuid
+ * @param row the config data
*/
private void updateConfig(String tableName, String columnName, String uuid,
- Row row) {
+ Row row) {
DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
TableSchema tableSchema = dbSchema.getTableSchema(tableName);
@@ -698,18 +739,17 @@ public class DefaultOvsdbClient
/**
* Insert transact config.
*
- * @param childTableName child table name
- * @param childColumnName child column name
- * @param parentTableName parent table name
+ * @param childTableName child table name
+ * @param childColumnName child column name
+ * @param parentTableName parent table name
* @param parentColumnName parent column
- * @param parentUuid parent uuid
- * @param row the config data
- *
+ * @param parentUuid parent uuid
+ * @param row the config data
* @return uuid, empty if no uuid is find
*/
private String insertConfig(String childTableName, String childColumnName,
- String parentTableName, String parentColumnName,
- String parentUuid, Row row) {
+ String parentTableName, String parentColumnName,
+ String parentUuid, Row row) {
DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
TableSchema tableSchema = dbSchema.getTableSchema(childTableName);
@@ -741,7 +781,7 @@ public class DefaultOvsdbClient
if (childTableName.equalsIgnoreCase(OvsdbConstant.PORT)) {
log.info("Handle port insert");
Insert intfInsert = handlePortInsertTable(OvsdbConstant.INTERFACE,
- row);
+ row);
if (intfInsert != null) {
operations.add(intfInsert);
@@ -772,8 +812,7 @@ public class DefaultOvsdbClient
* Handles port insert.
*
* @param tableName ovsdb table interface
- * @param portRow row of port
- *
+ * @param portRow row of port
* @return insert, empty if null
*/
private Insert handlePortInsertTable(String tableName, Row portRow) {
@@ -801,8 +840,7 @@ public class DefaultOvsdbClient
* Gets tunnel name.
*
* @param tunnelType
- * @param dstIp the remote ip address
- *
+ * @param dstIp the remote ip address
* @return tunnel name
*/
private String getTunnelName(String tunnelType, IpAddress dstIp) {
@@ -821,7 +859,7 @@ public class DefaultOvsdbClient
Function<JsonNode, DatabaseSchema> rowFunction = new Function<JsonNode, DatabaseSchema>() {
@Override
public DatabaseSchema apply(JsonNode input) {
- log.info("Get ovsdb database schema", dbName);
+ log.info("Get ovsdb database schema {}", dbName);
DatabaseSchema dbSchema = FromJsonUtil
.jsonNodeToDbSchema(dbName, input);
if (dbSchema == null) {
@@ -877,21 +915,17 @@ public class DefaultOvsdbClient
}
DatabaseSchema dbSchema = schema.get(dbName);
if (dbSchema != null) {
- Function<List<JsonNode>, List<OperationResult>> rowFunction =
- new Function<List<JsonNode>, List<OperationResult>>() {
- @Override
- public List<OperationResult> apply(List<JsonNode> input) {
- log.info("Get ovsdb operation result");
- List<OperationResult> result = FromJsonUtil
- .jsonNodeToOperationResult(input, operations);
-
- if (result == null) {
- log.debug("The operation result is null");
- return null;
- }
- return result;
+ Function<List<JsonNode>, List<OperationResult>> rowFunction = (input -> {
+ log.info("Get ovsdb operation result");
+ List<OperationResult> result = FromJsonUtil
+ .jsonNodeToOperationResult(input, operations);
+
+ if (result == null) {
+ log.debug("The operation result is null");
+ return null;
}
- };
+ return result;
+ });
return Futures.transform(transact(dbSchema, operations),
rowFunction);
}
@@ -972,7 +1006,7 @@ public class DefaultOvsdbClient
}
- @SuppressWarnings({ "rawtypes", "unchecked" })
+ @SuppressWarnings({"rawtypes", "unchecked"})
@Override
public void processResult(JsonNode response) {
log.debug("Handle result");
@@ -1042,6 +1076,105 @@ public class DefaultOvsdbClient
}
@Override
+ public Set<ControllerInfo> getControllers(DeviceId openflowDeviceId) {
+ UUID bridgeUuid = getBridgeUUID(openflowDeviceId);
+ if (bridgeUuid == null) {
+ log.warn("bad bridge Uuid");
+ return null;
+ }
+ List<Controller> controllers = getControllers(bridgeUuid);
+ if (controllers == null) {
+ log.warn("bad list of controllers");
+ return null;
+ }
+ return controllers.stream().
+ map(controller -> new ControllerInfo(
+ (String) controller.getTargetColumn()
+ .data())).collect(Collectors.toSet());
+ }
+
+ private List<Controller> getControllers(UUID bridgeUuid) {
+ DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
+ if (dbSchema == null) {
+ return null;
+ }
+ OvsdbRowStore rowStore = getRowStore(OvsdbConstant.DATABASENAME,
+ OvsdbConstant.BRIDGE);
+ if (rowStore == null) {
+ log.debug("There is no bridge table");
+ return null;
+ }
+
+ Row bridgeRow = rowStore.getRow(bridgeUuid.value());
+ Bridge bridge = (Bridge) TableGenerator.
+ getTable(dbSchema, bridgeRow, OvsdbTable.BRIDGE);
+
+ //FIXME remove log
+ log.warn("type of controller column", bridge.getControllerColumn()
+ .data().getClass());
+ Set<UUID> controllerUuids = (Set<UUID>) ((OvsdbSet) bridge
+ .getControllerColumn().data()).set();
+// Set<String> controllerUuidStrings = (Set<String>) bridge.getControllerColumn().data();
+
+ OvsdbRowStore controllerRowStore = getRowStore(OvsdbConstant.DATABASENAME,
+ OvsdbConstant.CONTROLLER);
+ if (controllerRowStore == null) {
+ log.debug("There is no controller table");
+ return null;
+ }
+
+ List<Controller> ovsdbControllers = new ArrayList<>();
+ ConcurrentMap<String, Row> controllerTableRows = controllerRowStore.getRowStore();
+ controllerTableRows.forEach((key, row) -> {
+ if (!controllerUuids.contains(UUID.uuid(key))) {
+ return;
+ }
+ Controller controller = (Controller) TableGenerator
+ .getTable(dbSchema, row, OvsdbTable.CONTROLLER);
+ ovsdbControllers.add(controller);
+ });
+ return ovsdbControllers;
+ }
+
+
+ private UUID getBridgeUUID(DeviceId openflowDeviceId) {
+ DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
+ if (dbSchema == null) {
+ return null;
+ }
+ OvsdbRowStore rowStore = getRowStore(OvsdbConstant.DATABASENAME,
+ OvsdbConstant.BRIDGE);
+ if (rowStore == null) {
+ log.debug("There is no bridge table");
+ return null;
+ }
+
+ ConcurrentMap<String, Row> bridgeTableRows = rowStore.getRowStore();
+ final AtomicReference<UUID> uuid = new AtomicReference<>();
+ for (Map.Entry<String, Row> entry : bridgeTableRows.entrySet()) {
+ Bridge b = (Bridge) TableGenerator.getTable(dbSchema,
+ entry.getValue(),
+ OvsdbTable.BRIDGE);
+ if (matchesDpid(b, openflowDeviceId)) {
+ uuid.set(UUID.uuid(entry.getKey()));
+ break;
+ }
+ }
+ if (uuid.get() == null) {
+ log.debug("There is no bridge for {}", openflowDeviceId);
+ }
+ return uuid.get();
+
+ }
+
+ private static boolean matchesDpid(Bridge b, DeviceId deviceId) {
+ String ofDpid = deviceId.toString().replace("of:", "");
+ Set ofDeviceIds = ((OvsdbSet) b.getDatapathIdColumn().data()).set();
+ //TODO Set<String>
+ return ofDeviceIds.contains(ofDpid);
+ }
+
+ @Override
public Set<OvsdbPort> getPorts() {
Set<OvsdbPort> ovsdbPorts = new HashSet<OvsdbPort>();
OvsdbTableStore tableStore = getTableStore(OvsdbConstant.DATABASENAME);
@@ -1185,4 +1318,10 @@ public class DefaultOvsdbClient
}
return ifaceid;
}
+
+ @Override
+ public void disconnect() {
+ channel.disconnect();
+ this.agent.removeConnectedNode(nodeId);
+ }
}
diff --git a/framework/src/onos/ovsdb/api/src/test/java/org/onosproject/ovsdb/controller/driver/OvsdbClientServiceAdapter.java b/framework/src/onos/ovsdb/api/src/test/java/org/onosproject/ovsdb/controller/driver/OvsdbClientServiceAdapter.java
new file mode 100644
index 00000000..71fee4fe
--- /dev/null
+++ b/framework/src/onos/ovsdb/api/src/test/java/org/onosproject/ovsdb/controller/driver/OvsdbClientServiceAdapter.java
@@ -0,0 +1,208 @@
+/*
+ * 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.ovsdb.controller.driver;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.util.concurrent.ListenableFuture;
+import org.onlab.packet.IpAddress;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.behaviour.ControllerInfo;
+import org.onosproject.ovsdb.controller.OvsdbBridge;
+import org.onosproject.ovsdb.controller.OvsdbClientService;
+import org.onosproject.ovsdb.controller.OvsdbNodeId;
+import org.onosproject.ovsdb.controller.OvsdbPort;
+import org.onosproject.ovsdb.controller.OvsdbTunnel;
+import org.onosproject.ovsdb.rfc.message.OperationResult;
+import org.onosproject.ovsdb.rfc.message.TableUpdates;
+import org.onosproject.ovsdb.rfc.notation.Row;
+import org.onosproject.ovsdb.rfc.notation.UUID;
+import org.onosproject.ovsdb.rfc.operations.Operation;
+import org.onosproject.ovsdb.rfc.schema.DatabaseSchema;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Test Adapter for OvsdbClientService.
+ */
+public class OvsdbClientServiceAdapter implements OvsdbClientService {
+
+ @Override
+ public OvsdbNodeId nodeId() {
+ return null;
+ }
+
+ @Override
+ public void createTunnel(IpAddress srcIp, IpAddress dstIp) {
+
+ }
+
+ @Override
+ public void dropTunnel(IpAddress srcIp, IpAddress dstIp) {
+
+ }
+
+ @Override
+ public Set<OvsdbTunnel> getTunnels() {
+ return null;
+ }
+
+ @Override
+ public void createBridge(String bridgeName) {
+
+ }
+
+ @Override
+ public void dropBridge(String bridgeName) {
+
+ }
+
+ @Override
+ public Set<OvsdbBridge> getBridges() {
+ return null;
+ }
+
+ @Override
+ public Set<ControllerInfo> getControllers(DeviceId openflowDeviceId) {
+ return null;
+ }
+
+ @Override
+ public void setControllersWithUUID(UUID bridgeUuid, List<ControllerInfo> controllers) {
+
+ }
+
+ @Override
+ public void setControllersWithDeviceId(DeviceId deviceId, List<ControllerInfo> controllers) {
+
+ }
+
+ @Override
+ public void createPort(String bridgeName, String portName) {
+
+ }
+
+ @Override
+ public void dropPort(String bridgeName, String portName) {
+
+ }
+
+ @Override
+ public Set<OvsdbPort> getPorts() {
+ return null;
+ }
+
+ @Override
+ public boolean isConnected() {
+ return false;
+ }
+
+ @Override
+ public String getBridgeUuid(String bridgeName) {
+ return null;
+ }
+
+ @Override
+ public String getPortUuid(String portName, String bridgeUuid) {
+ return null;
+ }
+
+ @Override
+ public String getInterfaceUuid(String portUuid, String portName) {
+ return null;
+ }
+
+ @Override
+ public String getControllerUuid(String controllerName, String controllerTarget) {
+ return null;
+ }
+
+ @Override
+ public String getOvsUuid(String dbName) {
+ return null;
+ }
+
+ @Override
+ public ListenableFuture<DatabaseSchema> getOvsdbSchema(String dbName) {
+ return null;
+ }
+
+ @Override
+ public ListenableFuture<TableUpdates> monitorTables(String dbName, String id) {
+ return null;
+ }
+
+ @Override
+ public ListenableFuture<List<OperationResult>> transactConfig(String dbName, List<Operation> operations) {
+ return null;
+ }
+
+ @Override
+ public DatabaseSchema getDatabaseSchema(String dbName) {
+ return null;
+ }
+
+ @Override
+ public Row getRow(String dbName, String tableName, String uuid) {
+ return null;
+ }
+
+ @Override
+ public void removeRow(String dbName, String tableName, String uuid) {
+
+ }
+
+ @Override
+ public void updateOvsdbStore(String dbName, String tableName, String uuid, Row row) {
+
+ }
+
+ @Override
+ public Set<OvsdbPort> getLocalPorts(Iterable<String> ifaceids) {
+ return null;
+ }
+
+ @Override
+ public void disconnect() {
+
+ }
+
+ @Override
+ public ListenableFuture<JsonNode> getSchema(List<String> dbnames) {
+ return null;
+ }
+
+ @Override
+ public ListenableFuture<List<String>> echo() {
+ return null;
+ }
+
+ @Override
+ public ListenableFuture<JsonNode> monitor(DatabaseSchema dbSchema, String monitorId) {
+ return null;
+ }
+
+ @Override
+ public ListenableFuture<List<String>> listDbs() {
+ return null;
+ }
+
+ @Override
+ public ListenableFuture<List<JsonNode>> transact(DatabaseSchema dbSchema, List<Operation> operations) {
+ return null;
+ }
+}
diff --git a/framework/src/onos/ovsdb/api/src/test/java/org/onosproject/ovsdb/controller/driver/OvsdbControllerAdapter.java b/framework/src/onos/ovsdb/api/src/test/java/org/onosproject/ovsdb/controller/driver/OvsdbControllerAdapter.java
new file mode 100644
index 00000000..902113aa
--- /dev/null
+++ b/framework/src/onos/ovsdb/api/src/test/java/org/onosproject/ovsdb/controller/driver/OvsdbControllerAdapter.java
@@ -0,0 +1,75 @@
+/*
+ * 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.ovsdb.controller.driver;
+
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.TpPort;
+import org.onosproject.ovsdb.controller.OvsdbClientService;
+import org.onosproject.ovsdb.controller.OvsdbController;
+import org.onosproject.ovsdb.controller.OvsdbEventListener;
+import org.onosproject.ovsdb.controller.OvsdbNodeId;
+import org.onosproject.ovsdb.controller.OvsdbNodeListener;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Test Adapter for OvsdbController.
+ */
+public class OvsdbControllerAdapter implements OvsdbController {
+ protected ConcurrentHashMap<OvsdbNodeId, OvsdbClientServiceAdapter> ovsdbClients =
+ new ConcurrentHashMap<OvsdbNodeId, OvsdbClientServiceAdapter>();
+
+ @Override
+ public void addNodeListener(OvsdbNodeListener listener) {
+
+ }
+
+ @Override
+ public void removeNodeListener(OvsdbNodeListener listener) {
+
+ }
+
+ @Override
+ public void addOvsdbEventListener(OvsdbEventListener listener) {
+
+ }
+
+ @Override
+ public void removeOvsdbEventListener(OvsdbEventListener listener) {
+
+ }
+
+ @Override
+ public List<OvsdbNodeId> getNodeIds() {
+ long port = 6653;
+ return new ArrayList<OvsdbNodeId>(Arrays.asList(
+ new OvsdbNodeId(IpAddress.valueOf("127.0.0.1"), port)));
+ }
+
+ @Override
+ public OvsdbClientService getOvsdbClient(OvsdbNodeId nodeId) {
+ return ovsdbClients.get(nodeId);
+ }
+
+ @Override
+ public void connect(IpAddress ip, TpPort port) {
+
+ }
+}
diff --git a/framework/src/onos/ovsdb/ctl/src/main/java/org/onosproject/ovsdb/controller/impl/Controller.java b/framework/src/onos/ovsdb/ctl/src/main/java/org/onosproject/ovsdb/controller/impl/Controller.java
index 07582327..2e84a16a 100644
--- a/framework/src/onos/ovsdb/ctl/src/main/java/org/onosproject/ovsdb/controller/impl/Controller.java
+++ b/framework/src/onos/ovsdb/ctl/src/main/java/org/onosproject/ovsdb/controller/impl/Controller.java
@@ -15,25 +15,38 @@
*/
package org.onosproject.ovsdb.controller.impl;
+import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.Channel;
+import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelFutureListener;
+import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
+import io.netty.channel.ChannelPipeline;
+import io.netty.channel.EventLoop;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.ServerChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
+import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringEncoder;
+import io.netty.handler.timeout.IdleState;
+import io.netty.handler.timeout.IdleStateEvent;
+import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.CharsetUtil;
import java.net.InetSocketAddress;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
import org.onlab.packet.IpAddress;
+import org.onlab.packet.TpPort;
import org.onosproject.ovsdb.controller.OvsdbConstant;
import org.onosproject.ovsdb.controller.OvsdbNodeId;
import org.onosproject.ovsdb.controller.driver.DefaultOvsdbClient;
@@ -63,6 +76,9 @@ public class Controller {
private EventLoopGroup workerGroup;
private Class<? extends ServerChannel> serverChannelClass;
+ private static final int MAX_RETRY = 5;
+ private static final int IDLE_TIMEOUT_SEC = 10;
+
/**
* Initialization.
*/
@@ -198,4 +214,86 @@ public class Controller {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
+
+ /**
+ * Connect to the ovsdb server with given ip address and port number.
+ *
+ * @param ip ip address
+ * @param port port number
+ */
+ public void connect(IpAddress ip, TpPort port) {
+ ChannelFutureListener listener = new ConnectionListener(this, ip, port);
+ connectRetry(ip, port, listener);
+ }
+
+ private void connectRetry(IpAddress ip, TpPort port, ChannelFutureListener listener) {
+ try {
+ Bootstrap b = new Bootstrap();
+ b.group(workerGroup)
+ .channel(NioSocketChannel.class)
+ .option(ChannelOption.TCP_NODELAY, true)
+ .handler(new ChannelInitializer<SocketChannel>() {
+
+ @Override
+ protected void initChannel(SocketChannel channel) throws Exception {
+ ChannelPipeline p = channel.pipeline();
+ p.addLast(new MessageDecoder(),
+ new StringEncoder(CharsetUtil.UTF_8),
+ new IdleStateHandler(IDLE_TIMEOUT_SEC, 0, 0),
+ new ConnectionHandler());
+ }
+ });
+ b.remoteAddress(ip.toString(), port.toInt());
+ b.connect().addListener(listener);
+ } catch (Exception e) {
+ log.warn("Connection to the ovsdb server {}:{} failed", ip.toString(), port.toString());
+ }
+ }
+
+ private class ConnectionListener implements ChannelFutureListener {
+ private Controller controller;
+ private IpAddress ip;
+ private TpPort port;
+ private AtomicInteger count = new AtomicInteger();
+
+ public ConnectionListener(Controller controller,
+ IpAddress ip,
+ TpPort port) {
+ this.controller = controller;
+ this.ip = ip;
+ this.port = port;
+ }
+
+ @Override
+ public void operationComplete(ChannelFuture channelFuture) throws Exception {
+ if (!channelFuture.isSuccess()) {
+ channelFuture.channel().close();
+
+ if (count.incrementAndGet() < MAX_RETRY) {
+ final EventLoop loop = channelFuture.channel().eventLoop();
+
+ loop.schedule(() -> {
+ controller.connectRetry(this.ip, this.port, this);
+ }, 1L, TimeUnit.SECONDS);
+ } else {
+ log.info("Connection to the ovsdb {}:{} failed",
+ this.ip.toString(), this.port.toString());
+ }
+ } else {
+ handleNewNodeConnection(channelFuture.channel());
+ }
+ }
+ }
+
+ private class ConnectionHandler extends ChannelDuplexHandler {
+
+ @Override
+ public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
+ IdleStateEvent e = (IdleStateEvent) evt;
+
+ if (e.state() == IdleState.READER_IDLE) {
+ ctx.close();
+ }
+ }
+ }
}
diff --git a/framework/src/onos/ovsdb/ctl/src/main/java/org/onosproject/ovsdb/controller/impl/OvsdbControllerImpl.java b/framework/src/onos/ovsdb/ctl/src/main/java/org/onosproject/ovsdb/controller/impl/OvsdbControllerImpl.java
index 9b482968..c2cbbf8b 100644
--- a/framework/src/onos/ovsdb/ctl/src/main/java/org/onosproject/ovsdb/controller/impl/OvsdbControllerImpl.java
+++ b/framework/src/onos/ovsdb/ctl/src/main/java/org/onosproject/ovsdb/controller/impl/OvsdbControllerImpl.java
@@ -15,24 +15,15 @@
*/
package org.onosproject.ovsdb.controller.impl;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.math.BigInteger;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CopyOnWriteArraySet;
-import java.util.concurrent.ExecutionException;
-
+import com.fasterxml.jackson.databind.JsonNode;
+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;
import org.apache.felix.scr.annotations.Service;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
+import org.onlab.packet.TpPort;
import org.onosproject.ovsdb.controller.DefaultEventSubject;
import org.onosproject.ovsdb.controller.EventSubject;
import org.onosproject.ovsdb.controller.OvsdbClientService;
@@ -67,7 +58,17 @@ import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.fasterxml.jackson.databind.JsonNode;
+import java.math.BigInteger;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.ExecutionException;
+
+import static com.google.common.base.Preconditions.checkNotNull;
/**
* The implementation of OvsdbController.
@@ -133,8 +134,7 @@ public class OvsdbControllerImpl implements OvsdbController {
@Override
public List<OvsdbNodeId> getNodeIds() {
- // TODO Auto-generated method stub
- return null;
+ return ImmutableList.copyOf(ovsdbClients.keySet());
}
@Override
@@ -142,6 +142,11 @@ public class OvsdbControllerImpl implements OvsdbController {
return ovsdbClients.get(nodeId);
}
+ @Override
+ public void connect(IpAddress ip, TpPort port) {
+ controller.connect(ip, port);
+ }
+
/**
* Implementation of an Ovsdb Agent which is responsible for keeping track
* of connected node and the state in which they are.
@@ -204,8 +209,8 @@ public class OvsdbControllerImpl implements OvsdbController {
* Processes table updates.
*
* @param clientService OvsdbClientService instance
- * @param updates TableUpdates instance
- * @param dbName ovsdb database name
+ * @param updates TableUpdates instance
+ * @param dbName ovsdb database name
*/
private void processTableUpdates(OvsdbClientService clientService,
TableUpdates updates, String dbName)
@@ -236,8 +241,8 @@ public class OvsdbControllerImpl implements OvsdbController {
Row row = clientService.getRow(OvsdbConstant.DATABASENAME, tableName, uuid.value());
dispatchInterfaceEvent(clientService,
row,
- OvsdbEvent.Type.PORT_REMOVED,
- dbSchema);
+ OvsdbEvent.Type.PORT_REMOVED,
+ dbSchema);
}
clientService.removeRow(dbName, tableName, uuid.value());
}
@@ -249,10 +254,10 @@ public class OvsdbControllerImpl implements OvsdbController {
* Dispatches event to the north.
*
* @param clientService OvsdbClientService instance
- * @param newRow a new row
- * @param oldRow an old row
- * @param eventType type of event
- * @param dbSchema ovsdb database schema
+ * @param newRow a new row
+ * @param oldRow an old row
+ * @param eventType type of event
+ * @param dbSchema ovsdb database schema
*/
private void dispatchInterfaceEvent(OvsdbClientService clientService,
Row row,
@@ -277,13 +282,13 @@ public class OvsdbControllerImpl implements OvsdbController {
}
EventSubject eventSubject = new DefaultEventSubject(MacAddress.valueOf(
- macAndIfaceId[0]),
+ macAndIfaceId[0]),
new HashSet<IpAddress>(),
new OvsdbPortName(intf
- .getName()),
+ .getName()),
new OvsdbPortNumber(localPort),
new OvsdbDatapathId(Long
- .toString(dpid)),
+ .toString(dpid)),
new OvsdbPortType(portType),
new OvsdbIfaceId(macAndIfaceId[1]));
for (OvsdbEventListener listener : ovsdbEventListener) {
@@ -309,7 +314,7 @@ public class OvsdbControllerImpl implements OvsdbController {
String attachedMac = externalIds.get(OvsdbConstant.EXTERNAL_ID_VM_MAC);
if (attachedMac == null) {
- log.warn("The attachedMac is null");
+ log.debug("The attachedMac is null"); //FIXME why always null?
return null;
}
String ifaceid = externalIds
@@ -318,7 +323,7 @@ public class OvsdbControllerImpl implements OvsdbController {
log.warn("The ifaceid is null");
return null;
}
- return new String[] {attachedMac, ifaceid};
+ return new String[]{attachedMac, ifaceid};
}
/**
@@ -343,7 +348,7 @@ public class OvsdbControllerImpl implements OvsdbController {
* Gets datapathid from table bridge.
*
* @param clientService OvsdbClientService instance
- * @param dbSchema ovsdb database schema
+ * @param dbSchema ovsdb database schema
* @return datapathid the bridge datapathid
*/
private long getDataPathid(OvsdbClientService clientService,
diff --git a/framework/src/onos/ovsdb/ctl/src/main/java/org/onosproject/ovsdb/controller/impl/OvsdbJsonRpcHandler.java b/framework/src/onos/ovsdb/ctl/src/main/java/org/onosproject/ovsdb/controller/impl/OvsdbJsonRpcHandler.java
index 37942c24..1956a1eb 100644
--- a/framework/src/onos/ovsdb/ctl/src/main/java/org/onosproject/ovsdb/controller/impl/OvsdbJsonRpcHandler.java
+++ b/framework/src/onos/ovsdb/ctl/src/main/java/org/onosproject/ovsdb/controller/impl/OvsdbJsonRpcHandler.java
@@ -89,7 +89,7 @@ public final class OvsdbJsonRpcHandler extends ChannelInboundHandlerAdapter {
*/
private void processOvsdbMessage(JsonNode jsonNode) {
- log.info("Handle ovsdb message");
+ log.debug("Handle ovsdb message");
if (jsonNode.has("result")) {
diff --git a/framework/src/onos/ovsdb/rfc/src/main/java/org/onosproject/ovsdb/rfc/notation/Row.java b/framework/src/onos/ovsdb/rfc/src/main/java/org/onosproject/ovsdb/rfc/notation/Row.java
index 33269223..00609602 100644
--- a/framework/src/onos/ovsdb/rfc/src/main/java/org/onosproject/ovsdb/rfc/notation/Row.java
+++ b/framework/src/onos/ovsdb/rfc/src/main/java/org/onosproject/ovsdb/rfc/notation/Row.java
@@ -15,20 +15,21 @@
*/
package org.onosproject.ovsdb.rfc.notation;
-import static com.google.common.base.MoreObjects.toStringHelper;
-import static com.google.common.base.Preconditions.checkNotNull;
+import com.google.common.collect.Maps;
import java.util.Collection;
import java.util.Map;
import java.util.Objects;
-import com.google.common.collect.Maps;
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
/**
* Row is the basic element of the OpenVswitch's table.
*/
public final class Row {
private String tableName;
+ private UUID uuid;
private Map<String, Column> columns;
/**
@@ -40,9 +41,11 @@ public final class Row {
/**
* Row constructor.
+ *
* @param tableName table name
*/
- public Row(String tableName) {
+ @Deprecated
+ private Row(String tableName) {
checkNotNull(tableName, "tableName cannot be null");
this.tableName = tableName;
this.columns = Maps.newHashMap();
@@ -50,18 +53,22 @@ public final class Row {
/**
* Row constructor.
+ *
* @param tableName table name
- * @param columns Map of Column entity
+ * @param columns Map of Column entity
*/
- public Row(String tableName, Map<String, Column> columns) {
+ public Row(String tableName, UUID uuid, Map<String, Column> columns) {
checkNotNull(tableName, "table name cannot be null");
+ checkNotNull(uuid, "uuid cannot be null");
checkNotNull(columns, "columns cannot be null");
this.tableName = tableName;
+ this.uuid = uuid;
this.columns = columns;
}
/**
* Returns tableName.
+ *
* @return tableName
*/
public String tableName() {
@@ -70,6 +77,7 @@ public final class Row {
/**
* Set tableName value.
+ *
* @param tableName table name
*/
public void setTableName(String tableName) {
@@ -77,7 +85,26 @@ public final class Row {
}
/**
+ * Returns uuid.
+ *
+ * @return uuid
+ */
+ public UUID uuid() {
+ return uuid;
+ }
+
+ /**
+ * Sets uuid value.
+ *
+ * @param uuid new uuid
+ */
+ public void setUuid(UUID uuid) {
+ this.uuid = uuid;
+ }
+
+ /**
* Returns Column by ColumnSchema.
+ *
* @param columnName column name
* @return Column
*/
@@ -87,6 +114,7 @@ public final class Row {
/**
* Returns Collection of Column.
+ *
* @return Collection of Column
*/
public Collection<Column> getColumns() {
@@ -95,8 +123,9 @@ public final class Row {
/**
* add Column.
+ *
* @param columnName column name
- * @param data Column entity
+ * @param data Column entity
*/
public void addColumn(String columnName, Column data) {
this.columns.put(columnName, data);
diff --git a/framework/src/onos/ovsdb/rfc/src/main/java/org/onosproject/ovsdb/rfc/table/Bridge.java b/framework/src/onos/ovsdb/rfc/src/main/java/org/onosproject/ovsdb/rfc/table/Bridge.java
index bd589f03..0b5ffeff 100644
--- a/framework/src/onos/ovsdb/rfc/src/main/java/org/onosproject/ovsdb/rfc/table/Bridge.java
+++ b/framework/src/onos/ovsdb/rfc/src/main/java/org/onosproject/ovsdb/rfc/table/Bridge.java
@@ -15,16 +15,17 @@
*/
package org.onosproject.ovsdb.rfc.table;
-import java.util.Map;
-import java.util.Set;
-
import org.onosproject.ovsdb.rfc.notation.Column;
+import org.onosproject.ovsdb.rfc.notation.OvsdbSet;
import org.onosproject.ovsdb.rfc.notation.Row;
import org.onosproject.ovsdb.rfc.notation.UUID;
import org.onosproject.ovsdb.rfc.schema.DatabaseSchema;
import org.onosproject.ovsdb.rfc.tableservice.AbstractOvsdbTableService;
import org.onosproject.ovsdb.rfc.tableservice.ColumnDescription;
+import java.util.Map;
+import java.util.Set;
+
/**
* This class provides operations of Bridge Table.
*/
@@ -351,7 +352,7 @@ public class Bridge extends AbstractOvsdbTableService {
* of attributes.
* @param controller the column data which column name is "controller"
*/
- public void setController(Set<UUID> controller) {
+ public void setController(OvsdbSet controller) {
ColumnDescription columndesc = new ColumnDescription(
BridgeColumn.CONTROLLER
.columnName(),
diff --git a/framework/src/onos/ovsdb/rfc/src/main/java/org/onosproject/ovsdb/rfc/table/TableGenerator.java b/framework/src/onos/ovsdb/rfc/src/main/java/org/onosproject/ovsdb/rfc/table/TableGenerator.java
index c1ae7c79..f5bd860d 100644
--- a/framework/src/onos/ovsdb/rfc/src/main/java/org/onosproject/ovsdb/rfc/table/TableGenerator.java
+++ b/framework/src/onos/ovsdb/rfc/src/main/java/org/onosproject/ovsdb/rfc/table/TableGenerator.java
@@ -37,6 +37,7 @@ public final class TableGenerator {
* @param tableName table name
* @return Object table entity
*/
+ //FIXME change the name, it creates a row object, such as a controller.
public static Object createTable(DatabaseSchema dbSchema,
OvsdbTable tableName) {
Row row = new Row();
diff --git a/framework/src/onos/ovsdb/rfc/src/main/java/org/onosproject/ovsdb/rfc/utils/FromJsonUtil.java b/framework/src/onos/ovsdb/rfc/src/main/java/org/onosproject/ovsdb/rfc/utils/FromJsonUtil.java
index 9744fb49..1dcf48f3 100644
--- a/framework/src/onos/ovsdb/rfc/src/main/java/org/onosproject/ovsdb/rfc/utils/FromJsonUtil.java
+++ b/framework/src/onos/ovsdb/rfc/src/main/java/org/onosproject/ovsdb/rfc/utils/FromJsonUtil.java
@@ -15,12 +15,11 @@
*/
package org.onosproject.ovsdb.rfc.utils;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
import org.onosproject.ovsdb.rfc.exception.AbnormalJsonNodeException;
import org.onosproject.ovsdb.rfc.exception.UnsupportedException;
import org.onosproject.ovsdb.rfc.jsonrpc.Callback;
@@ -41,11 +40,11 @@ import org.onosproject.ovsdb.rfc.schema.type.ColumnTypeFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
/**
* JsonNode utility class. convert JsonNode into Object.
@@ -247,7 +246,7 @@ public final class FromJsonUtil {
validateJsonNode(rowsNode, "rows");
ArrayList<Row> rows = Lists.newArrayList();
for (JsonNode rowNode : rowsNode.get("rows")) {
- rows.add(createRow(tableSchema, rowNode));
+ rows.add(createRow(tableSchema, null, rowNode)); //FIXME null will throw exception
}
return rows;
}
@@ -285,8 +284,8 @@ public final class FromJsonUtil {
UUID uuid = UUID.uuid(uuidStr);
JsonNode newR = oldNewRow.getValue().get("new");
JsonNode oldR = oldNewRow.getValue().get("old");
- Row newRow = newR != null ? createRow(tableSchema, newR) : null;
- Row oldRow = oldR != null ? createRow(tableSchema, oldR) : null;
+ Row newRow = newR != null ? createRow(tableSchema, uuid, newR) : null;
+ Row oldRow = oldR != null ? createRow(tableSchema, uuid, oldR) : null;
RowUpdate rowUpdate = new RowUpdate(uuid, oldRow, newRow);
rows.put(uuid, rowUpdate);
}
@@ -299,7 +298,7 @@ public final class FromJsonUtil {
* @param rowNode JsonNode
* @return Row
*/
- private static Row createRow(TableSchema tableSchema, JsonNode rowNode) {
+ private static Row createRow(TableSchema tableSchema, UUID uuid, JsonNode rowNode) {
if (tableSchema == null) {
return null;
}
@@ -314,7 +313,7 @@ public final class FromJsonUtil {
columns.put(columnName, new Column(columnName, obj));
}
}
- return new Row(tableSchema.name(), columns);
+ return new Row(tableSchema.name(), uuid, columns);
}
}
diff --git a/framework/src/onos/pcep/pcepio/src/main/java/org/onosproject/pcepio/protocol/ver1/PcepErrorVer1.java b/framework/src/onos/pcep/pcepio/src/main/java/org/onosproject/pcepio/protocol/ver1/PcepErrorVer1.java
index 847211ed..0ea51410 100644
--- a/framework/src/onos/pcep/pcepio/src/main/java/org/onosproject/pcepio/protocol/ver1/PcepErrorVer1.java
+++ b/framework/src/onos/pcep/pcepio/src/main/java/org/onosproject/pcepio/protocol/ver1/PcepErrorVer1.java
@@ -110,8 +110,8 @@ public class PcepErrorVer1 implements PcepError {
/**
* Parse RP List from the channel buffer.
*
- * @throws PcepParseException if mandatory fields are missing
* @param cb of type channel buffer
+ * @throws PcepParseException if mandatory fields are missing
*/
public void parseRPList(ChannelBuffer cb) throws PcepParseException {
byte yObjClass;
diff --git a/framework/src/onos/pom.xml b/framework/src/onos/pom.xml
index 1bce8cdb..93ef2779 100644
--- a/framework/src/onos/pom.xml
+++ b/framework/src/onos/pom.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- ~ Copyright 2014 Open Networking Laboratory
+ ~ 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.
@@ -57,6 +57,7 @@
<module>tools/package/archetypes</module>
<module>tools/package/branding</module>
+ <module>bgp</module>
</modules>
<url>http://onosproject.org/</url>
@@ -77,6 +78,7 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <onos-build-conf.version>1.0</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>
@@ -430,11 +432,27 @@
<scope>test</scope>
</dependency>
<dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-bgpio</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
<version>1.6</version>
</dependency>
<dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-bgp-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-app-bgp-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
<groupId>io.netty</groupId>
<artifactId>netty-common</artifactId>
<version>${netty4.version}</version>
@@ -591,12 +609,12 @@
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
- <version>3.0.0</version>
+ <version>3.0.1</version>
<dependencies>
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onos-build-conf</artifactId>
- <version>1.0</version>
+ <version>${onos-build-conf.version}</version>
</dependency>
</dependencies>
<configuration>
@@ -652,7 +670,7 @@
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onos-build-conf</artifactId>
- <version>1.0</version>
+ <version>${onos-build-conf.version}</version>
</dependency>
<!-- For Java 8 lambda support-->
<dependency>
diff --git a/framework/src/onos/providers/host/src/main/java/org/onosproject/provider/host/impl/HostLocationProvider.java b/framework/src/onos/providers/host/src/main/java/org/onosproject/provider/host/impl/HostLocationProvider.java
index 9a823630..93f6bf8c 100644
--- a/framework/src/onos/providers/host/src/main/java/org/onosproject/provider/host/impl/HostLocationProvider.java
+++ b/framework/src/onos/providers/host/src/main/java/org/onosproject/provider/host/impl/HostLocationProvider.java
@@ -335,15 +335,15 @@ public class HostLocationProvider extends AbstractProvider implements HostProvid
arp.getSenderProtocolAddress());
updateLocationIP(hid, srcMac, vlan, hloc, ip);
- // IPv4: update location only
+ // IPv4: update location only
} else if (eth.getEtherType() == Ethernet.TYPE_IPV4) {
updateLocation(hid, srcMac, vlan, hloc);
- //
- // NeighborAdvertisement and NeighborSolicitation: possible
- // new hosts, update both location and IP.
- //
- // IPv6: update location only
+ //
+ // NeighborAdvertisement and NeighborSolicitation: possible
+ // new hosts, update both location and IP.
+ //
+ // IPv6: update location only
} else if (eth.getEtherType() == Ethernet.TYPE_IPV6) {
IPv6 ipv6 = (IPv6) eth.getPayload();
IpAddress ip = IpAddress.valueOf(IpAddress.Version.INET6,
diff --git a/framework/src/onos/providers/host/src/test/java/org/onosproject/provider/host/impl/HostLocationProviderTest.java b/framework/src/onos/providers/host/src/test/java/org/onosproject/provider/host/impl/HostLocationProviderTest.java
index d010f178..6cbb623b 100644
--- a/framework/src/onos/providers/host/src/test/java/org/onosproject/provider/host/impl/HostLocationProviderTest.java
+++ b/framework/src/onos/providers/host/src/test/java/org/onosproject/provider/host/impl/HostLocationProviderTest.java
@@ -23,9 +23,17 @@ import org.onlab.osgi.ComponentContextAdapter;
import org.onlab.packet.ARP;
import org.onlab.packet.ChassisId;
import org.onlab.packet.Ethernet;
+import org.onlab.packet.ICMP6;
+import org.onlab.packet.IPv4;
+import org.onlab.packet.IPv6;
+import org.onlab.packet.Ip6Address;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
+import org.onlab.packet.ndp.NeighborAdvertisement;
+import org.onlab.packet.ndp.NeighborSolicitation;
+import org.onlab.packet.ndp.RouterAdvertisement;
+import org.onlab.packet.ndp.RouterSolicitation;
import org.onosproject.cfg.ComponentConfigAdapter;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
@@ -66,6 +74,7 @@ import java.util.Hashtable;
import java.util.Set;
import static org.easymock.EasyMock.*;
+import static org.hamcrest.Matchers.is;
import static org.junit.Assert.*;
import static org.onlab.packet.VlanId.vlanId;
import static org.onosproject.net.Device.Type.SWITCH;
@@ -75,27 +84,42 @@ import static org.onosproject.net.PortNumber.portNumber;
import static org.onosproject.net.device.DeviceEvent.Type.*;
public class HostLocationProviderTest {
-
private static final Integer INPORT = 10;
private static final String DEV1 = "of:1";
private static final String DEV2 = "of:2";
private static final String DEV3 = "of:3";
+ private static final String DEV4 = "of:4";
+ private static final String DEV5 = "of:5";
+ private static final String DEV6 = "of:6";
private static final VlanId VLAN = vlanId();
+
+ // IPv4 Host
private static final MacAddress MAC = MacAddress.valueOf("00:00:11:00:00:01");
private static final MacAddress BCMAC = MacAddress.valueOf("ff:ff:ff:ff:ff:ff");
private static final byte[] IP = new byte[]{10, 0, 0, 1};
-
private static final IpAddress IP_ADDRESS =
IpAddress.valueOf(IpAddress.Version.INET, IP);
private static final HostLocation LOCATION =
new HostLocation(deviceId(DEV1), portNumber(INPORT), 0L);
-
private static final DefaultHost HOST =
new DefaultHost(ProviderId.NONE, hostId(MAC), MAC,
vlanId(VlanId.UNTAGGED), LOCATION,
ImmutableSet.of(IP_ADDRESS));
+ // IPv6 Host
+ private static final MacAddress MAC2 = MacAddress.valueOf("00:00:22:00:00:02");
+ private static final MacAddress BCMAC2 = MacAddress.valueOf("33:33:00:00:00:01");
+ private static final byte[] IP2 = Ip6Address.valueOf("1000::1").toOctets();
+ private static final IpAddress IP_ADDRESS2 =
+ IpAddress.valueOf(IpAddress.Version.INET6, IP2);
+ private static final HostLocation LOCATION2 =
+ new HostLocation(deviceId(DEV4), portNumber(INPORT), 0L);
+ private static final DefaultHost HOST2 =
+ new DefaultHost(ProviderId.NONE, hostId(MAC2), MAC2,
+ vlanId(VlanId.UNTAGGED), LOCATION2,
+ ImmutableSet.of(IP_ADDRESS2));
+
private static final ComponentContextAdapter CTX_FOR_REMOVE =
new ComponentContextAdapter() {
@Override
@@ -157,51 +181,189 @@ public class HostLocationProviderTest {
@Test
public void events() {
// new host
- testProcessor.process(new TestPacketContext(DEV1));
+ testProcessor.process(new TestArpPacketContext(DEV1));
+ assertNotNull("new host expected", providerService.added);
+ assertNull("host motion unexpected", providerService.moved);
+
+ // the host moved to new switch
+ testProcessor.process(new TestArpPacketContext(DEV2));
+ assertNotNull("host motion expected", providerService.moved);
+
+ // the host was misheard on a spine
+ testProcessor.process(new TestArpPacketContext(DEV3));
+ assertNull("host misheard on spine switch", providerService.spine);
+
+ providerService.clear();
+
+ // new host
+ testProcessor.process(new TestNAPacketContext(DEV4));
assertNotNull("new host expected", providerService.added);
assertNull("host motion unexpected", providerService.moved);
// the host moved to new switch
- testProcessor.process(new TestPacketContext(DEV2));
+ testProcessor.process(new TestNAPacketContext(DEV5));
assertNotNull("host motion expected", providerService.moved);
// the host was misheard on a spine
- testProcessor.process(new TestPacketContext(DEV3));
+ testProcessor.process(new TestNAPacketContext(DEV6));
assertNull("host misheard on spine switch", providerService.spine);
}
@Test
public void removeHostByDeviceRemove() {
provider.modified(CTX_FOR_REMOVE);
- testProcessor.process(new TestPacketContext(DEV1));
+ testProcessor.process(new TestArpPacketContext(DEV1));
+ testProcessor.process(new TestNAPacketContext(DEV4));
+
Device device = new DefaultDevice(ProviderId.NONE, deviceId(DEV1), SWITCH,
"m", "h", "s", "n", new ChassisId(0L));
deviceService.listener.event(new DeviceEvent(DEVICE_REMOVED, device));
assertEquals("incorrect remove count", 1, providerService.removeCount);
+
+ device = new DefaultDevice(ProviderId.NONE, deviceId(DEV4), SWITCH,
+ "m", "h", "s", "n", new ChassisId(0L));
+ deviceService.listener.event(new DeviceEvent(DEVICE_REMOVED, device));
+ assertEquals("incorrect remove count", 2, providerService.removeCount);
}
@Test
public void removeHostByDeviceOffline() {
provider.modified(CTX_FOR_REMOVE);
- testProcessor.process(new TestPacketContext(DEV1));
+ testProcessor.process(new TestArpPacketContext(DEV1));
+ testProcessor.process(new TestArpPacketContext(DEV4));
+
Device device = new DefaultDevice(ProviderId.NONE, deviceId(DEV1), SWITCH,
"m", "h", "s", "n", new ChassisId(0L));
deviceService.listener.event(new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, device));
assertEquals("incorrect remove count", 1, providerService.removeCount);
+
+ device = new DefaultDevice(ProviderId.NONE, deviceId(DEV4), SWITCH,
+ "m", "h", "s", "n", new ChassisId(0L));
+ deviceService.listener.event(new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, device));
+ assertEquals("incorrect remove count", 2, providerService.removeCount);
}
@Test
public void removeHostByDevicePortDown() {
provider.modified(CTX_FOR_REMOVE);
- testProcessor.process(new TestPacketContext(DEV1));
+ testProcessor.process(new TestArpPacketContext(DEV1));
+ testProcessor.process(new TestArpPacketContext(DEV4));
+
Device device = new DefaultDevice(ProviderId.NONE, deviceId(DEV1), SWITCH,
"m", "h", "s", "n", new ChassisId(0L));
deviceService.listener.event(new DeviceEvent(PORT_UPDATED, device,
- new DefaultPort(device, portNumber(INPORT),
- false)));
+ new DefaultPort(device, portNumber(INPORT), false)));
assertEquals("incorrect remove count", 1, providerService.removeCount);
+
+ device = new DefaultDevice(ProviderId.NONE, deviceId(DEV4), SWITCH,
+ "m", "h", "s", "n", new ChassisId(0L));
+ deviceService.listener.event(new DeviceEvent(PORT_UPDATED, device,
+ new DefaultPort(device, portNumber(INPORT), false)));
+ assertEquals("incorrect remove count", 2, providerService.removeCount);
}
+ /**
+ * When receiving ARP, updates location and IP.
+ */
+ @Test
+ public void testReceiveArp() {
+ testProcessor.process(new TestArpPacketContext(DEV1));
+ HostDescription descr = providerService.added;
+ assertThat(descr.location(), is(LOCATION));
+ assertThat(descr.hwAddress(), is(MAC));
+ assertThat(descr.ipAddress().toArray()[0], is(IP_ADDRESS));
+ assertThat(descr.vlan(), is(VLAN));
+ }
+
+ /**
+ * When receiving IPv4, updates location only.
+ */
+ @Test
+ public void testReceiveIpv4() {
+ testProcessor.process(new TestIpv4PacketContext(DEV1));
+ HostDescription descr = providerService.added;
+ assertThat(descr.location(), is(LOCATION));
+ assertThat(descr.hwAddress(), is(MAC));
+ assertThat(descr.ipAddress().size(), is(0));
+ assertThat(descr.vlan(), is(VLAN));
+ }
+
+ /**
+ * When receiving NeighborAdvertisement, updates location and IP.
+ */
+ @Test
+ public void testReceiveNA() {
+ testProcessor.process(new TestNAPacketContext(DEV4));
+ assertNotNull(providerService.added);
+ HostDescription descr = providerService.added;
+ assertThat(descr.location(), is(LOCATION2));
+ assertThat(descr.hwAddress(), is(MAC2));
+ assertThat(descr.ipAddress().toArray()[0], is(IP_ADDRESS2));
+ assertThat(descr.vlan(), is(VLAN));
+ }
+
+ /**
+ * When receiving NeighborSolicitation, updates location and IP.
+ */
+ @Test
+ public void testReceiveNS() {
+ testProcessor.process(new TestNSPacketContext(DEV4));
+ HostDescription descr = providerService.added;
+ assertThat(descr.location(), is(LOCATION2));
+ assertThat(descr.hwAddress(), is(MAC2));
+ assertThat(descr.ipAddress().toArray()[0], is(IP_ADDRESS2));
+ assertThat(descr.vlan(), is(VLAN));
+ }
+
+ /**
+ * When receiving RouterAdvertisement, ignores it.
+ */
+ @Test
+ public void testReceivesRA() {
+ testProcessor.process(new TestRAPacketContext(DEV4));
+ assertNull(providerService.added);
+ }
+
+ /**
+ * When receiving RouterSolicitation, ignores it.
+ */
+ @Test
+ public void testReceiveRS() {
+ testProcessor.process(new TestRSPacketContext(DEV4));
+ assertNull(providerService.added);
+ }
+
+ /**
+ * When receiving Duplicate Address Detection (DAD), ignores it.
+ */
+ @Test
+ public void testReceiveDAD() {
+ testProcessor.process(new TestDADPacketContext(DEV4));
+ assertNull(providerService.added);
+ }
+
+ /**
+ * When receiving IPv6 multicast packet, ignores it.
+ */
+ @Test
+ public void testReceiveIpv6Multicast() {
+ testProcessor.process(new TestIpv6McastPacketContext(DEV4));
+ assertNull(providerService.added);
+ }
+
+ /**
+ * When receiving IPv6 unicast packet, updates location only.
+ */
+ @Test
+ public void testReceiveIpv6Unicast() {
+ testProcessor.process(new TestIpv6PacketContext(DEV4));
+ assertNotNull(providerService.added);
+ HostDescription descr = providerService.added;
+ assertThat(descr.location(), is(LOCATION2));
+ assertThat(descr.hwAddress(), is(MAC2));
+ assertThat(descr.ipAddress().size(), is(0));
+ assertThat(descr.vlan(), is(VLAN));
+ }
@After
public void tearDown() {
@@ -233,24 +395,30 @@ public class HostLocationProviderTest {
extends AbstractProviderService<HostProvider>
implements HostProviderService {
- DeviceId added = null;
- DeviceId moved = null;
- DeviceId spine = null;
+ HostDescription added = null;
+ HostDescription moved = null;
+ HostDescription spine = null;
public int removeCount;
+ public void clear() {
+ added = null;
+ moved = null;
+ spine = null;
+ removeCount = 0;
+ }
+
protected TestHostProviderService(HostProvider provider) {
super(provider);
}
@Override
public void hostDetected(HostId hostId, HostDescription hostDescription, boolean replaceIps) {
- DeviceId descr = hostDescription.location().deviceId();
if (added == null) {
- added = descr;
- } else if ((moved == null) && !descr.equals(added)) {
- moved = descr;
+ added = hostDescription;
+ } else if ((moved == null) && !hostDescription.equals(added)) {
+ moved = hostDescription;
} else {
- spine = descr;
+ spine = hostDescription;
}
}
@@ -259,6 +427,10 @@ public class HostLocationProviderTest {
removeCount++;
}
+ @Override
+ public void removeIpFromHost(HostId hostId, IpAddress ipAddress) {
+ }
+
}
private class TestPacketService extends PacketServiceAdapter {
@@ -268,24 +440,26 @@ public class HostLocationProviderTest {
}
}
-
private class TestTopologyService extends TopologyServiceAdapter {
@Override
public boolean isInfrastructure(Topology topology,
ConnectPoint connectPoint) {
//simulate DPID3 as an infrastructure switch
- if ((connectPoint.deviceId()).equals(deviceId(DEV3))) {
+ if ((connectPoint.deviceId()).equals(deviceId(DEV3)) ||
+ connectPoint.deviceId().equals(deviceId(DEV6))) {
return true;
}
return false;
}
}
- private class TestPacketContext implements PacketContext {
-
+ /**
+ * Generates ARP packet.
+ */
+ private class TestArpPacketContext implements PacketContext {
private final String deviceId;
- public TestPacketContext(String deviceId) {
+ public TestArpPacketContext(String deviceId) {
this.deviceId = deviceId;
}
@@ -340,6 +514,490 @@ public class HostLocationProviderTest {
}
}
+ /**
+ * Generates IPv6 Unicast packet.
+ */
+ private class TestIpv4PacketContext implements PacketContext {
+ private final String deviceId;
+
+ public TestIpv4PacketContext(String deviceId) {
+ this.deviceId = deviceId;
+ }
+
+ @Override
+ public long time() {
+ return 0;
+ }
+
+ @Override
+ public InboundPacket inPacket() {
+ IPv4 ipv4 = new IPv4();
+ ipv4.setDestinationAddress("10.0.0.1");
+ ipv4.setSourceAddress(IP_ADDRESS.toString());
+ Ethernet eth = new Ethernet();
+ eth.setEtherType(Ethernet.TYPE_IPV4)
+ .setVlanID(VLAN.toShort())
+ .setSourceMACAddress(MAC)
+ .setDestinationMACAddress(MacAddress.valueOf("00:00:00:00:00:01"))
+ .setPayload(ipv4);
+ ConnectPoint receivedFrom = new ConnectPoint(deviceId(deviceId),
+ portNumber(INPORT));
+ return new DefaultInboundPacket(receivedFrom, eth,
+ ByteBuffer.wrap(eth.serialize()));
+ }
+
+ @Override
+ public OutboundPacket outPacket() {
+ return null;
+ }
+
+ @Override
+ public TrafficTreatment.Builder treatmentBuilder() {
+ return null;
+ }
+
+ @Override
+ public void send() {
+
+ }
+
+ @Override
+ public boolean block() {
+ return false;
+ }
+
+ @Override
+ public boolean isHandled() {
+ return false;
+ }
+ }
+
+ /**
+ * Generates NeighborAdvertisement packet.
+ */
+ private class TestNAPacketContext implements PacketContext {
+ private final String deviceId;
+
+ public TestNAPacketContext(String deviceId) {
+ this.deviceId = deviceId;
+ }
+
+ @Override
+ public long time() {
+ return 0;
+ }
+
+ @Override
+ public InboundPacket inPacket() {
+ NeighborAdvertisement na = new NeighborAdvertisement();
+ ICMP6 icmp6 = new ICMP6();
+ icmp6.setPayload(na);
+ IPv6 ipv6 = new IPv6();
+ ipv6.setPayload(icmp6);
+ ipv6.setDestinationAddress(Ip6Address.valueOf("ff02::1").toOctets());
+ ipv6.setSourceAddress(IP2);
+ Ethernet eth = new Ethernet();
+ eth.setEtherType(Ethernet.TYPE_IPV6)
+ .setVlanID(VLAN.toShort())
+ .setSourceMACAddress(MAC2.toBytes())
+ .setDestinationMACAddress(BCMAC2)
+ .setPayload(ipv6);
+ ConnectPoint receivedFrom = new ConnectPoint(deviceId(deviceId),
+ portNumber(INPORT));
+ return new DefaultInboundPacket(receivedFrom, eth,
+ ByteBuffer.wrap(eth.serialize()));
+ }
+
+ @Override
+ public OutboundPacket outPacket() {
+ return null;
+ }
+
+ @Override
+ public TrafficTreatment.Builder treatmentBuilder() {
+ return null;
+ }
+
+ @Override
+ public void send() {
+
+ }
+
+ @Override
+ public boolean block() {
+ return false;
+ }
+
+ @Override
+ public boolean isHandled() {
+ return false;
+ }
+ }
+
+ /**
+ * Generates NeighborSolicitation packet.
+ */
+ private class TestNSPacketContext implements PacketContext {
+ private final String deviceId;
+
+ public TestNSPacketContext(String deviceId) {
+ this.deviceId = deviceId;
+ }
+
+ @Override
+ public long time() {
+ return 0;
+ }
+
+ @Override
+ public InboundPacket inPacket() {
+ NeighborSolicitation ns = new NeighborSolicitation();
+ ICMP6 icmp6 = new ICMP6();
+ icmp6.setPayload(ns);
+ IPv6 ipv6 = new IPv6();
+ ipv6.setPayload(icmp6);
+ ipv6.setDestinationAddress(Ip6Address.valueOf("ff02::1:ff00:0000").toOctets());
+ ipv6.setSourceAddress(IP2);
+ Ethernet eth = new Ethernet();
+ eth.setEtherType(Ethernet.TYPE_IPV6)
+ .setVlanID(VLAN.toShort())
+ .setSourceMACAddress(MAC2.toBytes())
+ .setDestinationMACAddress(BCMAC2)
+ .setPayload(ipv6);
+ ConnectPoint receivedFrom = new ConnectPoint(deviceId(deviceId),
+ portNumber(INPORT));
+ return new DefaultInboundPacket(receivedFrom, eth,
+ ByteBuffer.wrap(eth.serialize()));
+ }
+
+ @Override
+ public OutboundPacket outPacket() {
+ return null;
+ }
+
+ @Override
+ public TrafficTreatment.Builder treatmentBuilder() {
+ return null;
+ }
+
+ @Override
+ public void send() {
+
+ }
+
+ @Override
+ public boolean block() {
+ return false;
+ }
+
+ @Override
+ public boolean isHandled() {
+ return false;
+ }
+ }
+
+ /**
+ * Generates Duplicate Address Detection packet.
+ */
+ private class TestDADPacketContext implements PacketContext {
+ private final String deviceId;
+
+ public TestDADPacketContext(String deviceId) {
+ this.deviceId = deviceId;
+ }
+
+ @Override
+ public long time() {
+ return 0;
+ }
+
+ @Override
+ public InboundPacket inPacket() {
+ NeighborSolicitation ns = new NeighborSolicitation();
+ ICMP6 icmp6 = new ICMP6();
+ icmp6.setPayload(ns);
+ IPv6 ipv6 = new IPv6();
+ ipv6.setPayload(icmp6);
+ ipv6.setDestinationAddress(Ip6Address.valueOf("ff02::1").toOctets());
+ ipv6.setSourceAddress(Ip6Address.valueOf("::").toOctets());
+ Ethernet eth = new Ethernet();
+ eth.setEtherType(Ethernet.TYPE_IPV6)
+ .setVlanID(VLAN.toShort())
+ .setSourceMACAddress(MAC2.toBytes())
+ .setDestinationMACAddress(BCMAC2)
+ .setPayload(ipv6);
+ ConnectPoint receivedFrom = new ConnectPoint(deviceId(deviceId),
+ portNumber(INPORT));
+ return new DefaultInboundPacket(receivedFrom, eth,
+ ByteBuffer.wrap(eth.serialize()));
+ }
+
+ @Override
+ public OutboundPacket outPacket() {
+ return null;
+ }
+
+ @Override
+ public TrafficTreatment.Builder treatmentBuilder() {
+ return null;
+ }
+
+ @Override
+ public void send() {
+
+ }
+
+ @Override
+ public boolean block() {
+ return false;
+ }
+
+ @Override
+ public boolean isHandled() {
+ return false;
+ }
+ }
+
+ /**
+ * Generates Router Solicitation packet.
+ */
+ private class TestRSPacketContext implements PacketContext {
+ private final String deviceId;
+
+ public TestRSPacketContext(String deviceId) {
+ this.deviceId = deviceId;
+ }
+
+ @Override
+ public long time() {
+ return 0;
+ }
+
+ @Override
+ public InboundPacket inPacket() {
+ RouterSolicitation ns = new RouterSolicitation();
+ ICMP6 icmp6 = new ICMP6();
+ icmp6.setPayload(ns);
+ IPv6 ipv6 = new IPv6();
+ ipv6.setPayload(icmp6);
+ ipv6.setDestinationAddress(Ip6Address.valueOf("ff02::2").toOctets());
+ ipv6.setSourceAddress(Ip6Address.valueOf("::").toOctets());
+ Ethernet eth = new Ethernet();
+ eth.setEtherType(Ethernet.TYPE_IPV6)
+ .setVlanID(VLAN.toShort())
+ .setSourceMACAddress(MAC2.toBytes())
+ .setDestinationMACAddress(MacAddress.valueOf("33:33:00:00:00:02"))
+ .setPayload(ipv6);
+ ConnectPoint receivedFrom = new ConnectPoint(deviceId(deviceId),
+ portNumber(INPORT));
+ return new DefaultInboundPacket(receivedFrom, eth,
+ ByteBuffer.wrap(eth.serialize()));
+ }
+
+ @Override
+ public OutboundPacket outPacket() {
+ return null;
+ }
+
+ @Override
+ public TrafficTreatment.Builder treatmentBuilder() {
+ return null;
+ }
+
+ @Override
+ public void send() {
+
+ }
+
+ @Override
+ public boolean block() {
+ return false;
+ }
+
+ @Override
+ public boolean isHandled() {
+ return false;
+ }
+ }
+
+ /**
+ * Generates Router Advertisement packet.
+ */
+ private class TestRAPacketContext implements PacketContext {
+ private final String deviceId;
+
+ public TestRAPacketContext(String deviceId) {
+ this.deviceId = deviceId;
+ }
+
+ @Override
+ public long time() {
+ return 0;
+ }
+
+ @Override
+ public InboundPacket inPacket() {
+ RouterAdvertisement ns = new RouterAdvertisement();
+ ICMP6 icmp6 = new ICMP6();
+ icmp6.setPayload(ns);
+ IPv6 ipv6 = new IPv6();
+ ipv6.setPayload(icmp6);
+ ipv6.setDestinationAddress(Ip6Address.valueOf("ff02::1").toOctets());
+ ipv6.setSourceAddress(IP2);
+ Ethernet eth = new Ethernet();
+ eth.setEtherType(Ethernet.TYPE_IPV6)
+ .setVlanID(VLAN.toShort())
+ .setSourceMACAddress(MAC2.toBytes())
+ .setDestinationMACAddress(MacAddress.valueOf("33:33:00:00:00:01"))
+ .setPayload(ipv6);
+ ConnectPoint receivedFrom = new ConnectPoint(deviceId(deviceId),
+ portNumber(INPORT));
+ return new DefaultInboundPacket(receivedFrom, eth,
+ ByteBuffer.wrap(eth.serialize()));
+ }
+
+ @Override
+ public OutboundPacket outPacket() {
+ return null;
+ }
+
+ @Override
+ public TrafficTreatment.Builder treatmentBuilder() {
+ return null;
+ }
+
+ @Override
+ public void send() {
+
+ }
+
+ @Override
+ public boolean block() {
+ return false;
+ }
+
+ @Override
+ public boolean isHandled() {
+ return false;
+ }
+ }
+
+ /**
+ * Generates IPv6 Multicast packet.
+ */
+ private class TestIpv6McastPacketContext implements PacketContext {
+ private final String deviceId;
+
+ public TestIpv6McastPacketContext(String deviceId) {
+ this.deviceId = deviceId;
+ }
+
+ @Override
+ public long time() {
+ return 0;
+ }
+
+ @Override
+ public InboundPacket inPacket() {
+ IPv6 ipv6 = new IPv6();
+ ipv6.setDestinationAddress(Ip6Address.valueOf("ff02::1").toOctets());
+ ipv6.setSourceAddress(IP2);
+ Ethernet eth = new Ethernet();
+ eth.setEtherType(Ethernet.TYPE_IPV6)
+ .setVlanID(VLAN.toShort())
+ .setSourceMACAddress(MAC2.toBytes())
+ .setDestinationMACAddress(MacAddress.valueOf("33:33:00:00:00:01"))
+ .setPayload(ipv6);
+ ConnectPoint receivedFrom = new ConnectPoint(deviceId(deviceId),
+ portNumber(INPORT));
+ return new DefaultInboundPacket(receivedFrom, eth,
+ ByteBuffer.wrap(eth.serialize()));
+ }
+
+ @Override
+ public OutboundPacket outPacket() {
+ return null;
+ }
+
+ @Override
+ public TrafficTreatment.Builder treatmentBuilder() {
+ return null;
+ }
+
+ @Override
+ public void send() {
+
+ }
+
+ @Override
+ public boolean block() {
+ return false;
+ }
+
+ @Override
+ public boolean isHandled() {
+ return false;
+ }
+ }
+
+ /**
+ * Generates IPv6 Unicast packet.
+ */
+ private class TestIpv6PacketContext implements PacketContext {
+ private final String deviceId;
+
+ public TestIpv6PacketContext(String deviceId) {
+ this.deviceId = deviceId;
+ }
+
+ @Override
+ public long time() {
+ return 0;
+ }
+
+ @Override
+ public InboundPacket inPacket() {
+ IPv6 ipv6 = new IPv6();
+ ipv6.setDestinationAddress(Ip6Address.valueOf("1000::1").toOctets());
+ ipv6.setSourceAddress(IP2);
+ Ethernet eth = new Ethernet();
+ eth.setEtherType(Ethernet.TYPE_IPV6)
+ .setVlanID(VLAN.toShort())
+ .setSourceMACAddress(MAC2)
+ .setDestinationMACAddress(MacAddress.valueOf("00:00:00:00:00:01"))
+ .setPayload(ipv6);
+ ConnectPoint receivedFrom = new ConnectPoint(deviceId(deviceId),
+ portNumber(INPORT));
+ return new DefaultInboundPacket(receivedFrom, eth,
+ ByteBuffer.wrap(eth.serialize()));
+ }
+
+ @Override
+ public OutboundPacket outPacket() {
+ return null;
+ }
+
+ @Override
+ public TrafficTreatment.Builder treatmentBuilder() {
+ return null;
+ }
+
+ @Override
+ public void send() {
+
+ }
+
+ @Override
+ public boolean block() {
+ return false;
+ }
+
+ @Override
+ public boolean isHandled() {
+ return false;
+ }
+ }
+
private class TestDeviceService extends DeviceServiceAdapter {
private DeviceListener listener;
@@ -357,12 +1015,26 @@ public class HostLocationProviderTest {
private class TestHostService extends HostServiceAdapter {
@Override
public Set<Host> getConnectedHosts(ConnectPoint connectPoint) {
- return ImmutableSet.of(HOST);
+ ConnectPoint cp1 = new ConnectPoint(deviceId(DEV1), portNumber(INPORT));
+ ConnectPoint cp2 = new ConnectPoint(deviceId(DEV4), portNumber(INPORT));
+ if (connectPoint.equals(cp1)) {
+ return ImmutableSet.of(HOST);
+ } else if (connectPoint.equals(cp2)) {
+ return ImmutableSet.of(HOST2);
+ } else {
+ return ImmutableSet.of();
+ }
}
@Override
public Set<Host> getConnectedHosts(DeviceId deviceId) {
- return ImmutableSet.of(HOST);
+ if (deviceId.equals(deviceId(DEV1))) {
+ return ImmutableSet.of(HOST);
+ } else if (deviceId.equals(deviceId(DEV4))) {
+ return ImmutableSet.of(HOST2);
+ } else {
+ return ImmutableSet.of();
+ }
}
}
diff --git a/framework/src/onos/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LLDPLinkProvider.java b/framework/src/onos/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LLDPLinkProvider.java
index 386d838f..a840f856 100644
--- a/framework/src/onos/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LLDPLinkProvider.java
+++ b/framework/src/onos/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LLDPLinkProvider.java
@@ -67,6 +67,8 @@ import java.util.concurrent.ScheduledExecutorService;
import static com.google.common.base.Strings.isNullOrEmpty;
import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.onlab.packet.Ethernet.TYPE_BSN;
+import static org.onlab.packet.Ethernet.TYPE_LLDP;
import static org.onlab.util.Tools.get;
import static org.onlab.util.Tools.groupedThreads;
import static org.onosproject.net.Link.Type.DIRECT;
@@ -326,10 +328,10 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider {
*/
private void requestIntercepts() {
TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
- selector.matchEthType(Ethernet.TYPE_LLDP);
+ selector.matchEthType(TYPE_LLDP);
packetService.requestPackets(selector.build(), PacketPriority.CONTROL, appId);
- selector.matchEthType(Ethernet.TYPE_BSN);
+ selector.matchEthType(TYPE_BSN);
if (useBDDP) {
packetService.requestPackets(selector.build(), PacketPriority.CONTROL, appId);
} else {
@@ -342,9 +344,9 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider {
*/
private void withdrawIntercepts() {
TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
- selector.matchEthType(Ethernet.TYPE_LLDP);
+ selector.matchEthType(TYPE_LLDP);
packetService.cancelPackets(selector.build(), PacketPriority.CONTROL, appId);
- selector.matchEthType(Ethernet.TYPE_BSN);
+ selector.matchEthType(TYPE_BSN);
packetService.cancelPackets(selector.build(), PacketPriority.CONTROL, appId);
}
@@ -394,7 +396,7 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider {
synchronized (discoverers) {
ld = discoverers.get(deviceId);
if (ld == null) {
- if (rules.isSuppressed(device)) {
+ if (rules != null && rules.isSuppressed(device)) {
log.debug("LinkDiscovery from {} disabled by configuration", device.id());
return;
}
@@ -474,9 +476,15 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider {
private class InternalPacketProcessor implements PacketProcessor {
@Override
public void process(PacketContext context) {
- if (context == null) {
+ if (context == null || context.isHandled()) {
return;
}
+
+ Ethernet eth = context.inPacket().parsed();
+ if (eth == null || (eth.getEtherType() != TYPE_LLDP && eth.getEtherType() != TYPE_BSN)) {
+ return;
+ }
+
LinkDiscovery ld = discoverers.get(context.inPacket().receivedFrom().deviceId());
if (ld == null) {
return;
diff --git a/framework/src/onos/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java b/framework/src/onos/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java
index cb19dc52..4fa961f8 100644
--- a/framework/src/onos/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java
+++ b/framework/src/onos/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java
@@ -15,10 +15,24 @@
*/
package org.onosproject.provider.of.device.impl;
-import com.google.common.base.Strings;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Strings.isNullOrEmpty;
+import static org.onlab.util.Tools.get;
+import static org.onosproject.net.DeviceId.deviceId;
+import static org.onosproject.net.Port.Type.COPPER;
+import static org.onosproject.net.Port.Type.FIBER;
+import static org.onosproject.openflow.controller.Dpid.dpid;
+import static org.onosproject.openflow.controller.Dpid.uri;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
@@ -28,15 +42,17 @@ import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onlab.packet.ChassisId;
import org.onlab.util.Frequency;
-import org.onosproject.cfg.ComponentConfigService;
import org.onlab.util.Spectrum;
+import org.onosproject.cfg.ComponentConfigService;
import org.onosproject.net.AnnotationKeys;
import org.onosproject.net.ChannelSpacing;
import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.GridType;
import org.onosproject.net.MastershipRole;
import org.onosproject.net.OchSignal;
+import org.onosproject.net.OduCltPort;
import org.onosproject.net.OduSignalType;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
@@ -49,6 +65,7 @@ import org.onosproject.net.device.DeviceProvider;
import org.onosproject.net.device.DeviceProviderRegistry;
import org.onosproject.net.device.DeviceProviderService;
import org.onosproject.net.device.OchPortDescription;
+import org.onosproject.net.device.OduCltPortDescription;
import org.onosproject.net.device.OmsPortDescription;
import org.onosproject.net.device.PortDescription;
import org.onosproject.net.device.PortStatistics;
@@ -64,13 +81,19 @@ import org.onosproject.openflow.controller.PortDescPropertyType;
import org.onosproject.openflow.controller.RoleState;
import org.osgi.service.component.ComponentContext;
import org.projectfloodlight.openflow.protocol.OFCalientPortDescStatsEntry;
+import org.projectfloodlight.openflow.protocol.OFExpPort;
+import org.projectfloodlight.openflow.protocol.OFExpPortDescPropOpticalTransport;
+import org.projectfloodlight.openflow.protocol.OFExpPortOpticalTransportLayerEntry;
import org.projectfloodlight.openflow.protocol.OFFactory;
import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFObject;
import org.projectfloodlight.openflow.protocol.OFPortConfig;
import org.projectfloodlight.openflow.protocol.OFPortDesc;
import org.projectfloodlight.openflow.protocol.OFPortDescPropOpticalTransport;
import org.projectfloodlight.openflow.protocol.OFPortFeatures;
import org.projectfloodlight.openflow.protocol.OFPortOptical;
+import org.projectfloodlight.openflow.protocol.OFPortOpticalTransportLayerClass;
+import org.projectfloodlight.openflow.protocol.OFPortOpticalTransportSignalType;
import org.projectfloodlight.openflow.protocol.OFPortReason;
import org.projectfloodlight.openflow.protocol.OFPortState;
import org.projectfloodlight.openflow.protocol.OFPortStatsEntry;
@@ -83,23 +106,10 @@ import org.projectfloodlight.openflow.protocol.OFVersion;
import org.projectfloodlight.openflow.types.PortSpeed;
import org.slf4j.Logger;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Dictionary;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Strings.isNullOrEmpty;
-import static org.onlab.util.Tools.get;
-import static org.onosproject.net.DeviceId.deviceId;
-import static org.onosproject.net.Port.Type.COPPER;
-import static org.onosproject.net.Port.Type.FIBER;
-import static org.onosproject.openflow.controller.Dpid.dpid;
-import static org.onosproject.openflow.controller.Dpid.uri;
-import static org.slf4j.LoggerFactory.getLogger;
+import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
/**
* Provider which uses an OpenFlow controller to detect network
@@ -109,7 +119,11 @@ import static org.slf4j.LoggerFactory.getLogger;
public class OpenFlowDeviceProvider extends AbstractProvider implements DeviceProvider {
private static final Logger LOG = getLogger(OpenFlowDeviceProvider.class);
+
private static final long MBPS = 1_000 * 1_000;
+ private static final Frequency FREQ100 = Frequency.ofGHz(100);
+ private static final Frequency FREQ193_1 = Frequency.ofTHz(193.1);
+ private static final Frequency FREQ4_4 = Frequency.ofTHz(4.4);
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DeviceProviderRegistry providerRegistry;
@@ -145,27 +159,16 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr
providerService = providerRegistry.register(this);
controller.addListener(listener);
controller.addEventListener(listener);
- for (OpenFlowSwitch sw : controller.getSwitches()) {
- try {
- listener.switchAdded(new Dpid(sw.getId()));
- } catch (Exception e) {
- LOG.warn("Failed initially adding {} : {}", sw.getStringId(), e.getMessage());
- LOG.debug("Error details:", e);
- // disconnect to trigger switch-add later
- sw.disconnectSwitch();
- }
- PortStatsCollector psc = new PortStatsCollector(sw, portStatsPollFrequency);
- psc.start();
- collectors.put(new Dpid(sw.getId()), psc);
- }
+ connectInitialDevices();
LOG.info("Started");
}
@Deactivate
public void deactivate(ComponentContext context) {
cfgService.unregisterProperties(getClass(), false);
- providerRegistry.unregister(this);
controller.removeListener(listener);
+ disconnectDevices();
+ providerRegistry.unregister(this);
collectors.values().forEach(PortStatsCollector::stop);
providerService = null;
LOG.info("Stopped");
@@ -191,13 +194,31 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr
LOG.info("Settings: portStatsPollFrequency={}", portStatsPollFrequency);
}
+ private void connectInitialDevices() {
+ for (OpenFlowSwitch sw : controller.getSwitches()) {
+ try {
+ listener.switchAdded(new Dpid(sw.getId()));
+ } catch (Exception e) {
+ LOG.warn("Failed initially adding {} : {}", sw.getStringId(), e.getMessage());
+ LOG.debug("Error details:", e);
+ // disconnect to trigger switch-add later
+ sw.disconnectSwitch();
+ }
+ PortStatsCollector psc = new PortStatsCollector(sw, portStatsPollFrequency);
+ psc.start();
+ collectors.put(new Dpid(sw.getId()), psc);
+ }
+ }
+
+ private void disconnectDevices() {
+ // Only disconnect the devices for which we are currently master.
+ controller.getMasterSwitches().forEach(sw -> listener.switchRemoved(new Dpid(sw.getId())));
+ }
+
@Override
public boolean isReachable(DeviceId deviceId) {
OpenFlowSwitch sw = controller.getSwitch(dpid(deviceId.uri()));
- if (sw == null || !sw.isConnected()) {
- return false;
- }
- return true;
+ return sw != null && sw.isConnected();
}
@Override
@@ -302,8 +323,9 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr
ChassisId cId = new ChassisId(dpid.value());
SparseAnnotations annotations = DefaultAnnotations.builder()
- .set("protocol", sw.factory().getVersion().toString())
- .set("channelId", sw.channelId())
+ .set(AnnotationKeys.PROTOCOL, sw.factory().getVersion().toString())
+ .set(AnnotationKeys.CHANNEL_ID, sw.channelId())
+ .set(AnnotationKeys.MANAGEMENT_ADDRESS, sw.channelId().split(":")[0])
.build();
DeviceDescription description =
@@ -386,18 +408,27 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr
*/
private List<PortDescription> buildPortDescriptions(OpenFlowSwitch sw) {
final List<PortDescription> portDescs = new ArrayList<>(sw.getPorts().size());
- sw.getPorts().forEach(port -> portDescs.add(buildPortDescription(port)));
+ if (!(Device.Type.ROADM.equals(sw.deviceType()))) {
+ sw.getPorts().forEach(port -> portDescs.add(buildPortDescription(port)));
+ }
OpenFlowOpticalSwitch opsw;
switch (sw.deviceType()) {
case ROADM:
opsw = (OpenFlowOpticalSwitch) sw;
+ List<OFPortDesc> ports = opsw.getPorts();
+ LOG.debug("SW ID {} , ETH- ODU CLT Ports {}", opsw.getId(), ports);
+ // ODU client ports are reported as ETH
+ ports.forEach(port -> portDescs.add(buildOduCltPortDescription(port)));
+
opsw.getPortTypes().forEach(type -> {
- opsw.getPortsOf(type).forEach(
- op -> {
- portDescs.add(buildPortDescription(type, (OFPortOptical) op));
- }
- );
+ List<? extends OFObject> portsOf = opsw.getPortsOf(type);
+ LOG.debug("Ports Of{}", portsOf);
+ portsOf.forEach(
+ op -> {
+ portDescs.add(buildPortDescription(type, (OFObject) op));
+ }
+ );
});
break;
case FIBER_SWITCH:
@@ -417,6 +448,105 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr
return portDescs;
}
+ private PortDescription buildOduCltPortDescription(OFPortDesc port) {
+ PortNumber portNo = PortNumber.portNumber(port.getPortNo().getPortNumber());
+ boolean enabled = !port.getState().contains(OFPortState.LINK_DOWN) &&
+ !port.getConfig().contains(OFPortConfig.PORT_DOWN);
+ Long portSpeed = portSpeed(port);
+ OduCltPort.SignalType sigType = null;
+
+ switch (portSpeed.toString()) {
+ case "1":
+ sigType = OduCltPort.SignalType.CLT_1GBE;
+ break;
+ case "10":
+ sigType = OduCltPort.SignalType.CLT_10GBE;
+ break;
+ case "40":
+ sigType = OduCltPort.SignalType.CLT_40GBE;
+ break;
+ case "100":
+ sigType = OduCltPort.SignalType.CLT_100GBE;
+ break;
+ default:
+ throw new RuntimeException("Un recognize OduClt speed: " + portSpeed.toString());
+ }
+
+ SparseAnnotations annotations = buildOduCltAnnotation(port);
+ return new OduCltPortDescription(portNo, enabled, sigType, annotations);
+ }
+
+ private SparseAnnotations buildOduCltAnnotation(OFPortDesc port) {
+ SparseAnnotations annotations = null;
+ String portName = Strings.emptyToNull(port.getName());
+ if (portName != null) {
+ annotations = DefaultAnnotations.builder()
+ .set(AnnotationKeys.PORT_NAME, portName)
+ .set(AnnotationKeys.STATIC_PORT, Boolean.TRUE.toString()).build();
+ }
+ return annotations;
+ }
+
+ private PortDescription buildPortDescription(PortDescPropertyType ptype, OFObject port) {
+ if (port instanceof OFPortOptical) {
+ return buildPortDescription(ptype, (OFPortOptical) port);
+ }
+ return buildPortDescription(ptype, (OFExpPort) port);
+ }
+
+ /**
+ * Build a portDescription from a given a port description describing some
+ * Optical port.
+ *
+ * @param ptype description property type.
+ * @param port the port to build from.
+ * @return portDescription for the port.
+ */
+ private PortDescription buildPortDescription(PortDescPropertyType ptype, OFExpPort port) {
+ PortNumber portNo = PortNumber.portNumber(port.getPortNo().getPortNumber());
+ boolean enabled = !port.getState().contains(OFPortState.LINK_DOWN)
+ && !port.getConfig().contains(OFPortConfig.PORT_DOWN);
+ SparseAnnotations annotations = makePortNameAnnotation(port.getName());
+
+ OFExpPortDescPropOpticalTransport firstProp = port.getProperties().get(0);
+ OFPortOpticalTransportSignalType sigType = firstProp.getPortSignalType();
+
+ DefaultPortDescription portDes = null;
+ switch (sigType) {
+ case OMSN:
+ portDes = new OmsPortDescription(portNo, enabled, FREQ193_1, FREQ193_1.add(FREQ4_4),
+ FREQ100, annotations);
+ break;
+ case OCH:
+ OFExpPortOpticalTransportLayerEntry entry = firstProp.getFeatures().get(0).getValue().get(0);
+ OFPortOpticalTransportLayerClass layerClass = entry.getLayerClass();
+ if (!OFPortOpticalTransportLayerClass.ODU.equals(layerClass)) {
+ LOG.error("Unsupported layer Class {} ", layerClass);
+ return null;
+ }
+
+ // convert to ONOS OduSignalType
+ OduSignalType oduSignalType = OpenFlowDeviceValueMapper.
+ lookupOduSignalType((byte) entry.getSignalType());
+ //OchSignal is needed for OchPortDescription constructor,
+ //yet not relevant for tunable OCH port, creating with default parameters
+ OchSignal signalId = new OchSignal(GridType.DWDM, ChannelSpacing.CHL_50GHZ, 1, 1);
+
+ portDes = new OchPortDescription(portNo, enabled,
+ oduSignalType, true, signalId, annotations);
+
+ break;
+ case OTU2:
+ case OTU4:
+ LOG.error("Signal tpye OTU2/4 not supported yet ", port.toString());
+ break;
+ default:
+ break;
+ }
+
+ return portDes;
+ }
+
/**
* Creates an annotation for the port name if one is available.
*
@@ -565,5 +695,4 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr
}
}
}
-
}
diff --git a/framework/src/onos/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceValueMapper.java b/framework/src/onos/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceValueMapper.java
new file mode 100644
index 00000000..7bdf06fd
--- /dev/null
+++ b/framework/src/onos/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceValueMapper.java
@@ -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.provider.of.device.impl;
+
+import org.onosproject.net.OduSignalType;
+
+import com.google.common.collect.BiMap;
+import com.google.common.collect.EnumHashBiMap;
+
+/**
+ * Collection of helper methods to convert protocol agnostic models to values used in OpenFlow spec.
+ */
+final class OpenFlowDeviceValueMapper {
+
+ // prohibit instantiation
+ private OpenFlowDeviceValueMapper() {}
+
+ private static final BiMap<OduSignalType, Byte> ODU_SIGNAL_TYPES = EnumHashBiMap.create(OduSignalType.class);
+ static {
+ // See ONF "Optical Transport Protocol Extensions Version 1.0" for the following values
+ ODU_SIGNAL_TYPES.put(OduSignalType.ODU1, (byte) 1); // OFPODUT_ODU1 of enum ofp_odu_signal_type
+ ODU_SIGNAL_TYPES.put(OduSignalType.ODU2, (byte) 2); // OFPODUT_ODU2 of enum ofp_odu_signal_type
+ ODU_SIGNAL_TYPES.put(OduSignalType.ODU3, (byte) 3); // OFPODUT_ODU3 of enum ofp_odu_signal_type
+ ODU_SIGNAL_TYPES.put(OduSignalType.ODU4, (byte) 4); // OFPODUT_ODU4 of enum ofp_odu_signal_type
+ ODU_SIGNAL_TYPES.put(OduSignalType.ODU0, (byte) 10); // OFPODUT_ODU0 of enum ofp_odu_signal_type
+ ODU_SIGNAL_TYPES.put(OduSignalType.ODU2e, (byte) 11); // OFPODUT_ODU2E of enum ofp_odu_signal_type
+ }
+
+ /**
+ * Looks up the specified input value to the corresponding value with the specified map.
+ *
+ * @param map bidirectional mapping
+ * @param input input value
+ * @param cls class of output value
+ * @param <I> type of input value
+ * @param <O> type of output value
+ * @return the corresponding value stored in the specified map
+ */
+ private static <I, O> O lookup(BiMap<I, O> map, I input, Class<O> cls) {
+ if (!map.containsKey(input)) {
+ throw new RuntimeException(
+ String.format("No mapping found for %s when converting to %s", input, cls.getName()));
+ }
+
+ return map.get(input);
+ }
+
+ /**
+ * Looks up the the corresponding {@link OduSignalType} instance
+ * from the specified byte value for ODU signal type defined in
+ * ONF "Optical Transport Protocol Extensions Version 1.0".
+ *
+ * @param signalType byte value as ODU (Optical channel Data Unit) signal type defined the spec
+ * @return the corresponding OchSignalType instance
+ */
+ static OduSignalType lookupOduSignalType(byte signalType) {
+ return lookup(ODU_SIGNAL_TYPES.inverse(), signalType, OduSignalType.class);
+ }
+
+}
diff --git a/framework/src/onos/providers/openflow/device/src/test/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProviderTest.java b/framework/src/onos/providers/openflow/device/src/test/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProviderTest.java
index 7b4d7922..d0838bb8 100644
--- a/framework/src/onos/providers/openflow/device/src/test/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProviderTest.java
+++ b/framework/src/onos/providers/openflow/device/src/test/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProviderTest.java
@@ -16,6 +16,7 @@
package org.onosproject.provider.of.device.impl;
import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
@@ -236,7 +237,7 @@ public class OpenFlowDeviceProviderTest {
@Override
public Iterable<OpenFlowSwitch> getMasterSwitches() {
- return null;
+ return ImmutableSet.of();
}
@Override
diff --git a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowEntryBuilder.java b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowEntryBuilder.java
index f238bdb1..cf918605 100644
--- a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowEntryBuilder.java
+++ b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowEntryBuilder.java
@@ -221,11 +221,6 @@ public class FlowEntryBuilder {
private TrafficTreatment buildTreatment() {
TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder();
- // If this is a drop rule
- if (instructions.size() == 0) {
- builder.drop();
- return builder.build();
- }
for (OFInstruction in : instructions) {
switch (in.getType()) {
case GOTO_TABLE:
diff --git a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer10.java b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer10.java
index c9de4500..f77819d5 100644
--- a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer10.java
+++ b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer10.java
@@ -142,7 +142,7 @@ public class FlowModBuilderVer10 extends FlowModBuilder {
for (Instruction i : treatment.immediate()) {
switch (i.type()) {
case DROP:
- log.warn("Saw drop action; assigning drop action");
+ case NOACTION:
return Collections.emptyList();
case L2MODIFICATION:
act = buildL2Modification(i);
diff --git a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java
index 8918d337..cc265758 100644
--- a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java
+++ b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java
@@ -123,6 +123,9 @@ public class FlowModBuilderVer13 extends FlowModBuilder {
if (treatment.writeMetadata() != null) {
instructions.add(buildMetadata(treatment.writeMetadata()));
}
+ if (treatment.metered() != null) {
+ instructions.add(buildMeter(treatment.metered()));
+ }
long cookie = flowRule().id().value();
@@ -212,6 +215,7 @@ public class FlowModBuilderVer13 extends FlowModBuilder {
for (Instruction i : treatments) {
switch (i.type()) {
case DROP:
+ case NOACTION:
return Collections.emptyList();
case L0MODIFICATION:
actions.add(buildL0Modification(i));
diff --git a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/NewAdaptiveFlowStatsCollector.java b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/NewAdaptiveFlowStatsCollector.java
new file mode 100644
index 00000000..a81367cd
--- /dev/null
+++ b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/NewAdaptiveFlowStatsCollector.java
@@ -0,0 +1,881 @@
+/*
+ * 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.provider.of.flow.impl;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+import org.onosproject.net.flow.DefaultTypedFlowEntry;
+import org.onosproject.net.flow.FlowEntry;
+import org.onosproject.net.flow.FlowId;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.StoredFlowEntry;
+import org.onosproject.net.flow.TypedStoredFlowEntry;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.Instructions;
+import org.onosproject.openflow.controller.OpenFlowSwitch;
+import org.onosproject.openflow.controller.RoleState;
+import org.projectfloodlight.openflow.protocol.OFFlowStatsRequest;
+import org.projectfloodlight.openflow.protocol.match.Match;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.TableId;
+import org.slf4j.Logger;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.net.flow.TypedStoredFlowEntry.*;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Efficiently and adaptively collects flow statistics for the specified switch.
+ */
+public class NewAdaptiveFlowStatsCollector {
+
+ private final Logger log = getLogger(getClass());
+
+ private final OpenFlowSwitch sw;
+
+ private ScheduledExecutorService adaptiveFlowStatsScheduler =
+ Executors.newScheduledThreadPool(4, groupedThreads("onos/flow", "device-stats-collector-%d"));
+ private ScheduledFuture<?> calAndShortFlowsThread;
+ private ScheduledFuture<?> midFlowsThread;
+ private ScheduledFuture<?> longFlowsThread;
+
+ // Task that calculates all flowEntries' FlowLiveType and collects stats IMMEDIATE flows every calAndPollInterval
+ private CalAndShortFlowsTask calAndShortFlowsTask;
+ // Task that collects stats MID flows every 2*calAndPollInterval
+ private MidFlowsTask midFlowsTask;
+ // Task that collects stats LONG flows every 3*calAndPollInterval
+ private LongFlowsTask longFlowsTask;
+
+ private static final int CAL_AND_POLL_TIMES = 1; // must be always 0
+ private static final int MID_POLL_TIMES = 2; // variable greater or equal than 1
+ private static final int LONG_POLL_TIMES = 3; // variable greater or equal than MID_POLL_TIMES
+ //TODO: make ENTIRE_POLL_TIMES configurable with enable or disable
+ // must be variable greater or equal than common multiple of MID_POLL_TIMES and LONG_POLL_TIMES
+ private static final int ENTIRE_POLL_TIMES = 6;
+
+ private static final int DEFAULT_CAL_AND_POLL_FREQUENCY = 5;
+ private static final int MIN_CAL_AND_POLL_FREQUENCY = 2;
+ private static final int MAX_CAL_AND_POLL_FREQUENCY = 60;
+
+ private int calAndPollInterval; // CAL_AND_POLL_TIMES * DEFAULT_CAL_AND_POLL_FREQUENCY;
+ private int midPollInterval; // MID_POLL_TIMES * DEFAULT_CAL_AND_POLL_FREQUENCY;
+ private int longPollInterval; // LONG_POLL_TIMES * DEFAULT_CAL_AND_POLL_FREQUENCY;
+ // only used for checking condition at each task if it collects entire flows from a given switch or not
+ private int entirePollInterval; // ENTIRE_POLL_TIMES * DEFAULT_CAL_AND_POLL_FREQUENCY;
+
+ // Number of call count of each Task,
+ // for undoing collection except only entire flows collecting task in CalAndShortFlowsTask
+ private int callCountCalAndShortFlowsTask = 0; // increased CAL_AND_POLL_TIMES whenever Task is called
+ private int callCountMidFlowsTask = 0; // increased MID_POLL_TIMES whenever Task is called
+ private int callCountLongFlowsTask = 0; // increased LONG_POLL_TIMES whenever Task is called
+
+ private InternalDeviceFlowTable deviceFlowTable = new InternalDeviceFlowTable();
+
+ private boolean isFirstTimeStart = true;
+
+ public static final long NO_FLOW_MISSING_XID = (-1);
+ private long flowMissingXid = NO_FLOW_MISSING_XID;
+
+ /**
+ * Creates a new adaptive collector for the given switch and default cal_and_poll frequency.
+ *
+ * @param sw switch to pull
+ * @param pollInterval cal and immediate poll frequency in seconds
+ */
+ NewAdaptiveFlowStatsCollector(OpenFlowSwitch sw, int pollInterval) {
+ this.sw = sw;
+
+ initMemberVars(pollInterval);
+ }
+
+ // check calAndPollInterval validity and set all pollInterval values and finally initialize each task call count
+ private void initMemberVars(int pollInterval) {
+ if (pollInterval < MIN_CAL_AND_POLL_FREQUENCY) {
+ this.calAndPollInterval = MIN_CAL_AND_POLL_FREQUENCY;
+ } else if (pollInterval >= MAX_CAL_AND_POLL_FREQUENCY) {
+ this.calAndPollInterval = MAX_CAL_AND_POLL_FREQUENCY;
+ } else {
+ this.calAndPollInterval = pollInterval;
+ }
+
+ calAndPollInterval = CAL_AND_POLL_TIMES * calAndPollInterval;
+ midPollInterval = MID_POLL_TIMES * calAndPollInterval;
+ longPollInterval = LONG_POLL_TIMES * calAndPollInterval;
+ entirePollInterval = ENTIRE_POLL_TIMES * calAndPollInterval;
+
+ callCountCalAndShortFlowsTask = 0;
+ callCountMidFlowsTask = 0;
+ callCountLongFlowsTask = 0;
+
+ flowMissingXid = NO_FLOW_MISSING_XID;
+ }
+
+ /**
+ * Adjusts adaptive poll frequency.
+ *
+ * @param pollInterval poll frequency in seconds
+ */
+ synchronized void adjustCalAndPollInterval(int pollInterval) {
+ initMemberVars(pollInterval);
+
+ if (calAndShortFlowsThread != null) {
+ calAndShortFlowsThread.cancel(false);
+ }
+ if (midFlowsThread != null) {
+ midFlowsThread.cancel(false);
+ }
+ if (longFlowsThread != null) {
+ longFlowsThread.cancel(false);
+ }
+
+ calAndShortFlowsTask = new CalAndShortFlowsTask();
+ calAndShortFlowsThread = adaptiveFlowStatsScheduler.scheduleWithFixedDelay(
+ calAndShortFlowsTask,
+ 0,
+ calAndPollInterval,
+ TimeUnit.SECONDS);
+
+ midFlowsTask = new MidFlowsTask();
+ midFlowsThread = adaptiveFlowStatsScheduler.scheduleWithFixedDelay(
+ midFlowsTask,
+ 0,
+ midPollInterval,
+ TimeUnit.SECONDS);
+
+ longFlowsTask = new LongFlowsTask();
+ longFlowsThread = adaptiveFlowStatsScheduler.scheduleWithFixedDelay(
+ longFlowsTask,
+ 0,
+ longPollInterval,
+ TimeUnit.SECONDS);
+
+ log.debug("calAndPollInterval=" + calAndPollInterval + "is adjusted");
+ }
+
+ private class CalAndShortFlowsTask implements Runnable {
+ @Override
+ public void run() {
+ if (sw.getRole() == RoleState.MASTER) {
+ log.trace("CalAndShortFlowsTask Collecting AdaptiveStats for {}", sw.getStringId());
+
+ if (isFirstTimeStart) {
+ // isFirstTimeStart, get entire flow stats from a given switch sw
+ log.trace("CalAndShortFlowsTask Collecting Entire AdaptiveStats at first time start for {}",
+ sw.getStringId());
+ ofFlowStatsRequestAllSend();
+
+ callCountCalAndShortFlowsTask += CAL_AND_POLL_TIMES;
+ isFirstTimeStart = false;
+ } else if (callCountCalAndShortFlowsTask == ENTIRE_POLL_TIMES) {
+ // entire_poll_times, get entire flow stats from a given switch sw
+ log.trace("CalAndShortFlowsTask Collecting Entire AdaptiveStats for {}", sw.getStringId());
+ ofFlowStatsRequestAllSend();
+
+ callCountCalAndShortFlowsTask = CAL_AND_POLL_TIMES;
+ //TODO: check flows deleted in switch, but exist in controller flow table, then remove them
+ //
+ } else {
+ calAndShortFlowsTaskInternal();
+ callCountCalAndShortFlowsTask += CAL_AND_POLL_TIMES;
+ }
+ }
+ }
+ }
+
+ // send openflow flow stats request message with getting all flow entries to a given switch sw
+ private void ofFlowStatsRequestAllSend() {
+ OFFlowStatsRequest request = sw.factory().buildFlowStatsRequest()
+ .setMatch(sw.factory().matchWildcardAll())
+ .setTableId(TableId.ALL)
+ .setOutPort(OFPort.NO_MASK)
+ .build();
+
+ synchronized (this) {
+ // set the request xid to check the reply in OpenFlowRuleProvider
+ // After processing the reply of this request message,
+ // this must be set to NO_FLOW_MISSING_XID(-1) by provider
+ setFlowMissingXid(request.getXid());
+ log.debug("ofFlowStatsRequestAllSend,Request={},for {}", request.toString(), sw.getStringId());
+
+ sw.sendMsg(request);
+ }
+ }
+
+ // send openflow flow stats request message with getting the specific flow entry(fe) to a given switch sw
+ private void ofFlowStatsRequestFlowSend(FlowEntry fe) {
+ // set find match
+ Match match = FlowModBuilder.builder(fe, sw.factory(), Optional.empty()).buildMatch();
+ // set find tableId
+ TableId tableId = TableId.of(fe.tableId());
+ // set output port
+ Instruction ins = fe.treatment().allInstructions().stream()
+ .filter(i -> (i.type() == Instruction.Type.OUTPUT))
+ .findFirst()
+ .orElse(null);
+ OFPort ofPort = OFPort.NO_MASK;
+ if (ins != null) {
+ Instructions.OutputInstruction out = (Instructions.OutputInstruction) ins;
+ ofPort = OFPort.of((int) ((out.port().toLong())));
+ }
+
+ OFFlowStatsRequest request = sw.factory().buildFlowStatsRequest()
+ .setMatch(match)
+ .setTableId(tableId)
+ .setOutPort(ofPort)
+ .build();
+
+ synchronized (this) {
+ if (getFlowMissingXid() != NO_FLOW_MISSING_XID) {
+ log.debug("ofFlowStatsRequestFlowSend: previous FlowStatsRequestAll does not be processed yet,"
+ + " set no flow missing xid anyway, for {}",
+ sw.getStringId());
+ setFlowMissingXid(NO_FLOW_MISSING_XID);
+ }
+
+ sw.sendMsg(request);
+ }
+ }
+
+ private void calAndShortFlowsTaskInternal() {
+ deviceFlowTable.checkAndMoveLiveFlowAll();
+
+ deviceFlowTable.getShortFlows().forEach(fe -> {
+ ofFlowStatsRequestFlowSend(fe);
+ });
+ }
+
+ private class MidFlowsTask implements Runnable {
+ @Override
+ public void run() {
+ if (sw.getRole() == RoleState.MASTER) {
+ log.trace("MidFlowsTask Collecting AdaptiveStats for {}", sw.getStringId());
+
+ // skip collecting because CalAndShortFlowsTask collects entire flow stats from a given switch sw
+ if (callCountMidFlowsTask == ENTIRE_POLL_TIMES) {
+ callCountMidFlowsTask = MID_POLL_TIMES;
+ } else {
+ midFlowsTaskInternal();
+ callCountMidFlowsTask += MID_POLL_TIMES;
+ }
+ }
+ }
+ }
+
+ private void midFlowsTaskInternal() {
+ deviceFlowTable.getMidFlows().forEach(fe -> {
+ ofFlowStatsRequestFlowSend(fe);
+ });
+ }
+
+ private class LongFlowsTask implements Runnable {
+ @Override
+ public void run() {
+ if (sw.getRole() == RoleState.MASTER) {
+ log.trace("LongFlowsTask Collecting AdaptiveStats for {}", sw.getStringId());
+
+ // skip collecting because CalAndShortFlowsTask collects entire flow stats from a given switch sw
+ if (callCountLongFlowsTask == ENTIRE_POLL_TIMES) {
+ callCountLongFlowsTask = LONG_POLL_TIMES;
+ } else {
+ longFlowsTaskInternal();
+ callCountLongFlowsTask += LONG_POLL_TIMES;
+ }
+ }
+ }
+ }
+
+ private void longFlowsTaskInternal() {
+ deviceFlowTable.getLongFlows().forEach(fe -> {
+ ofFlowStatsRequestFlowSend(fe);
+ });
+ }
+
+ /**
+ * start adaptive flow statistic collection.
+ *
+ */
+ public synchronized void start() {
+ log.debug("Starting AdaptiveStats collection thread for {}", sw.getStringId());
+ callCountCalAndShortFlowsTask = 0;
+ callCountMidFlowsTask = 0;
+ callCountLongFlowsTask = 0;
+
+ isFirstTimeStart = true;
+
+ // Initially start polling quickly. Then drop down to configured value
+ calAndShortFlowsTask = new CalAndShortFlowsTask();
+ calAndShortFlowsThread = adaptiveFlowStatsScheduler.scheduleWithFixedDelay(
+ calAndShortFlowsTask,
+ 1,
+ calAndPollInterval,
+ TimeUnit.SECONDS);
+
+ midFlowsTask = new MidFlowsTask();
+ midFlowsThread = adaptiveFlowStatsScheduler.scheduleWithFixedDelay(
+ midFlowsTask,
+ 1,
+ midPollInterval,
+ TimeUnit.SECONDS);
+
+ longFlowsTask = new LongFlowsTask();
+ longFlowsThread = adaptiveFlowStatsScheduler.scheduleWithFixedDelay(
+ longFlowsTask,
+ 1,
+ longPollInterval,
+ TimeUnit.SECONDS);
+
+ log.info("Started");
+ }
+
+ /**
+ * stop adaptive flow statistic collection.
+ *
+ */
+ public synchronized void stop() {
+ log.debug("Stopping AdaptiveStats collection thread for {}", sw.getStringId());
+ if (calAndShortFlowsThread != null) {
+ calAndShortFlowsThread.cancel(true);
+ }
+ if (midFlowsThread != null) {
+ midFlowsThread.cancel(true);
+ }
+ if (longFlowsThread != null) {
+ longFlowsThread.cancel(true);
+ }
+
+ adaptiveFlowStatsScheduler.shutdownNow();
+
+ isFirstTimeStart = false;
+
+ log.info("Stopped");
+ }
+
+ /**
+ * add typed flow entry from flow rule into the internal flow table.
+ *
+ * @param flowRules the flow rules
+ *
+ */
+ public synchronized void addWithFlowRule(FlowRule... flowRules) {
+ for (FlowRule fr : flowRules) {
+ // First remove old entry unconditionally, if exist
+ deviceFlowTable.remove(fr);
+
+ // add new flow entry, we suppose IMMEDIATE_FLOW
+ TypedStoredFlowEntry newFlowEntry = new DefaultTypedFlowEntry(fr,
+ FlowLiveType.IMMEDIATE_FLOW);
+ deviceFlowTable.addWithCalAndSetFlowLiveType(newFlowEntry);
+ }
+ }
+
+ /**
+ * add or update typed flow entry from flow entry into the internal flow table.
+ *
+ * @param flowEntries the flow entries
+ *
+ */
+ public synchronized void addOrUpdateFlows(FlowEntry... flowEntries) {
+ for (FlowEntry fe : flowEntries) {
+ // check if this new rule is an update to an existing entry
+ TypedStoredFlowEntry stored = deviceFlowTable.getFlowEntry(fe);
+
+ if (stored != null) {
+ // duplicated flow entry is collected!, just skip
+ if (fe.bytes() == stored.bytes() && fe.packets() == stored.packets()
+ && fe.life() == stored.life()) {
+ log.debug("addOrUpdateFlows:, FlowId=" + Long.toHexString(fe.id().value())
+ + ",is DUPLICATED stats collection, just skip."
+ + " AdaptiveStats collection thread for {}",
+ sw.getStringId());
+
+ stored.setLastSeen();
+ continue;
+ } else if (fe.life() < stored.life()) {
+ // Invalid updates the stats values, i.e., bytes, packets, durations ...
+ log.debug("addOrUpdateFlows():" +
+ " Invalid Flow Update! The new life is SMALLER than the previous one, jus skip." +
+ " new flowId=" + Long.toHexString(fe.id().value()) +
+ ", old flowId=" + Long.toHexString(stored.id().value()) +
+ ", new bytes=" + fe.bytes() + ", old bytes=" + stored.bytes() +
+ ", new life=" + fe.life() + ", old life=" + stored.life() +
+ ", new lastSeen=" + fe.lastSeen() + ", old lastSeen=" + stored.lastSeen());
+ // go next
+ stored.setLastSeen();
+ continue;
+ }
+
+ // update now
+ stored.setLife(fe.life());
+ stored.setPackets(fe.packets());
+ stored.setBytes(fe.bytes());
+ stored.setLastSeen();
+ if (stored.state() == FlowEntry.FlowEntryState.PENDING_ADD) {
+ // flow is really RULE_ADDED
+ stored.setState(FlowEntry.FlowEntryState.ADDED);
+ }
+ // flow is RULE_UPDATED, skip adding and just updating flow live table
+ //deviceFlowTable.calAndSetFlowLiveType(stored);
+ continue;
+ }
+
+ // add new flow entry, we suppose IMMEDIATE_FLOW
+ TypedStoredFlowEntry newFlowEntry = new DefaultTypedFlowEntry(fe,
+ FlowLiveType.IMMEDIATE_FLOW);
+ deviceFlowTable.addWithCalAndSetFlowLiveType(newFlowEntry);
+ }
+ }
+
+ /**
+ * remove typed flow entry from the internal flow table.
+ *
+ * @param flowRules the flow entries
+ *
+ */
+ public synchronized void removeFlows(FlowRule... flowRules) {
+ for (FlowRule rule : flowRules) {
+ deviceFlowTable.remove(rule);
+ }
+ }
+
+ // same as removeFlows() function
+ /**
+ * remove typed flow entry from the internal flow table.
+ *
+ * @param flowRules the flow entries
+ *
+ */
+ public void flowRemoved(FlowRule... flowRules) {
+ removeFlows(flowRules);
+ }
+
+ // same as addOrUpdateFlows() function
+ /**
+ * add or update typed flow entry from flow entry into the internal flow table.
+ *
+ * @param flowEntries the flow entry list
+ *
+ */
+ public void pushFlowMetrics(List<FlowEntry> flowEntries) {
+ flowEntries.forEach(fe -> {
+ addOrUpdateFlows(fe);
+ });
+ }
+
+ /**
+ * returns flowMissingXid that indicates the execution of flowMissing process or not(NO_FLOW_MISSING_XID(-1)).
+ *
+ */
+ public long getFlowMissingXid() {
+ return flowMissingXid;
+ }
+
+ /**
+ * set flowMissingXid, namely OFFlowStatsRequest match any ALL message Id.
+ *
+ * @param flowMissingXid the OFFlowStatsRequest message Id
+ *
+ */
+ public void setFlowMissingXid(long flowMissingXid) {
+ this.flowMissingXid = flowMissingXid;
+ }
+
+ private class InternalDeviceFlowTable {
+
+ private final Map<FlowId, Set<TypedStoredFlowEntry>>
+ flowEntries = Maps.newConcurrentMap();
+
+ private final Set<StoredFlowEntry> shortFlows = new HashSet<>();
+ private final Set<StoredFlowEntry> midFlows = new HashSet<>();
+ private final Set<StoredFlowEntry> longFlows = new HashSet<>();
+
+ // Assumed latency adjustment(default=500 millisecond) between FlowStatsRequest and Reply
+ private final long latencyFlowStatsRequestAndReplyMillis = 500;
+
+
+ // Statistics for table operation
+ private long addCount = 0, addWithSetFlowLiveTypeCount = 0;
+ private long removeCount = 0;
+
+ /**
+ * Resets all count values with zero.
+ *
+ */
+ public void resetAllCount() {
+ addCount = 0;
+ addWithSetFlowLiveTypeCount = 0;
+ removeCount = 0;
+ }
+
+ // get set of flow entries for the given flowId
+ private Set<TypedStoredFlowEntry> getFlowEntriesInternal(FlowId flowId) {
+ return flowEntries.computeIfAbsent(flowId, id -> Sets.newCopyOnWriteArraySet());
+ }
+
+ // get flow entry for the given flow rule
+ private TypedStoredFlowEntry getFlowEntryInternal(FlowRule rule) {
+ Set<TypedStoredFlowEntry> flowEntries = getFlowEntriesInternal(rule.id());
+ return flowEntries.stream()
+ .filter(entry -> Objects.equal(entry, rule))
+ .findAny()
+ .orElse(null);
+ }
+
+ // get the flow entries for all flows in flow table
+ private Set<TypedStoredFlowEntry> getFlowEntriesInternal() {
+ Set<TypedStoredFlowEntry> result = Sets.newHashSet();
+
+ flowEntries.values().forEach(result::addAll);
+ return result;
+ }
+
+ /**
+ * Gets the number of flow entry in flow table.
+ *
+ * @return the number of flow entry.
+ *
+ */
+ public long getFlowCount() {
+ return flowEntries.values().stream().mapToLong(Set::size).sum();
+ }
+
+ /**
+ * Gets the number of flow entry in flow table.
+ *
+ * @param rule the flow rule
+ * @return the typed flow entry.
+ *
+ */
+ public TypedStoredFlowEntry getFlowEntry(FlowRule rule) {
+ checkNotNull(rule);
+
+ return getFlowEntryInternal(rule);
+ }
+
+ /**
+ * Gets the all typed flow entries in flow table.
+ *
+ * @return the set of typed flow entry.
+ *
+ */
+ public Set<TypedStoredFlowEntry> getFlowEntries() {
+ return getFlowEntriesInternal();
+ }
+
+ /**
+ * Gets the short typed flow entries in flow table.
+ *
+ * @return the set of typed flow entry.
+ *
+ */
+ public Set<StoredFlowEntry> getShortFlows() {
+ return ImmutableSet.copyOf(shortFlows); //Sets.newHashSet(shortFlows);
+ }
+
+ /**
+ * Gets the mid typed flow entries in flow table.
+ *
+ * @return the set of typed flow entry.
+ *
+ */
+ public Set<StoredFlowEntry> getMidFlows() {
+ return ImmutableSet.copyOf(midFlows); //Sets.newHashSet(midFlows);
+ }
+
+ /**
+ * Gets the long typed flow entries in flow table.
+ *
+ * @return the set of typed flow entry.
+ *
+ */
+ public Set<StoredFlowEntry> getLongFlows() {
+ return ImmutableSet.copyOf(longFlows); //Sets.newHashSet(longFlows);
+ }
+
+ /**
+ * Add typed flow entry into table only.
+ *
+ * @param rule the flow rule
+ *
+ */
+ public synchronized void add(TypedStoredFlowEntry rule) {
+ checkNotNull(rule);
+
+ //rule have to be new DefaultTypedFlowEntry
+ boolean result = getFlowEntriesInternal(rule.id()).add(rule);
+
+ if (result) {
+ addCount++;
+ }
+ }
+
+ /**
+ * Calculates and set the flow live type at the first time,
+ * and then add it into a corresponding typed flow table.
+ *
+ * @param rule the flow rule
+ *
+ */
+ public void calAndSetFlowLiveType(TypedStoredFlowEntry rule) {
+ checkNotNull(rule);
+
+ calAndSetFlowLiveTypeInternal(rule);
+ }
+
+ /**
+ * Add the typed flow entry into table, and calculates and set the flow live type,
+ * and then add it into a corresponding typed flow table.
+ *
+ * @param rule the flow rule
+ *
+ */
+ public synchronized void addWithCalAndSetFlowLiveType(TypedStoredFlowEntry rule) {
+ checkNotNull(rule);
+
+ //rule have to be new DefaultTypedFlowEntry
+ boolean result = getFlowEntriesInternal(rule.id()).add(rule);
+ if (result) {
+ calAndSetFlowLiveTypeInternal(rule);
+ addWithSetFlowLiveTypeCount++;
+ } else {
+ log.debug("addWithCalAndSetFlowLiveType, FlowId=" + Long.toHexString(rule.id().value())
+ + " ADD Failed, cause it may already exists in table !!!,"
+ + " AdaptiveStats collection thread for {}",
+ sw.getStringId());
+ }
+ }
+
+ // In real, calculates and set the flow live type at the first time,
+ // and then add it into a corresponding typed flow table
+ private void calAndSetFlowLiveTypeInternal(TypedStoredFlowEntry rule) {
+ long life = rule.life();
+ FlowLiveType prevFlowLiveType = rule.flowLiveType();
+
+ if (life >= longPollInterval) {
+ rule.setFlowLiveType(FlowLiveType.LONG_FLOW);
+ longFlows.add(rule);
+ } else if (life >= midPollInterval) {
+ rule.setFlowLiveType(FlowLiveType.MID_FLOW);
+ midFlows.add(rule);
+ } else if (life >= calAndPollInterval) {
+ rule.setFlowLiveType(FlowLiveType.SHORT_FLOW);
+ shortFlows.add(rule);
+ } else if (life >= 0) {
+ rule.setFlowLiveType(FlowLiveType.IMMEDIATE_FLOW);
+ } else { // life < 0
+ rule.setFlowLiveType(FlowLiveType.UNKNOWN_FLOW);
+ }
+
+ if (rule.flowLiveType() != prevFlowLiveType) {
+ switch (prevFlowLiveType) {
+ // delete it from previous flow table
+ case SHORT_FLOW:
+ shortFlows.remove(rule);
+ break;
+ case MID_FLOW:
+ midFlows.remove(rule);
+ break;
+ case LONG_FLOW:
+ longFlows.remove(rule);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+
+ // check the flow live type based on current time, then set and add it into corresponding table
+ private boolean checkAndMoveLiveFlowInternal(TypedStoredFlowEntry fe, long cTime) {
+ long curTime = (cTime > 0 ? cTime : System.currentTimeMillis());
+ // For latency adjustment(default=500 millisecond) between FlowStatsRequest and Reply
+ long fromLastSeen = ((curTime - fe.lastSeen() + latencyFlowStatsRequestAndReplyMillis) / 1000);
+ // fe.life() unit is SECOND!
+ long liveTime = fe.life() + fromLastSeen;
+
+
+ switch (fe.flowLiveType()) {
+ case IMMEDIATE_FLOW:
+ if (liveTime >= longPollInterval) {
+ fe.setFlowLiveType(FlowLiveType.LONG_FLOW);
+ longFlows.add(fe);
+ } else if (liveTime >= midPollInterval) {
+ fe.setFlowLiveType(FlowLiveType.MID_FLOW);
+ midFlows.add(fe);
+ } else if (liveTime >= calAndPollInterval) {
+ fe.setFlowLiveType(FlowLiveType.SHORT_FLOW);
+ shortFlows.add(fe);
+ }
+ break;
+ case SHORT_FLOW:
+ if (liveTime >= longPollInterval) {
+ fe.setFlowLiveType(FlowLiveType.LONG_FLOW);
+ shortFlows.remove(fe);
+ longFlows.add(fe);
+ } else if (liveTime >= midPollInterval) {
+ fe.setFlowLiveType(FlowLiveType.MID_FLOW);
+ shortFlows.remove(fe);
+ midFlows.add(fe);
+ }
+ break;
+ case MID_FLOW:
+ if (liveTime >= longPollInterval) {
+ fe.setFlowLiveType(FlowLiveType.LONG_FLOW);
+ midFlows.remove(fe);
+ longFlows.add(fe);
+ }
+ break;
+ case LONG_FLOW:
+ if (fromLastSeen > entirePollInterval) {
+ log.trace("checkAndMoveLiveFlowInternal, flow is already removed at switch.");
+ return false;
+ }
+ break;
+ case UNKNOWN_FLOW: // Unknown flow is an internal error flow type, just fall through
+ default :
+ // Error Unknown Live Type
+ log.error("checkAndMoveLiveFlowInternal, Unknown Live Type error!"
+ + "AdaptiveStats collection thread for {}",
+ sw.getStringId());
+ return false;
+ }
+
+ log.debug("checkAndMoveLiveFlowInternal, FlowId=" + Long.toHexString(fe.id().value())
+ + ", state=" + fe.state()
+ + ", After liveType=" + fe.flowLiveType()
+ + ", liveTime=" + liveTime
+ + ", life=" + fe.life()
+ + ", bytes=" + fe.bytes()
+ + ", packets=" + fe.packets()
+ + ", fromLastSeen=" + fromLastSeen
+ + ", priority=" + fe.priority()
+ + ", selector=" + fe.selector().criteria()
+ + ", treatment=" + fe.treatment()
+ + " AdaptiveStats collection thread for {}",
+ sw.getStringId());
+
+ return true;
+ }
+
+ /**
+ * Check and move live type for all type flow entries in table at every calAndPollInterval time.
+ *
+ */
+ public void checkAndMoveLiveFlowAll() {
+ Set<TypedStoredFlowEntry> typedFlowEntries = getFlowEntriesInternal();
+
+ long calCurTime = System.currentTimeMillis();
+ typedFlowEntries.forEach(fe -> {
+ if (!checkAndMoveLiveFlowInternal(fe, calCurTime)) {
+ remove(fe);
+ }
+ });
+
+ // print table counts for debug
+ if (log.isDebugEnabled()) {
+ synchronized (this) {
+ long totalFlowCount = getFlowCount();
+ long shortFlowCount = shortFlows.size();
+ long midFlowCount = midFlows.size();
+ long longFlowCount = longFlows.size();
+ long immediateFlowCount = totalFlowCount - shortFlowCount - midFlowCount - longFlowCount;
+ long calTotalCount = addCount + addWithSetFlowLiveTypeCount - removeCount;
+
+ log.debug("--------------------------------------------------------------------------- for {}",
+ sw.getStringId());
+ log.debug("checkAndMoveLiveFlowAll, Total Flow_Count=" + totalFlowCount
+ + ", add - remove_Count=" + calTotalCount
+ + ", IMMEDIATE_FLOW_Count=" + immediateFlowCount
+ + ", SHORT_FLOW_Count=" + shortFlowCount
+ + ", MID_FLOW_Count=" + midFlowCount
+ + ", LONG_FLOW_Count=" + longFlowCount
+ + ", add_Count=" + addCount
+ + ", addWithSetFlowLiveType_Count=" + addWithSetFlowLiveTypeCount
+ + ", remove_Count=" + removeCount
+ + " AdaptiveStats collection thread for {}", sw.getStringId());
+ log.debug("--------------------------------------------------------------------------- for {}",
+ sw.getStringId());
+ if (totalFlowCount != calTotalCount) {
+ log.error("checkAndMoveLiveFlowAll, Real total flow count and "
+ + "calculated total flow count do NOT match, something is wrong internally "
+ + "or check counter value bound is over!");
+ }
+ if (immediateFlowCount < 0) {
+ log.error("checkAndMoveLiveFlowAll, IMMEDIATE_FLOW count is negative, "
+ + "something is wrong internally "
+ + "or check counter value bound is over!");
+ }
+ }
+ }
+ log.trace("checkAndMoveLiveFlowAll, AdaptiveStats for {}", sw.getStringId());
+ }
+
+ /**
+ * Remove the typed flow entry from table.
+ *
+ * @param rule the flow rule
+ *
+ */
+ public synchronized void remove(FlowRule rule) {
+ checkNotNull(rule);
+
+ TypedStoredFlowEntry removeStore = getFlowEntryInternal(rule);
+ if (removeStore != null) {
+ removeLiveFlowsInternal((TypedStoredFlowEntry) removeStore);
+ boolean result = getFlowEntriesInternal(rule.id()).remove(removeStore);
+
+ if (result) {
+ removeCount++;
+ }
+ }
+ }
+
+ // Remove the typed flow entry from corresponding table
+ private void removeLiveFlowsInternal(TypedStoredFlowEntry fe) {
+ switch (fe.flowLiveType()) {
+ case IMMEDIATE_FLOW:
+ // do nothing
+ break;
+ case SHORT_FLOW:
+ shortFlows.remove(fe);
+ break;
+ case MID_FLOW:
+ midFlows.remove(fe);
+ break;
+ case LONG_FLOW:
+ longFlows.remove(fe);
+ break;
+ default: // error in Flow Live Type
+ log.error("removeLiveFlowsInternal, Unknown Live Type error!");
+ break;
+ }
+ }
+ }
+}
diff --git a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java
index de079e03..6374ca55 100644
--- a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java
+++ b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 Open Networking Laboratory
+ * 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.
@@ -21,6 +21,7 @@ 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 +33,7 @@ import org.onosproject.cfg.ComponentConfigService;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.DeviceId;
import org.onosproject.net.flow.CompletedBatchOperation;
+import org.onosproject.net.flow.DefaultTableStatisticsEntry;
import org.onosproject.net.flow.FlowEntry;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.FlowRuleBatchEntry;
@@ -40,6 +42,7 @@ import org.onosproject.net.flow.FlowRuleExtPayLoad;
import org.onosproject.net.flow.FlowRuleProvider;
import org.onosproject.net.flow.FlowRuleProviderRegistry;
import org.onosproject.net.flow.FlowRuleProviderService;
+import org.onosproject.net.flow.TableStatisticsEntry;
import org.onosproject.net.provider.AbstractProvider;
import org.onosproject.net.provider.ProviderId;
import org.onosproject.net.statistic.DefaultLoad;
@@ -58,6 +61,8 @@ 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;
@@ -70,12 +75,14 @@ import java.util.Collections;
import java.util.Dictionary;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.Timer;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
+import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Strings.isNullOrEmpty;
import static org.onlab.util.Tools.get;
import static org.slf4j.LoggerFactory.getLogger;
@@ -99,11 +106,16 @@ public class OpenFlowRuleProvider extends AbstractProvider
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected ComponentConfigService cfgService;
- private static final int DEFAULT_POLL_FREQUENCY = 10;
+ private static final int DEFAULT_POLL_FREQUENCY = 5;
@Property(name = "flowPollFrequency", intValue = DEFAULT_POLL_FREQUENCY,
label = "Frequency (in seconds) for polling flow statistics")
private int flowPollFrequency = DEFAULT_POLL_FREQUENCY;
+ private static final boolean DEFAULT_ADAPTIVE_FLOW_SAMPLING = true;
+ @Property(name = "adaptiveFlowSampling", boolValue = DEFAULT_ADAPTIVE_FLOW_SAMPLING,
+ label = "Adaptive Flow Sampling is on or off")
+ private boolean adaptiveFlowSampling = DEFAULT_ADAPTIVE_FLOW_SAMPLING;
+
private FlowRuleProviderService providerService;
private final InternalFlowProvider listener = new InternalFlowProvider();
@@ -111,7 +123,12 @@ public class OpenFlowRuleProvider extends AbstractProvider
private Cache<Long, InternalCacheEntry> pendingBatches;
private final Timer timer = new Timer("onos-openflow-collector");
+ private final Map<Dpid, FlowStatsCollector> simpleCollectors = Maps.newHashMap();
+
+ // NewAdaptiveFlowStatsCollector Set
+ private final Map<Dpid, NewAdaptiveFlowStatsCollector> afsCollectors = Maps.newHashMap();
private final Map<Dpid, FlowStatsCollector> collectors = Maps.newHashMap();
+ private final Map<Dpid, TableStatisticsCollector> tableStatsCollectors = Maps.newHashMap();
/**
* Creates an OpenFlow host provider.
@@ -128,9 +145,11 @@ public class OpenFlowRuleProvider extends AbstractProvider
controller.addEventListener(listener);
pendingBatches = createBatchCache();
+
createCollectors();
- log.info("Started");
+ log.info("Started with flowPollFrequency = {}, adaptiveFlowSampling = {}",
+ flowPollFrequency, adaptiveFlowSampling);
}
@Deactivate
@@ -161,6 +180,20 @@ public class OpenFlowRuleProvider extends AbstractProvider
}
log.info("Settings: flowPollFrequency={}", flowPollFrequency);
+
+ boolean newAdaptiveFlowSampling;
+ String s = get(properties, "adaptiveFlowSampling");
+ newAdaptiveFlowSampling = isNullOrEmpty(s) ? adaptiveFlowSampling : Boolean.parseBoolean(s.trim());
+
+ if (newAdaptiveFlowSampling != adaptiveFlowSampling) {
+ // stop previous collector
+ stopCollectors();
+ adaptiveFlowSampling = newAdaptiveFlowSampling;
+ // create new collectors
+ createCollectors();
+ }
+
+ log.info("Settings: adaptiveFlowSampling={}", adaptiveFlowSampling);
}
private Cache<Long, InternalCacheEntry> createBatchCache() {
@@ -179,19 +212,43 @@ public class OpenFlowRuleProvider extends AbstractProvider
}
private void createCollector(OpenFlowSwitch sw) {
- FlowStatsCollector fsc = new FlowStatsCollector(timer, sw, flowPollFrequency);
- fsc.start();
- collectors.put(new Dpid(sw.getId()), fsc);
+ if (adaptiveFlowSampling) {
+ // NewAdaptiveFlowStatsCollector Constructor
+ NewAdaptiveFlowStatsCollector fsc = new NewAdaptiveFlowStatsCollector(sw, flowPollFrequency);
+ fsc.start();
+ afsCollectors.put(new Dpid(sw.getId()), fsc);
+ } else {
+ FlowStatsCollector fsc = new FlowStatsCollector(timer, sw, flowPollFrequency);
+ fsc.start();
+ simpleCollectors.put(new Dpid(sw.getId()), fsc);
+ }
+ TableStatisticsCollector tsc = new TableStatisticsCollector(timer, sw, flowPollFrequency);
+ tsc.start();
+ tableStatsCollectors.put(new Dpid(sw.getId()), tsc);
}
private void stopCollectors() {
- collectors.values().forEach(FlowStatsCollector::stop);
- collectors.clear();
+ if (adaptiveFlowSampling) {
+ // NewAdaptiveFlowStatsCollector Destructor
+ afsCollectors.values().forEach(NewAdaptiveFlowStatsCollector::stop);
+ afsCollectors.clear();
+ } else {
+ simpleCollectors.values().forEach(FlowStatsCollector::stop);
+ simpleCollectors.clear();
+ }
+ tableStatsCollectors.values().forEach(TableStatisticsCollector::stop);
+ tableStatsCollectors.clear();
}
private void adjustRate() {
DefaultLoad.setPollInterval(flowPollFrequency);
- collectors.values().forEach(fsc -> fsc.adjustPollInterval(flowPollFrequency));
+ if (adaptiveFlowSampling) {
+ // NewAdaptiveFlowStatsCollector calAndPollInterval
+ afsCollectors.values().forEach(fsc -> fsc.adjustCalAndPollInterval(flowPollFrequency));
+ } else {
+ simpleCollectors.values().forEach(fsc -> fsc.adjustPollInterval(flowPollFrequency));
+ }
+ tableStatsCollectors.values().forEach(tsc -> tsc.adjustPollInterval(flowPollFrequency));
}
@Override
@@ -202,8 +259,9 @@ public class OpenFlowRuleProvider extends AbstractProvider
}
private void applyRule(FlowRule flowRule) {
- OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId()
- .uri()));
+ Dpid dpid = Dpid.dpid(flowRule.deviceId().uri());
+ OpenFlowSwitch sw = controller.getSwitch(dpid);
+
FlowRuleExtPayLoad flowRuleExtPayLoad = flowRule.payLoad();
if (hasPayload(flowRuleExtPayLoad)) {
OFMessage msg = new ThirdPartyMessage(flowRuleExtPayLoad.payLoad());
@@ -212,6 +270,14 @@ public class OpenFlowRuleProvider extends AbstractProvider
}
sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
Optional.empty()).buildFlowAdd());
+
+ if (adaptiveFlowSampling) {
+ // Add TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
+ NewAdaptiveFlowStatsCollector collector = afsCollectors.get(dpid);
+ if (collector != null) {
+ collector.addWithFlowRule(flowRule);
+ }
+ }
}
@Override
@@ -222,8 +288,9 @@ public class OpenFlowRuleProvider extends AbstractProvider
}
private void removeRule(FlowRule flowRule) {
- OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId()
- .uri()));
+ Dpid dpid = Dpid.dpid(flowRule.deviceId().uri());
+ OpenFlowSwitch sw = controller.getSwitch(dpid);
+
FlowRuleExtPayLoad flowRuleExtPayLoad = flowRule.payLoad();
if (hasPayload(flowRuleExtPayLoad)) {
OFMessage msg = new ThirdPartyMessage(flowRuleExtPayLoad.payLoad());
@@ -232,6 +299,14 @@ public class OpenFlowRuleProvider extends AbstractProvider
}
sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
Optional.empty()).buildFlowDel());
+
+ if (adaptiveFlowSampling) {
+ // Remove TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
+ NewAdaptiveFlowStatsCollector collector = afsCollectors.get(dpid);
+ if (collector != null) {
+ collector.removeFlows(flowRule);
+ }
+ }
}
@Override
@@ -242,11 +317,12 @@ public class OpenFlowRuleProvider extends AbstractProvider
@Override
public void executeBatch(FlowRuleBatchOperation batch) {
+ checkNotNull(batch);
pendingBatches.put(batch.id(), new InternalCacheEntry(batch));
- OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(batch.deviceId()
- .uri()));
+ Dpid dpid = Dpid.dpid(batch.deviceId().uri());
+ OpenFlowSwitch sw = controller.getSwitch(dpid);
OFFlowMod mod;
for (FlowRuleBatchEntry fbe : batch.getOperations()) {
// flow is the third party privacy flow
@@ -257,21 +333,35 @@ public class OpenFlowRuleProvider extends AbstractProvider
sw.sendMsg(msg);
continue;
}
- FlowModBuilder builder = FlowModBuilder.builder(fbe.target(), sw
- .factory(), Optional.of(batch.id()));
+ FlowModBuilder builder =
+ FlowModBuilder.builder(fbe.target(), sw.factory(), Optional.of(batch.id()));
+ NewAdaptiveFlowStatsCollector collector = afsCollectors.get(dpid);
switch (fbe.operator()) {
case ADD:
mod = builder.buildFlowAdd();
+ if (adaptiveFlowSampling && collector != null) {
+ // Add TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
+ collector.addWithFlowRule(fbe.target());
+ }
break;
case REMOVE:
mod = builder.buildFlowDel();
+ if (adaptiveFlowSampling && collector != null) {
+ // Remove TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
+ collector.removeFlows(fbe.target());
+ }
break;
case MODIFY:
mod = builder.buildFlowMod();
+ if (adaptiveFlowSampling && collector != null) {
+ // Add or Update TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
+ // afsCollectors.get(dpid).addWithFlowRule(fbe.target()); //check if add is good or not
+ collector.addOrUpdateFlows((FlowEntry) fbe.target());
+ }
break;
default:
log.error("Unsupported batch operation {}; skipping flowmod {}",
- fbe.operator(), fbe);
+ fbe.operator(), fbe);
continue;
}
sw.sendMsg(mod);
@@ -292,14 +382,28 @@ public class OpenFlowRuleProvider extends AbstractProvider
@Override
public void switchAdded(Dpid dpid) {
+
+ OpenFlowSwitch sw = controller.getSwitch(dpid);
+
createCollector(controller.getSwitch(dpid));
}
@Override
public void switchRemoved(Dpid dpid) {
- FlowStatsCollector collector = collectors.remove(dpid);
- if (collector != null) {
- collector.stop();
+ if (adaptiveFlowSampling) {
+ NewAdaptiveFlowStatsCollector collector = afsCollectors.remove(dpid);
+ if (collector != null) {
+ collector.stop();
+ }
+ } else {
+ FlowStatsCollector collector = simpleCollectors.remove(dpid);
+ if (collector != null) {
+ collector.stop();
+ }
+ }
+ TableStatisticsCollector tsc = tableStatsCollectors.remove(dpid);
+ if (tsc != null) {
+ tsc.stop();
}
}
@@ -321,10 +425,20 @@ public class OpenFlowRuleProvider extends AbstractProvider
FlowEntry fr = new FlowEntryBuilder(dpid, removed).build();
providerService.flowRemoved(fr);
+
+ if (adaptiveFlowSampling) {
+ // Removed TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
+ NewAdaptiveFlowStatsCollector collector = afsCollectors.get(dpid);
+ if (collector != null) {
+ collector.flowRemoved(fr);
+ }
+ }
break;
case STATS_REPLY:
if (((OFStatsReply) msg).getStatsType() == OFStatsType.FLOW) {
pushFlowMetrics(dpid, (OFFlowStatsReply) msg);
+ } else if (((OFStatsReply) msg).getStatsType() == OFStatsType.TABLE) {
+ pushTableStatistics(dpid, (OFTableStatsReply) msg);
}
break;
case BARRIER_REPLY:
@@ -370,11 +484,10 @@ public class OpenFlowRuleProvider extends AbstractProvider
+ " tell us which one.");
}
}
- break;
+
default:
log.debug("Unhandled message type: {}", msg.getType());
}
-
}
@Override
@@ -386,13 +499,68 @@ public class OpenFlowRuleProvider extends AbstractProvider
private void pushFlowMetrics(Dpid dpid, OFFlowStatsReply replies) {
DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
- OpenFlowSwitch sw = controller.getSwitch(dpid);
List<FlowEntry> flowEntries = replies.getEntries().stream()
.map(entry -> new FlowEntryBuilder(dpid, entry).build())
.collect(Collectors.toList());
- providerService.pushFlowMetrics(did, flowEntries);
+ if (adaptiveFlowSampling) {
+ NewAdaptiveFlowStatsCollector afsc = afsCollectors.get(dpid);
+
+ synchronized (afsc) {
+ if (afsc.getFlowMissingXid() != NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID) {
+ log.debug("OpenFlowRuleProvider:pushFlowMetrics, flowMissingXid={}, "
+ + "OFFlowStatsReply Xid={}, for {}",
+ afsc.getFlowMissingXid(), replies.getXid(), dpid);
+ }
+
+ // Check that OFFlowStatsReply Xid is same with the one of OFFlowStatsRequest?
+ if (afsc.getFlowMissingXid() != NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID) {
+ if (afsc.getFlowMissingXid() == replies.getXid()) {
+ // call entire flow stats update with flowMissing synchronization.
+ // used existing pushFlowMetrics
+ providerService.pushFlowMetrics(did, flowEntries);
+ }
+ // reset flowMissingXid to NO_FLOW_MISSING_XID
+ afsc.setFlowMissingXid(NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID);
+
+ } else {
+ // call individual flow stats update
+ providerService.pushFlowMetricsWithoutFlowMissing(did, flowEntries);
+ }
+
+ // Update TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
+ afsc.pushFlowMetrics(flowEntries);
+ }
+ } else {
+ // call existing entire flow stats update with flowMissing synchronization
+ providerService.pushFlowMetrics(did, flowEntries);
+ }
+ }
+
+ private void pushTableStatistics(Dpid dpid, OFTableStatsReply replies) {
+
+ DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
+ List<TableStatisticsEntry> tableStatsEntries = replies.getEntries().stream()
+ .map(entry -> buildTableStatistics(did, entry))
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ providerService.pushTableStatistics(did, tableStatsEntries);
+ }
+
+ private TableStatisticsEntry buildTableStatistics(DeviceId deviceId,
+ OFTableStatsEntry ofEntry) {
+ TableStatisticsEntry entry = null;
+ if (ofEntry != null) {
+ entry = new DefaultTableStatisticsEntry(deviceId,
+ ofEntry.getTableId().getValue(),
+ ofEntry.getActiveCount(),
+ ofEntry.getLookupCount().getValue(),
+ ofEntry.getMatchedCount().getValue());
+ }
+
+ return entry;
+
}
}
diff --git a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/TableStatisticsCollector.java b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/TableStatisticsCollector.java
new file mode 100644
index 00000000..922a470a
--- /dev/null
+++ b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/TableStatisticsCollector.java
@@ -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.provider.of.flow.impl;
+
+import org.onlab.util.SharedExecutors;
+import org.onosproject.openflow.controller.OpenFlowSwitch;
+import org.onosproject.openflow.controller.RoleState;
+import org.projectfloodlight.openflow.protocol.OFTableStatsRequest;
+import org.slf4j.Logger;
+
+import java.util.Timer;
+import java.util.TimerTask;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Collects Table statistics for the specified switch.
+ */
+class TableStatisticsCollector {
+
+ private final Logger log = getLogger(getClass());
+
+ public static final int SECONDS = 1000;
+
+ private final OpenFlowSwitch sw;
+ private Timer timer;
+ private TimerTask task;
+
+ private int pollInterval;
+
+ /**
+ * Creates a new table statistics collector for the given switch and poll frequency.
+ *
+ * @param timer timer to use for scheduling
+ * @param sw switch to pull
+ * @param pollInterval poll frequency in seconds
+ */
+ TableStatisticsCollector(Timer timer, OpenFlowSwitch sw, int pollInterval) {
+ this.timer = timer;
+ this.sw = sw;
+ this.pollInterval = pollInterval;
+ }
+
+ /**
+ * Adjusts poll frequency.
+ *
+ * @param pollInterval poll frequency in seconds
+ */
+ synchronized void adjustPollInterval(int pollInterval) {
+ this.pollInterval = pollInterval;
+ task.cancel();
+ task = new InternalTimerTask();
+ timer.scheduleAtFixedRate(task, pollInterval * SECONDS, pollInterval * 1000);
+ }
+
+ private class InternalTimerTask extends TimerTask {
+ @Override
+ public void run() {
+ if (sw.getRole() == RoleState.MASTER) {
+ log.trace("Collecting stats for {}", sw.getStringId());
+ OFTableStatsRequest request = sw.factory().buildTableStatsRequest()
+ .build();
+ sw.sendMsg(request);
+ }
+ }
+ }
+
+ public synchronized void start() {
+ // Initially start polling quickly. Then drop down to configured value
+ log.debug("Starting Table Stats collection thread for {}", sw.getStringId());
+ task = new InternalTimerTask();
+ SharedExecutors.getTimer().scheduleAtFixedRate(task, 1 * SECONDS,
+ pollInterval * SECONDS);
+ }
+
+ public synchronized void stop() {
+ log.debug("Stopping Table Stats collection thread for {}", sw.getStringId());
+ task.cancel();
+ task = null;
+ }
+
+}
diff --git a/framework/src/onos/providers/ovsdb/device/src/test/java/org/onosproject/ovsdb/providers/device/OvsdbDeviceProviderTest.java b/framework/src/onos/providers/ovsdb/device/src/test/java/org/onosproject/ovsdb/providers/device/OvsdbDeviceProviderTest.java
index 5e4c5677..7663a64d 100644
--- a/framework/src/onos/providers/ovsdb/device/src/test/java/org/onosproject/ovsdb/providers/device/OvsdbDeviceProviderTest.java
+++ b/framework/src/onos/providers/ovsdb/device/src/test/java/org/onosproject/ovsdb/providers/device/OvsdbDeviceProviderTest.java
@@ -27,6 +27,7 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.onlab.packet.IpAddress;
+import org.onlab.packet.TpPort;
import org.onosproject.net.DeviceId;
import org.onosproject.net.MastershipRole;
import org.onosproject.net.device.DeviceDescription;
@@ -193,6 +194,10 @@ public class OvsdbDeviceProviderTest {
return null;
}
+ @Override
+ public void connect(IpAddress ip, TpPort port) {
+
+ }
}
}
diff --git a/framework/src/onos/providers/ovsdb/host/src/test/java/org/onosproject/ovsdb/provider/host/OvsdbHostProviderTest.java b/framework/src/onos/providers/ovsdb/host/src/test/java/org/onosproject/ovsdb/provider/host/OvsdbHostProviderTest.java
index ad720c85..01e07dd8 100644
--- a/framework/src/onos/providers/ovsdb/host/src/test/java/org/onosproject/ovsdb/provider/host/OvsdbHostProviderTest.java
+++ b/framework/src/onos/providers/ovsdb/host/src/test/java/org/onosproject/ovsdb/provider/host/OvsdbHostProviderTest.java
@@ -24,7 +24,9 @@ import java.util.Set;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
+import org.onlab.packet.TpPort;
import org.onosproject.net.DeviceId;
import org.onosproject.net.HostId;
import org.onosproject.net.host.HostDescription;
@@ -159,6 +161,11 @@ public class OvsdbHostProviderTest {
removeCount++;
}
+ @Override
+ public void removeIpFromHost(HostId hostId, IpAddress ipAddress) {
+
+ }
+
}
private class OvsdbControllerTest implements OvsdbController {
@@ -195,5 +202,10 @@ public class OvsdbHostProviderTest {
public OvsdbClientService getOvsdbClient(OvsdbNodeId nodeId) {
return null;
}
+
+ @Override
+ public void connect(IpAddress ip, TpPort port) {
+
+ }
}
}
diff --git a/framework/src/onos/tools/build/conf/pom.xml b/framework/src/onos/tools/build/conf/pom.xml
index e4f8e9dc..29e4dea0 100644
--- a/framework/src/onos/tools/build/conf/pom.xml
+++ b/framework/src/onos/tools/build/conf/pom.xml
@@ -27,7 +27,7 @@
<groupId>org.onosproject</groupId>
<artifactId>onos-build-conf</artifactId>
- <version>1.0</version>
+ <version>1.1</version>
<description>Various ONOS build settings</description>
<properties>
diff --git a/framework/src/onos/tools/build/conf/src/main/resources/onos/checkstyle.xml b/framework/src/onos/tools/build/conf/src/main/resources/onos/checkstyle.xml
index 2908c891..1bb3b0bf 100644
--- a/framework/src/onos/tools/build/conf/src/main/resources/onos/checkstyle.xml
+++ b/framework/src/onos/tools/build/conf/src/main/resources/onos/checkstyle.xml
@@ -229,7 +229,10 @@
<!-- ONOS alows declarations inside of switch case blocks -->
<property name="allowInSwitchCase" value="true"/>
</module>
- <module name="EmptyBlock"/>
+ <module name="EmptyBlock">
+ <!-- allow empty block, as long as there's some comment -->
+ <property name="option" value="text"/>
+ </module>
<module name="LeftCurly"/>
<module name="NeedBraces"/>
<module name="RightCurly"/>
diff --git a/framework/src/onos/tools/build/docker/Dockerfile b/framework/src/onos/tools/build/docker/Dockerfile
index fd61ad86..ee9666ab 100644
--- a/framework/src/onos/tools/build/docker/Dockerfile
+++ b/framework/src/onos/tools/build/docker/Dockerfile
@@ -45,11 +45,11 @@ RUN mkdir onos && \
# Ports
-# 6633 - OpenFlow
+# 6653 - OpenFlow
# 8181 - GUI
# 8101 - ONOS CLI
# 9876 - ONOS CLUSTER COMMUNICATION
-EXPOSE 6633 8181 8101 9876
+EXPOSE 6653 8181 8101 9876
# Get ready to run command
WORKDIR /root/onos
diff --git a/framework/src/onos/tools/build/onos-package b/framework/src/onos/tools/build/onos-package
index 32794457..5566e60d 100755
--- a/framework/src/onos/tools/build/onos-package
+++ b/framework/src/onos/tools/build/onos-package
@@ -28,6 +28,10 @@ function build_stage_dir() {
[ -f $KARAF_TAR ] && tar zxf $KARAF_TAR && rm -rf $ONOS_STAGE/$KARAF_DIST/demos
mkdir bin
+ # Patch the log-file size in place to increase it to 10 MB
+ perl -pi.old -e "s/maxFileSize=1MB/maxFileSize=10MB/g" \
+ $ONOS_STAGE/$KARAF_DIST/etc/org.ops4j.pax.logging.cfg
+
# Stage the ONOS admin scripts and patch in Karaf service wrapper extras
cp -r $ONOS_ROOT/tools/package/bin .
cp -r $ONOS_ROOT/tools/package/init $ONOS_STAGE/init
diff --git a/framework/src/onos/tools/dev/bash_profile b/framework/src/onos/tools/dev/bash_profile
index 5e161ccd..f39c2ce1 100644
--- a/framework/src/onos/tools/dev/bash_profile
+++ b/framework/src/onos/tools/dev/bash_profile
@@ -148,41 +148,41 @@ function nuke {
spy "$@" | cut -c7-11 | xargs kill
}
-# Edit a cell file by providing a cell name. Opens the cell file in $EDITOR.
-function vicell() {
- local apply=false
- local create=false
- local cdf=""
- local cpath="${ONOS_ROOT}/tools/test/cells/"
-
- if [ -z "$1" ] || [ "$1" = "-h" ] ; then
- printf "usage: vicell [file] [options]\n\noptions:\n"
- printf "\t-a: apply the cell after editing\n"
- printf "\t-e: [editor] set EDITOR to [editor] (default *vi*)\n"
- printf "\t-c: create cell file if none exist\n\n"
- return 1
- fi
-
- while [ $# -gt 0 ]; do
- case "$1" in
- -a) apply=true ;;
- -e) EDITOR=$2; shift ;;
- -c) create=true ;;
- *) cdf="$1" ;;
- esac
- shift
- done
-
- if [ ! -e "${cpath}${cdf}" ] && [ "$create" = "false" ]; then
- printf "${cdf} : no such cell\n" && return 1
- fi
-
- if [ -z "${EDITOR}" ] || [ -x "$(which ${EDITOR})" ]; then
- unset EDITOR && vi ${cpath}${cdf}
- else
- $EDITOR ${cpath}${cdf}
- fi
- ($apply) && cell ${cdf}
+# Edit a cell file by providing a cell name; opens the cell file in $EDITOR.
+function vicell {
+ local apply=false
+ local create=false
+ local cdf=""
+ local cpath="${ONOS_ROOT}/tools/test/cells/"
+
+ if [ -z "$1" ] || [ "$1" = "-h" ] ; then
+ printf "usage: vicell [file] [options]\n\noptions:\n"
+ printf "\t-a: apply the cell after editing\n"
+ printf "\t-e: [editor] set EDITOR to [editor] (default *vi*)\n"
+ printf "\t-c: create cell file if none exist\n\n"
+ return 1
+ fi
+
+ while [ $# -gt 0 ]; do
+ case "$1" in
+ -a) apply=true ;;
+ -e) EDITOR=$2; shift ;;
+ -c) create=true ;;
+ *) cdf="$1" ;;
+ esac
+ shift
+ done
+
+ if [ ! -e "${cpath}${cdf}" ] && [ "$create" = "false" ]; then
+ printf "${cdf} : no such cell\n" && return 1
+ fi
+
+ if [ -z "${EDITOR}" ] || [ -x "$(which ${EDITOR})" ]; then
+ unset EDITOR && vi ${cpath}${cdf}
+ else
+ $EDITOR ${cpath}${cdf}
+ fi
+ ($apply) && cell ${cdf}
}
# autocomplete for certain utilities
diff --git a/framework/src/onos/tools/dev/bin/onos-create-app b/framework/src/onos/tools/dev/bin/onos-create-app
index 65b00b65..454bcd6e 100755
--- a/framework/src/onos/tools/dev/bin/onos-create-app
+++ b/framework/src/onos/tools/dev/bin/onos-create-app
@@ -11,7 +11,7 @@ type=${1:-bundle}
[ $type = app ] && archetype=bundle || archetype=$type
if [ "$1" = "-?" -o "$1" = "-h" -o "$1" = "--help" ]; then
- echo "usage: $(basename $0) {app|bundle|ui|cli|api} groupId artifactId version package mvn-options"
+ echo "usage: $(basename $0) {app|bundle|ui|uitab|uitopo|cli|api} groupId artifactId version package mvn-options"
echo " All arguments are optional"
exit 1
fi
diff --git a/framework/src/onos/tools/dev/header.txt b/framework/src/onos/tools/dev/header.txt
index 6c18c92c..5b9dcb84 100644
--- a/framework/src/onos/tools/dev/header.txt
+++ b/framework/src/onos/tools/dev/header.txt
@@ -1,4 +1,4 @@
-Copyright $today.year Open Networking Laboratory
+Copyright 2014-$today.year 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.
diff --git a/framework/src/onos/tools/package/archetypes/pom.xml b/framework/src/onos/tools/package/archetypes/pom.xml
index 525a2f68..12a23229 100644
--- a/framework/src/onos/tools/package/archetypes/pom.xml
+++ b/framework/src/onos/tools/package/archetypes/pom.xml
@@ -38,6 +38,8 @@
<module>bundle</module>
<module>cli</module>
<module>ui</module>
+ <module>uitab</module>
+ <module>uitopo</module>
</modules>
<build>
diff --git a/framework/src/onos/tools/package/archetypes/ui/pom.xml b/framework/src/onos/tools/package/archetypes/ui/pom.xml
index 8dd3a8e0..9bebe9da 100644
--- a/framework/src/onos/tools/package/archetypes/ui/pom.xml
+++ b/framework/src/onos/tools/package/archetypes/ui/pom.xml
@@ -26,6 +26,6 @@
<artifactId>onos-ui-archetype</artifactId>
<packaging>maven-archetype</packaging>
- <description>ONOS UI overlay archetype</description>
+ <description>ONOS UI Custom-View overlay archetype</description>
</project>
diff --git a/framework/src/onos/tools/package/archetypes/ui/src/main/resources/archetype-resources/pom.xml b/framework/src/onos/tools/package/archetypes/ui/src/main/resources/archetype-resources/pom.xml
index 2e1f091e..d67c181a 100644
--- a/framework/src/onos/tools/package/archetypes/ui/src/main/resources/archetype-resources/pom.xml
+++ b/framework/src/onos/tools/package/archetypes/ui/src/main/resources/archetype-resources/pom.xml
@@ -22,7 +22,7 @@
<version>${version}</version>
<packaging>bundle</packaging>
- <description>ONOS OSGi UI bundle archetype</description>
+ <description>ONOS OSGi UI Custom-View bundle archetype</description>
<url>http://onosproject.org</url>
<properties>
diff --git a/framework/src/onos/tools/package/archetypes/ui/src/main/resources/archetype-resources/src/main/java/AppUiComponent.java b/framework/src/onos/tools/package/archetypes/ui/src/main/resources/archetype-resources/src/main/java/AppUiComponent.java
index f40bcb5f..e44b34d5 100644
--- a/framework/src/onos/tools/package/archetypes/ui/src/main/resources/archetype-resources/src/main/java/AppUiComponent.java
+++ b/framework/src/onos/tools/package/archetypes/ui/src/main/resources/archetype-resources/src/main/java/AppUiComponent.java
@@ -34,11 +34,14 @@ import org.slf4j.LoggerFactory;
import java.util.List;
/**
- * Skeletal ONOS UI application component.
+ * Skeletal ONOS UI Custom-View application component.
*/
@Component(immediate = true)
public class AppUiComponent {
+ private static final String VIEW_ID = "sampleCustom";
+ private static final String VIEW_TEXT = "Sample Custom";
+
private final Logger log = LoggerFactory.getLogger(getClass());
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -46,7 +49,7 @@ public class AppUiComponent {
// List of application views
private final List<UiView> uiViews = ImmutableList.of(
- new UiView(UiView.Category.OTHER, "sample", "Sample")
+ new UiView(UiView.Category.OTHER, VIEW_ID, VIEW_TEXT)
);
// Factory for UI message handlers
diff --git a/framework/src/onos/tools/package/archetypes/ui/src/main/resources/archetype-resources/src/main/java/AppUiMessageHandler.java b/framework/src/onos/tools/package/archetypes/ui/src/main/resources/archetype-resources/src/main/java/AppUiMessageHandler.java
index d9d68b53..d6486328 100644
--- a/framework/src/onos/tools/package/archetypes/ui/src/main/resources/archetype-resources/src/main/java/AppUiMessageHandler.java
+++ b/framework/src/onos/tools/package/archetypes/ui/src/main/resources/archetype-resources/src/main/java/AppUiMessageHandler.java
@@ -22,168 +22,56 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.ImmutableSet;
import org.onosproject.ui.RequestHandler;
import org.onosproject.ui.UiMessageHandler;
-import org.onosproject.ui.table.TableModel;
-import org.onosproject.ui.table.TableRequestHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.lang.Override;
-import java.util.ArrayList;
import java.util.Collection;
-import java.util.List;
/**
- * Skeletal ONOS UI message handler.
- * <p>
- * This example specifically supporting a "table" view.
+ * Skeletal ONOS UI Custom-View message handler.
*/
public class AppUiMessageHandler extends UiMessageHandler {
- private static final String SAMPLE_DATA_REQ = "sampleDataRequest";
- private static final String SAMPLE_DATA_RESP = "sampleDataResponse";
- private static final String SAMPLES = "samples";
+ private static final String SAMPLE_CUSTOM_DATA_REQ = "sampleCustomDataRequest";
+ private static final String SAMPLE_CUSTOM_DATA_RESP = "sampleCustomDataResponse";
- private static final String SAMPLE_DETAIL_REQ = "sampleDetailsRequest";
- private static final String SAMPLE_DETAIL_RESP = "sampleDetailsResponse";
- private static final String DETAILS = "details";
-
- private static final String ID = "id";
- private static final String LABEL = "label";
- private static final String CODE = "code";
- private static final String COMMENT = "comment";
- private static final String RESULT = "result";
-
- private static final String[] COLUMN_IDS = { ID, LABEL, CODE };
+ private static final String NUMBER = "number";
+ private static final String SQUARE = "square";
+ private static final String CUBE = "cube";
+ private static final String MESSAGE = "message";
+ private static final String MSG_FORMAT = "Next incrememt is %d units";
private final Logger log = LoggerFactory.getLogger(getClass());
+ private long someNumber = 1;
+ private long someIncrement = 1;
@Override
protected Collection<RequestHandler> createRequestHandlers() {
return ImmutableSet.of(
- new SampleDataRequestHandler(),
- new SampleDetailRequestHandler()
+ new SampleCustomDataRequestHandler()
);
}
- // handler for sample table requests
- private final class SampleDataRequestHandler extends TableRequestHandler {
-
- private SampleDataRequestHandler() {
- super(SAMPLE_DATA_REQ, SAMPLE_DATA_RESP, SAMPLES);
- }
-
- // if necessary, override defaultColumnId() -- if it isn't "id"
+ // handler for sample data requests
+ private final class SampleCustomDataRequestHandler extends RequestHandler {
- @Override
- protected String[] getColumnIds() {
- return COLUMN_IDS;
- }
-
- @Override
- protected void populateTable(TableModel tm, ObjectNode payload) {
- // === set custom column cell formatters/comparators if need be...
- // tm.setFormatter(CODE, new CodeFormatter());
- // tm.setComparator(CODE, new CodeComparator());
-
- // === retrieve table row items from some service...
- // SomeService ss = get(SomeService.class);
- // List<Item> items = ss.getItems()
-
- // fake data for demonstration purposes...
- List<Item> items = getItems();
- for (Item item: items) {
- populateRow(tm.addRow(), item);
- }
- }
-
- private void populateRow(TableModel.Row row, Item item) {
- row.cell(ID, item.id())
- .cell(LABEL, item.label())
- .cell(CODE, item.code());
- }
- }
-
-
- // handler for sample item details requests
- private final class SampleDetailRequestHandler extends RequestHandler {
-
- private SampleDetailRequestHandler() {
- super(SAMPLE_DETAIL_REQ);
+ private SampleCustomDataRequestHandler() {
+ super(SAMPLE_CUSTOM_DATA_REQ);
}
@Override
public void process(long sid, ObjectNode payload) {
- String id = string(payload, ID, "(none)");
-
- // SomeService ss = get(SomeService.class);
- // Item item = ss.getItemDetails(id)
-
- // fake data for demonstration purposes...
- Item item = getItem(id);
-
- ObjectNode rootNode = MAPPER.createObjectNode();
- ObjectNode data = MAPPER.createObjectNode();
- rootNode.set(DETAILS, data);
-
- if (item == null) {
- rootNode.put(RESULT, "Item with id '" + id + "' not found");
- log.warn("attempted to get item detail for id '{}'", id);
-
- } else {
- rootNode.put(RESULT, "Found item with id '" + id + "'");
-
- data.put(ID, item.id());
- data.put(LABEL, item.label());
- data.put(CODE, item.code());
- data.put(COMMENT, "Some arbitrary comment");
- }
-
- sendMessage(SAMPLE_DETAIL_RESP, 0, rootNode);
- }
- }
-
-
- // ===================================================================
- // NOTE: The code below this line is to create fake data for this
- // sample code. Normally you would use existing services to
- // provide real data.
-
- // Lookup a single item.
- private static Item getItem(String id) {
- // We realize this code is really inefficient, but
- // it suffices for our purposes of demonstration...
- for (Item item : getItems()) {
- if (item.id().equals(id)) {
- return item;
- }
+ someIncrement++;
+ someNumber += someIncrement;
+ log.debug("Computing data for {}...", someNumber);
+
+ ObjectNode result = objectNode();
+ result.put(NUMBER, someNumber);
+ result.put(SQUARE, someNumber * someNumber);
+ result.put(CUBE, someNumber * someNumber * someNumber);
+ result.put(MESSAGE, String.format(MSG_FORMAT, someIncrement + 1));
+ sendMessage(SAMPLE_CUSTOM_DATA_RESP, 0, result);
}
- return null;
- }
-
- // Produce a list of items.
- private static List<Item> getItems() {
- List<Item> items = new ArrayList<>();
- items.add(new Item("item-1", "foo", 42));
- items.add(new Item("item-2", "bar", 99));
- items.add(new Item("item-3", "baz", 65));
- return items;
- }
-
- // Simple model class to provide sample data
- private static class Item {
- private final String id;
- private final String label;
- private final int code;
-
- Item(String id, String label, int code) {
- this.id = id;
- this.label = label;
- this.code = code;
- }
-
- String id() { return id; }
- String label() { return label; }
- int code() { return code; }
}
} \ No newline at end of file
diff --git a/framework/src/onos/tools/package/archetypes/ui/src/main/resources/archetype-resources/src/main/resources/app/view/sampleCustom/sampleCustom.css b/framework/src/onos/tools/package/archetypes/ui/src/main/resources/archetype-resources/src/main/resources/app/view/sampleCustom/sampleCustom.css
new file mode 100644
index 00000000..ffeac0aa
--- /dev/null
+++ b/framework/src/onos/tools/package/archetypes/ui/src/main/resources/archetype-resources/src/main/resources/app/view/sampleCustom/sampleCustom.css
@@ -0,0 +1,48 @@
+/* css for sample app custom view */
+
+#ov-sample-custom {
+ padding: 20px;
+}
+.light #ov-sample-custom {
+ color: navy;
+}
+.dark #ov-sample-custom {
+ color: #88f;
+}
+
+#ov-sample-custom .button-panel {
+ margin: 10px;
+ width: 200px;
+}
+
+.light #ov-sample-custom .button-panel {
+ background-color: #ccf;
+}
+.dark #ov-sample-custom .button-panel {
+ background-color: #444;
+}
+
+#ov-sample-custom .my-button {
+ cursor: pointer;
+ padding: 4px;
+ text-align: center;
+}
+
+.light #ov-sample-custom .my-button {
+ color: white;
+ background-color: #99d;
+}
+.dark #ov-sample-custom .my-button {
+ color: black;
+ background-color: #aaa;
+}
+
+#ov-sample-custom .number {
+ font-size: 140%;
+ text-align: right;
+}
+
+#ov-sample-custom .quote {
+ margin: 10px 20px;
+ font-style: italic;
+} \ No newline at end of file
diff --git a/framework/src/onos/tools/package/archetypes/ui/src/main/resources/archetype-resources/src/main/resources/app/view/sampleCustom/sampleCustom.html b/framework/src/onos/tools/package/archetypes/ui/src/main/resources/archetype-resources/src/main/resources/app/view/sampleCustom/sampleCustom.html
new file mode 100644
index 00000000..d3d79a10
--- /dev/null
+++ b/framework/src/onos/tools/package/archetypes/ui/src/main/resources/archetype-resources/src/main/resources/app/view/sampleCustom/sampleCustom.html
@@ -0,0 +1,32 @@
+<!-- partial HTML -->
+<div id="ov-sample-custom">
+ <div class="button-panel">
+ <div class="my-button" ng-click="getData()">
+ Fetch Data
+ </div>
+ </div>
+
+ <div class="data-panel">
+ <table>
+ <tr>
+ <td> Number </td>
+ <td class="number"> {{data.number}} </td>
+ </tr>
+ <tr>
+ <td> Square </td>
+ <td class="number"> {{data.square}} </td>
+ </tr>
+ <tr>
+ <td> Cube </td>
+ <td class="number"> {{data.cube}} </td>
+ </tr>
+ </table>
+
+ <p>
+ A message from our sponsors:
+ </p>
+ <p>
+ <span class="quote"> {{data.message}} </span>
+ </p>
+ </div>
+</div>
diff --git a/framework/src/onos/tools/package/archetypes/ui/src/main/resources/archetype-resources/src/main/resources/app/view/sampleCustom/sampleCustom.js b/framework/src/onos/tools/package/archetypes/ui/src/main/resources/archetype-resources/src/main/resources/app/view/sampleCustom/sampleCustom.js
new file mode 100644
index 00000000..21058640
--- /dev/null
+++ b/framework/src/onos/tools/package/archetypes/ui/src/main/resources/archetype-resources/src/main/resources/app/view/sampleCustom/sampleCustom.js
@@ -0,0 +1,69 @@
+// js for sample app custom view
+(function () {
+ 'use strict';
+
+ // injected refs
+ var $log, $scope, wss, ks;
+
+ // constants
+ var dataReq = 'sampleCustomDataRequest',
+ dataResp = 'sampleCustomDataResponse';
+
+ function addKeyBindings() {
+ var map = {
+ space: [getData, 'Fetch data from server'],
+
+ _helpFormat: [
+ ['space']
+ ]
+ };
+
+ ks.keyBindings(map);
+ }
+
+ function getData() {
+ wss.sendEvent(dataReq);
+ }
+
+ function respDataCb(data) {
+ $scope.data = data;
+ $scope.$apply();
+ }
+
+
+ angular.module('ovSampleCustom', [])
+ .controller('OvSampleCustomCtrl',
+ ['$log', '$scope', 'WebSocketService', 'KeyService',
+
+ function (_$log_, _$scope_, _wss_, _ks_) {
+ $log = _$log_;
+ $scope = _$scope_;
+ wss = _wss_;
+ ks = _ks_;
+
+ var handlers = {};
+ $scope.data = {};
+
+ // data response handler
+ handlers[dataResp] = respDataCb;
+ wss.bindHandlers(handlers);
+
+ addKeyBindings();
+
+ // custom click handler
+ $scope.getData = getData;
+
+ // get data the first time...
+ getData();
+
+ // cleanup
+ $scope.$on('$destroy', function () {
+ wss.unbindHandlers(handlers);
+ ks.unbindKeys();
+ $log.log('OvSampleCustomCtrl has been destroyed');
+ });
+
+ $log.log('OvSampleCustomCtrl has been created');
+ }]);
+
+}());
diff --git a/framework/src/onos/tools/package/archetypes/ui/src/main/resources/archetype-resources/src/main/resources/css.html b/framework/src/onos/tools/package/archetypes/ui/src/main/resources/archetype-resources/src/main/resources/css.html
index c4697256..4e7b7092 100644
--- a/framework/src/onos/tools/package/archetypes/ui/src/main/resources/archetype-resources/src/main/resources/css.html
+++ b/framework/src/onos/tools/package/archetypes/ui/src/main/resources/archetype-resources/src/main/resources/css.html
@@ -1 +1 @@
-<link rel="stylesheet" href="app/view/sample/sample.css"> \ No newline at end of file
+<link rel="stylesheet" href="app/view/sampleCustom/sampleCustom.css"> \ No newline at end of file
diff --git a/framework/src/onos/tools/package/archetypes/ui/src/main/resources/archetype-resources/src/main/resources/js.html b/framework/src/onos/tools/package/archetypes/ui/src/main/resources/archetype-resources/src/main/resources/js.html
index 7cacc707..6550b85e 100644
--- a/framework/src/onos/tools/package/archetypes/ui/src/main/resources/archetype-resources/src/main/resources/js.html
+++ b/framework/src/onos/tools/package/archetypes/ui/src/main/resources/archetype-resources/src/main/resources/js.html
@@ -1 +1 @@
-<script src="app/view/sample/sample.js"></script> \ No newline at end of file
+<script src="app/view/sampleCustom/sampleCustom.js"></script> \ No newline at end of file
diff --git a/framework/src/onos/tools/package/archetypes/uitab/pom.xml b/framework/src/onos/tools/package/archetypes/uitab/pom.xml
new file mode 100644
index 00000000..cb18f1f3
--- /dev/null
+++ b/framework/src/onos/tools/package/archetypes/uitab/pom.xml
@@ -0,0 +1,31 @@
+<?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/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-archetypes</artifactId>
+ <version>1.4.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>onos-uitab-archetype</artifactId>
+ <packaging>maven-archetype</packaging>
+
+ <description>ONOS UI Table-View overlay archetype</description>
+
+</project>
diff --git a/framework/src/onos/tools/package/archetypes/uitab/src/main/resources/META-INF/maven/archetype-metadata.xml b/framework/src/onos/tools/package/archetypes/uitab/src/main/resources/META-INF/maven/archetype-metadata.xml
new file mode 100644
index 00000000..a6273811
--- /dev/null
+++ b/framework/src/onos/tools/package/archetypes/uitab/src/main/resources/META-INF/maven/archetype-metadata.xml
@@ -0,0 +1,39 @@
+<?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.
+ -->
+<archetype-descriptor
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0 http://maven.apache.org/xsd/archetype-descriptor-1.0.0.xsd"
+ name="onos-uitab" partial="true"
+ xmlns="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <fileSets>
+ <fileSet filtered="true" packaged="true" encoding="UTF-8">
+ <directory>src/main/java</directory>
+ <includes>
+ <include>**/*.java</include>
+ </includes>
+ </fileSet>
+ <fileSet filtered="true" packaged="false" encoding="UTF-8">
+ <directory>src/main/resources</directory>
+ <includes>
+ <include>**/*.html</include>
+ <include>**/*.js</include>
+ <include>**/*.css</include>
+ </includes>
+ </fileSet>
+ </fileSets>
+</archetype-descriptor>
diff --git a/framework/src/onos/tools/package/archetypes/uitab/src/main/resources/archetype-resources/pom.xml b/framework/src/onos/tools/package/archetypes/uitab/src/main/resources/archetype-resources/pom.xml
new file mode 100644
index 00000000..05a62b27
--- /dev/null
+++ b/framework/src/onos/tools/package/archetypes/uitab/src/main/resources/archetype-resources/pom.xml
@@ -0,0 +1,140 @@
+<?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/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>${groupId}</groupId>
+ <artifactId>${artifactId}</artifactId>
+ <version>${version}</version>
+ <packaging>bundle</packaging>
+
+ <description>ONOS OSGi UI Table-View bundle archetype</description>
+ <url>http://onosproject.org</url>
+
+ <properties>
+ <onos.version>1.4.0-SNAPSHOT</onos.version>
+ <!-- Uncomment to generate ONOS app from this module.
+ <onos.app.name>org.foo.app</onos.app.name>
+ <onos.app.origin>Foo, Inc.</onos.app.origin>
+ -->
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-api</artifactId>
+ <version>${onos.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onlab-osgi</artifactId>
+ <version>${onos.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.11</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-api</artifactId>
+ <version>${onos.version}</version>
+ <scope>test</scope>
+ <classifier>tests</classifier>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.scr.annotations</artifactId>
+ <version>1.9.8</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>2.5.3</version>
+ <extensions>true</extensions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.5.1</version>
+ <configuration>
+ <source>1.8</source>
+ <target>1.8</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-scr-plugin</artifactId>
+ <version>1.20.0</version>
+ <executions>
+ <execution>
+ <id>generate-scr-srcdescriptor</id>
+ <goals>
+ <goal>scr</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <supportedProjectTypes>
+ <supportedProjectType>bundle</supportedProjectType>
+ <supportedProjectType>war</supportedProjectType>
+ </supportedProjectTypes>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-maven-plugin</artifactId>
+ <version>1.5</version>
+ <executions>
+ <execution>
+ <id>cfg</id>
+ <phase>generate-resources</phase>
+ <goals>
+ <goal>cfg</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>swagger</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>swagger</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>app</id>
+ <phase>package</phase>
+ <goals>
+ <goal>app</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/framework/src/onos/tools/package/archetypes/uitab/src/main/resources/archetype-resources/src/main/java/AppUiTableComponent.java b/framework/src/onos/tools/package/archetypes/uitab/src/main/resources/archetype-resources/src/main/java/AppUiTableComponent.java
new file mode 100644
index 00000000..263564ce
--- /dev/null
+++ b/framework/src/onos/tools/package/archetypes/uitab/src/main/resources/archetype-resources/src/main/java/AppUiTableComponent.java
@@ -0,0 +1,80 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+/*
+ * 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 ${package};
+
+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;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onosproject.ui.UiExtension;
+import org.onosproject.ui.UiExtensionService;
+import org.onosproject.ui.UiMessageHandlerFactory;
+import org.onosproject.ui.UiView;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+/**
+ * Skeletal ONOS UI Table-View application component.
+ */
+@Component(immediate = true)
+public class AppUiTableComponent {
+
+ private static final String VIEW_ID = "sampleTable";
+ private static final String VIEW_TEXT = "Sample Table";
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected UiExtensionService uiExtensionService;
+
+ // List of application views
+ private final List<UiView> uiViews = ImmutableList.of(
+ new UiView(UiView.Category.OTHER, VIEW_ID, VIEW_TEXT)
+ );
+
+ // Factory for UI message handlers
+ private final UiMessageHandlerFactory messageHandlerFactory =
+ () -> ImmutableList.of(
+ new AppUiTableMessageHandler()
+ );
+
+ // Application UI extension
+ protected UiExtension extension =
+ new UiExtension.Builder(getClass().getClassLoader(), uiViews)
+ .resourcePath(VIEW_ID)
+ .messageHandlerFactory(messageHandlerFactory)
+ .build();
+
+ @Activate
+ protected void activate() {
+ uiExtensionService.register(extension);
+ log.info("Started");
+ }
+
+ @Deactivate
+ protected void deactivate() {
+ uiExtensionService.unregister(extension);
+ log.info("Stopped");
+ }
+
+}
diff --git a/framework/src/onos/tools/package/archetypes/uitab/src/main/resources/archetype-resources/src/main/java/AppUiTableMessageHandler.java b/framework/src/onos/tools/package/archetypes/uitab/src/main/resources/archetype-resources/src/main/java/AppUiTableMessageHandler.java
new file mode 100644
index 00000000..a673f1fd
--- /dev/null
+++ b/framework/src/onos/tools/package/archetypes/uitab/src/main/resources/archetype-resources/src/main/java/AppUiTableMessageHandler.java
@@ -0,0 +1,190 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+/*
+ * 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 ${package};
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.ImmutableSet;
+import org.onosproject.ui.RequestHandler;
+import org.onosproject.ui.UiMessageHandler;
+import org.onosproject.ui.table.TableModel;
+import org.onosproject.ui.table.TableRequestHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.Override;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Skeletal ONOS UI Table-View message handler.
+ */
+public class AppUiTableMessageHandler extends UiMessageHandler {
+
+ private static final String SAMPLE_TABLE_DATA_REQ = "sampleTableDataRequest";
+ private static final String SAMPLE_TABLE_DATA_RESP = "sampleTableDataResponse";
+ private static final String SAMPLE_TABLES = "sampleTables";
+
+ private static final String SAMPLE_TABLE_DETAIL_REQ = "sampleTableDetailsRequest";
+ private static final String SAMPLE_TABLE_DETAIL_RESP = "sampleTableDetailsResponse";
+ private static final String DETAILS = "details";
+
+ private static final String ID = "id";
+ private static final String LABEL = "label";
+ private static final String CODE = "code";
+ private static final String COMMENT = "comment";
+ private static final String RESULT = "result";
+
+ private static final String[] COLUMN_IDS = { ID, LABEL, CODE };
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+
+ @Override
+ protected Collection<RequestHandler> createRequestHandlers() {
+ return ImmutableSet.of(
+ new SampleTableDataRequestHandler(),
+ new SampleTableDetailRequestHandler()
+ );
+ }
+
+ // handler for sample table requests
+ private final class SampleTableDataRequestHandler extends TableRequestHandler {
+
+ private SampleTableDataRequestHandler() {
+ super(SAMPLE_TABLE_DATA_REQ, SAMPLE_TABLE_DATA_RESP, SAMPLE_TABLES);
+ }
+
+ // if necessary, override defaultColumnId() -- if it isn't "id"
+
+ @Override
+ protected String[] getColumnIds() {
+ return COLUMN_IDS;
+ }
+
+ // if required, override createTableModel() to set column formatters / comparators
+
+ @Override
+ protected void populateTable(TableModel tm, ObjectNode payload) {
+ // === NOTE: the table model supplied here will have been created
+ // via a call to createTableModel(). To assign non-default
+ // cell formatters or comparators to the table model, override
+ // createTableModel() and set them there.
+
+ // === retrieve table row items from some service...
+ // SomeService ss = get(SomeService.class);
+ // List<Item> items = ss.getItems()
+
+ // fake data for demonstration purposes...
+ List<Item> items = getItems();
+ for (Item item: items) {
+ populateRow(tm.addRow(), item);
+ }
+ }
+
+ private void populateRow(TableModel.Row row, Item item) {
+ row.cell(ID, item.id())
+ .cell(LABEL, item.label())
+ .cell(CODE, item.code());
+ }
+ }
+
+
+ // handler for sample item details requests
+ private final class SampleTableDetailRequestHandler extends RequestHandler {
+
+ private SampleTableDetailRequestHandler() {
+ super(SAMPLE_TABLE_DETAIL_REQ);
+ }
+
+ @Override
+ public void process(long sid, ObjectNode payload) {
+ String id = string(payload, ID, "(none)");
+
+ // SomeService ss = get(SomeService.class);
+ // Item item = ss.getItemDetails(id)
+
+ // fake data for demonstration purposes...
+ Item item = getItem(id);
+
+ ObjectNode rootNode = objectNode();
+ ObjectNode data = objectNode();
+ rootNode.set(DETAILS, data);
+
+ if (item == null) {
+ rootNode.put(RESULT, "Item with id '" + id + "' not found");
+ log.warn("attempted to get item detail for id '{}'", id);
+
+ } else {
+ rootNode.put(RESULT, "Found item with id '" + id + "'");
+
+ data.put(ID, item.id());
+ data.put(LABEL, item.label());
+ data.put(CODE, item.code());
+ data.put(COMMENT, "Some arbitrary comment");
+ }
+
+ sendMessage(SAMPLE_TABLE_DETAIL_RESP, 0, rootNode);
+ }
+ }
+
+
+ // ===================================================================
+ // NOTE: The code below this line is to create fake data for this
+ // sample code. Normally you would use existing services to
+ // provide real data.
+
+ // Lookup a single item.
+ private static Item getItem(String id) {
+ // We realize this code is really inefficient, but
+ // it suffices for our purposes of demonstration...
+ for (Item item : getItems()) {
+ if (item.id().equals(id)) {
+ return item;
+ }
+ }
+ return null;
+ }
+
+ // Produce a list of items.
+ private static List<Item> getItems() {
+ List<Item> items = new ArrayList<>();
+ items.add(new Item("item-1", "foo", 42));
+ items.add(new Item("item-2", "bar", 99));
+ items.add(new Item("item-3", "baz", 65));
+ return items;
+ }
+
+ // Simple model class to provide sample data
+ private static class Item {
+ private final String id;
+ private final String label;
+ private final int code;
+
+ Item(String id, String label, int code) {
+ this.id = id;
+ this.label = label;
+ this.code = code;
+ }
+
+ String id() { return id; }
+ String label() { return label; }
+ int code() { return code; }
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/tools/package/archetypes/uitab/src/main/resources/archetype-resources/src/main/resources/app/view/sampleTable/sampleTable.css b/framework/src/onos/tools/package/archetypes/uitab/src/main/resources/archetype-resources/src/main/resources/app/view/sampleTable/sampleTable.css
new file mode 100644
index 00000000..5eb551b3
--- /dev/null
+++ b/framework/src/onos/tools/package/archetypes/uitab/src/main/resources/archetype-resources/src/main/resources/app/view/sampleTable/sampleTable.css
@@ -0,0 +1,35 @@
+/* css for sample table view */
+
+#ov-sample-table h2 {
+ display: inline-block;
+}
+
+/* Panel Styling */
+#ov-sample-table-item-details-panel.floatpanel {
+ position: absolute;
+ top: 115px;
+}
+
+.light #ov-sample-table-item-details-panel.floatpanel {
+ background-color: rgb(229, 234, 237);
+}
+.dark #ov-sample-table-item-details-panel.floatpanel {
+ background-color: #3A4042;
+}
+
+#ov-sample-table-item-details-panel h3 {
+ margin: 0;
+ font-size: large;
+}
+
+#ov-sample-table-item-details-panel h4 {
+ margin: 0;
+}
+
+#ov-sample-table-item-details-panel td {
+ padding: 5px;
+}
+#ov-sample-table-item-details-panel td.label {
+ font-style: italic;
+ opacity: 0.8;
+}
diff --git a/framework/src/onos/tools/package/archetypes/uitab/src/main/resources/archetype-resources/src/main/resources/app/view/sampleTable/sampleTable.html b/framework/src/onos/tools/package/archetypes/uitab/src/main/resources/archetype-resources/src/main/resources/app/view/sampleTable/sampleTable.html
new file mode 100644
index 00000000..e20a94d7
--- /dev/null
+++ b/framework/src/onos/tools/package/archetypes/uitab/src/main/resources/archetype-resources/src/main/resources/app/view/sampleTable/sampleTable.html
@@ -0,0 +1,46 @@
+<!-- partial HTML -->
+<div id="ov-sample-table">
+ <div class="tabular-header">
+ <h2>Items ({{tableData.length}} total)</h2>
+ <div class="ctrl-btns">
+ <div class="refresh" ng-class="{active: autoRefresh}"
+ icon icon-id="refresh" icon-size="36"
+ tooltip tt-msg="autoRefreshTip"
+ ng-click="toggleRefresh()"></div>
+ </div>
+ </div>
+
+ <div class="summary-list" onos-table-resize>
+
+ <div class="table-header" onos-sortable-header>
+ <table>
+ <tr>
+ <td colId="id" sortable>Item ID </td>
+ <td colId="label" sortable>Label </td>
+ <td colId="code" sortable>Code </td>
+ </tr>
+ </table>
+ </div>
+
+ <div class="table-body">
+ <table>
+ <tr ng-if="!tableData.length" class="no-data">
+ <td colspan="3">
+ No Items found
+ </td>
+ </tr>
+
+ <tr ng-repeat="item in tableData track by $index"
+ ng-click="selectCallback($event, item)"
+ ng-class="{selected: item.id === selId}">
+ <td>{{item.id}}</td>
+ <td>{{item.label}}</td>
+ <td>{{item.code}}</td>
+ </tr>
+ </table>
+ </div>
+
+ </div>
+
+ <ov-sample-table-item-details-panel></ov-sample-table-item-details-panel>
+</div>
diff --git a/framework/src/onos/tools/package/archetypes/uitab/src/main/resources/archetype-resources/src/main/resources/app/view/sampleTable/sampleTable.js b/framework/src/onos/tools/package/archetypes/uitab/src/main/resources/archetype-resources/src/main/resources/app/view/sampleTable/sampleTable.js
new file mode 100644
index 00000000..7b925550
--- /dev/null
+++ b/framework/src/onos/tools/package/archetypes/uitab/src/main/resources/archetype-resources/src/main/resources/app/view/sampleTable/sampleTable.js
@@ -0,0 +1,141 @@
+// js for sample app table view
+(function () {
+ 'use strict';
+
+ // injected refs
+ var $log, $scope, fs, wss;
+
+ // constants
+ var detailsReq = 'sampleTableDetailsRequest',
+ detailsResp = 'sampleTableDetailsResponse',
+ pName = 'ov-sample-table-item-details-panel',
+
+ propOrder = ['id', 'label', 'code'],
+ friendlyProps = ['Item ID', 'Item Label', 'Special Code'];
+
+
+ function addProp(tbody, index, value) {
+ var tr = tbody.append('tr');
+
+ function addCell(cls, txt) {
+ tr.append('td').attr('class', cls).html(txt);
+ }
+ addCell('label', friendlyProps[index] + ' :');
+ addCell('value', value);
+ }
+
+ function populatePanel(panel) {
+ var title = panel.append('h3'),
+ tbody = panel.append('table').append('tbody');
+
+ title.text('Item Details');
+
+ propOrder.forEach(function (prop, i) {
+ addProp(tbody, i, $scope.panelDetails[prop]);
+ });
+
+ panel.append('hr');
+ panel.append('h4').text('Comments');
+ panel.append('p').text($scope.panelDetails.comment);
+ }
+
+ function respDetailsCb(data) {
+ $scope.panelDetails = data.details;
+ $scope.$apply();
+ }
+
+ angular.module('ovSampleTable', [])
+ .controller('OvSampleTableCtrl',
+ ['$log', '$scope', 'TableBuilderService',
+ 'FnService', 'WebSocketService',
+
+ function (_$log_, _$scope_, tbs, _fs_, _wss_) {
+ $log = _$log_;
+ $scope = _$scope_;
+ fs = _fs_;
+ wss = _wss_;
+
+ var handlers = {};
+ $scope.panelDetails = {};
+
+ // details response handler
+ handlers[detailsResp] = respDetailsCb;
+ wss.bindHandlers(handlers);
+
+ // custom selection callback
+ function selCb($event, row) {
+ if ($scope.selId) {
+ wss.sendEvent(detailsReq, { id: row.id });
+ } else {
+ $scope.hidePanel();
+ }
+ $log.debug('Got a click on:', row);
+ }
+
+ // TableBuilderService creating a table for us
+ tbs.buildTable({
+ scope: $scope,
+ tag: 'sampleTable',
+ selCb: selCb
+ });
+
+ // cleanup
+ $scope.$on('$destroy', function () {
+ wss.unbindHandlers(handlers);
+ $log.log('OvSampleTableCtrl has been destroyed');
+ });
+
+ $log.log('OvSampleTableCtrl has been created');
+ }])
+
+ .directive('ovSampleTableItemDetailsPanel', ['PanelService', 'KeyService',
+ function (ps, ks) {
+ return {
+ restrict: 'E',
+ link: function (scope, element, attrs) {
+ // insert details panel with PanelService
+ // create the panel
+ var panel = ps.createPanel(pName, {
+ width: 200,
+ margin: 20,
+ hideMargin: 0
+ });
+ panel.hide();
+ scope.hidePanel = function () { panel.hide(); };
+
+ function closePanel() {
+ if (panel.isVisible()) {
+ $scope.selId = null;
+ panel.hide();
+ return true;
+ }
+ return false;
+ }
+
+ // create key bindings to handle panel
+ ks.keyBindings({
+ esc: [closePanel, 'Close the details panel'],
+ _helpFormat: ['esc']
+ });
+ ks.gestureNotes([
+ ['click', 'Select a row to show item details']
+ ]);
+
+ // update the panel's contents when the data is changed
+ scope.$watch('panelDetails', function () {
+ if (!fs.isEmptyObject(scope.panelDetails)) {
+ panel.empty();
+ populatePanel(panel);
+ panel.show();
+ }
+ });
+
+ // cleanup on destroyed scope
+ scope.$on('$destroy', function () {
+ ks.unbindKeys();
+ ps.destroyPanel(pName);
+ });
+ }
+ };
+ }]);
+}());
diff --git a/framework/src/onos/tools/package/archetypes/uitab/src/main/resources/archetype-resources/src/main/resources/sampleTable/css.html b/framework/src/onos/tools/package/archetypes/uitab/src/main/resources/archetype-resources/src/main/resources/sampleTable/css.html
new file mode 100644
index 00000000..26112b0d
--- /dev/null
+++ b/framework/src/onos/tools/package/archetypes/uitab/src/main/resources/archetype-resources/src/main/resources/sampleTable/css.html
@@ -0,0 +1 @@
+<link rel="stylesheet" href="app/view/sampleTable/sampleTable.css"> \ No newline at end of file
diff --git a/framework/src/onos/tools/package/archetypes/uitab/src/main/resources/archetype-resources/src/main/resources/sampleTable/js.html b/framework/src/onos/tools/package/archetypes/uitab/src/main/resources/archetype-resources/src/main/resources/sampleTable/js.html
new file mode 100644
index 00000000..4bfa2169
--- /dev/null
+++ b/framework/src/onos/tools/package/archetypes/uitab/src/main/resources/archetype-resources/src/main/resources/sampleTable/js.html
@@ -0,0 +1 @@
+<script src="app/view/sampleTable/sampleTable.js"></script> \ No newline at end of file
diff --git a/framework/src/onos/tools/package/archetypes/uitab/src/test/resources/projects/basic/archetype.properties b/framework/src/onos/tools/package/archetypes/uitab/src/test/resources/projects/basic/archetype.properties
new file mode 100644
index 00000000..a1213b40
--- /dev/null
+++ b/framework/src/onos/tools/package/archetypes/uitab/src/test/resources/projects/basic/archetype.properties
@@ -0,0 +1,21 @@
+#
+# 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.
+#
+
+#Thu Dec 04 09:24:50 PST 2014
+package=it.pkg
+version=0.1-SNAPSHOT
+groupId=archetype.it
+artifactId=basic
diff --git a/framework/src/onos/tools/package/archetypes/uitab/src/test/resources/projects/basic/goal.txt b/framework/src/onos/tools/package/archetypes/uitab/src/test/resources/projects/basic/goal.txt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/framework/src/onos/tools/package/archetypes/uitab/src/test/resources/projects/basic/goal.txt
diff --git a/framework/src/onos/tools/package/archetypes/uitopo/pom.xml b/framework/src/onos/tools/package/archetypes/uitopo/pom.xml
new file mode 100644
index 00000000..6ed7c871
--- /dev/null
+++ b/framework/src/onos/tools/package/archetypes/uitopo/pom.xml
@@ -0,0 +1,31 @@
+<?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/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-archetypes</artifactId>
+ <version>1.4.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>onos-uitopo-archetype</artifactId>
+ <packaging>maven-archetype</packaging>
+
+ <description>ONOS UI Topology-Overlay overlay archetype</description>
+
+</project>
diff --git a/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/META-INF/maven/archetype-metadata.xml b/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/META-INF/maven/archetype-metadata.xml
new file mode 100644
index 00000000..26a9082d
--- /dev/null
+++ b/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/META-INF/maven/archetype-metadata.xml
@@ -0,0 +1,39 @@
+<?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.
+ -->
+<archetype-descriptor
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0 http://maven.apache.org/xsd/archetype-descriptor-1.0.0.xsd"
+ name="onos-uitopo" partial="true"
+ xmlns="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <fileSets>
+ <fileSet filtered="true" packaged="true" encoding="UTF-8">
+ <directory>src/main/java</directory>
+ <includes>
+ <include>**/*.java</include>
+ </includes>
+ </fileSet>
+ <fileSet filtered="true" packaged="false" encoding="UTF-8">
+ <directory>src/main/resources</directory>
+ <includes>
+ <include>**/*.html</include>
+ <include>**/*.js</include>
+ <include>**/*.css</include>
+ </includes>
+ </fileSet>
+ </fileSets>
+</archetype-descriptor>
diff --git a/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/pom.xml b/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/pom.xml
new file mode 100644
index 00000000..f0688ec2
--- /dev/null
+++ b/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/pom.xml
@@ -0,0 +1,140 @@
+<?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/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>${groupId}</groupId>
+ <artifactId>${artifactId}</artifactId>
+ <version>${version}</version>
+ <packaging>bundle</packaging>
+
+ <description>ONOS OSGi UI Topology-Overlay bundle archetype</description>
+ <url>http://onosproject.org</url>
+
+ <properties>
+ <onos.version>1.4.0-SNAPSHOT</onos.version>
+ <!-- Uncomment to generate ONOS app from this module.
+ <onos.app.name>org.foo.app</onos.app.name>
+ <onos.app.origin>Foo, Inc.</onos.app.origin>
+ -->
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-api</artifactId>
+ <version>${onos.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onlab-osgi</artifactId>
+ <version>${onos.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.11</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-api</artifactId>
+ <version>${onos.version}</version>
+ <scope>test</scope>
+ <classifier>tests</classifier>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.scr.annotations</artifactId>
+ <version>1.9.8</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>2.5.3</version>
+ <extensions>true</extensions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.5.1</version>
+ <configuration>
+ <source>1.8</source>
+ <target>1.8</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-scr-plugin</artifactId>
+ <version>1.20.0</version>
+ <executions>
+ <execution>
+ <id>generate-scr-srcdescriptor</id>
+ <goals>
+ <goal>scr</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <supportedProjectTypes>
+ <supportedProjectType>bundle</supportedProjectType>
+ <supportedProjectType>war</supportedProjectType>
+ </supportedProjectTypes>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-maven-plugin</artifactId>
+ <version>1.5</version>
+ <executions>
+ <execution>
+ <id>cfg</id>
+ <phase>generate-resources</phase>
+ <goals>
+ <goal>cfg</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>swagger</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>swagger</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>app</id>
+ <phase>package</phase>
+ <goals>
+ <goal>app</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/java/AppUiTopovComponent.java b/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/java/AppUiTopovComponent.java
new file mode 100644
index 00000000..fa62a784
--- /dev/null
+++ b/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/java/AppUiTopovComponent.java
@@ -0,0 +1,89 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+/*
+ * 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 ${package};
+
+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;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onosproject.ui.UiExtension;
+import org.onosproject.ui.UiExtensionService;
+import org.onosproject.ui.UiMessageHandlerFactory;
+import org.onosproject.ui.UiTopoOverlayFactory;
+import org.onosproject.ui.UiView;
+import org.onosproject.ui.UiViewHidden;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+/**
+ * Skeletal ONOS UI Topology-Overlay application component.
+ */
+@Component(immediate = true)
+public class AppUiTopovComponent {
+
+ private static final ClassLoader CL = AppUiTopovComponent.class.getClassLoader();
+ private static final String VIEW_ID = "sampleTopov";
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected UiExtensionService uiExtensionService;
+
+ // List of application views
+ private final List<UiView> uiViews = ImmutableList.of(
+ new UiViewHidden(VIEW_ID)
+ );
+
+ // Factory for UI message handlers
+ private final UiMessageHandlerFactory messageHandlerFactory =
+ () -> ImmutableList.of(
+ new AppUiTopovMessageHandler()
+ );
+
+ // Factory for UI topology overlays
+ private final UiTopoOverlayFactory topoOverlayFactory =
+ () -> ImmutableList.of(
+ new AppUiTopovOverlay()
+ );
+
+ // Application UI extension
+ protected UiExtension extension =
+ new UiExtension.Builder(CL, uiViews)
+ .resourcePath(VIEW_ID)
+ .messageHandlerFactory(messageHandlerFactory)
+ .topoOverlayFactory(topoOverlayFactory)
+ .build();
+
+ @Activate
+ protected void activate() {
+ uiExtensionService.register(extension);
+ log.info("Started");
+ }
+
+ @Deactivate
+ protected void deactivate() {
+ uiExtensionService.unregister(extension);
+ log.info("Stopped");
+ }
+
+}
diff --git a/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/java/AppUiTopovMessageHandler.java b/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/java/AppUiTopovMessageHandler.java
new file mode 100644
index 00000000..fe28186b
--- /dev/null
+++ b/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/java/AppUiTopovMessageHandler.java
@@ -0,0 +1,319 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+/*
+ * 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 ${package};
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableSet;
+import org.onlab.osgi.ServiceDirectory;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Element;
+import org.onosproject.net.HostId;
+import org.onosproject.net.Link;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.host.HostService;
+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.Highlights;
+import org.onosproject.ui.topo.TopoJson;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
+
+/**
+ * Skeletal ONOS UI Topology-Overlay message handler.
+ */
+public class AppUiTopovMessageHandler extends UiMessageHandler {
+
+ private static final String SAMPLE_DISPLAY_START = "sampleDisplayStart";
+ private static final String SAMPLE_DISPLAY_UPDATE = "sampleDisplayUpdate";
+ private static final String SAMPLE_DISPLAY_STOP = "sampleDisplayStop";
+
+ private static final String ID = "id";
+ private static final String MODE = "mode";
+
+ private static final long UPDATE_PERIOD_MS = 1000;
+
+ private static final Link[] EMPTY_LINK_SET = new Link[0];
+
+ private enum Mode { IDLE, MOUSE, LINK }
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ private DeviceService deviceService;
+ private HostService hostService;
+ private LinkService linkService;
+
+ private final Timer timer = new Timer("sample-overlay");
+ private TimerTask demoTask = null;
+ private Mode currentMode = Mode.IDLE;
+ private Element elementOfNote;
+ private Link[] linkSet = EMPTY_LINK_SET;
+ private int linkIndex;
+
+
+ // ===============-=-=-=-=-=-======================-=-=-=-=-=-=-================================
+
+
+ @Override
+ public void init(UiConnection connection, ServiceDirectory directory) {
+ super.init(connection, directory);
+ deviceService = directory.get(DeviceService.class);
+ hostService = directory.get(HostService.class);
+ linkService = directory.get(LinkService.class);
+ }
+
+ @Override
+ protected Collection<RequestHandler> createRequestHandlers() {
+ return ImmutableSet.of(
+ new DisplayStartHandler(),
+ new DisplayUpdateHandler(),
+ new DisplayStopHandler()
+ );
+ }
+
+ // === -------------------------
+ // === Handler classes
+
+ private final class DisplayStartHandler extends RequestHandler {
+ public DisplayStartHandler() {
+ super(SAMPLE_DISPLAY_START);
+ }
+
+ @Override
+ public void process(long sid, ObjectNode payload) {
+ String mode = string(payload, MODE);
+
+ log.debug("Start Display: mode [{}]", mode);
+ clearState();
+ clearForMode();
+
+ switch (mode) {
+ case "mouse":
+ currentMode = Mode.MOUSE;
+ cancelTask();
+ sendMouseData();
+ break;
+
+ case "link":
+ currentMode = Mode.LINK;
+ scheduleTask();
+ initLinkSet();
+ sendLinkData();
+ break;
+
+ default:
+ currentMode = Mode.IDLE;
+ cancelTask();
+ break;
+ }
+ }
+ }
+
+ private final class DisplayUpdateHandler extends RequestHandler {
+ public DisplayUpdateHandler() {
+ super(SAMPLE_DISPLAY_UPDATE);
+ }
+
+ @Override
+ public void process(long sid, ObjectNode payload) {
+ String id = string(payload, ID);
+ log.debug("Update Display: id [{}]", id);
+ if (!Strings.isNullOrEmpty(id)) {
+ updateForMode(id);
+ } else {
+ clearForMode();
+ }
+ }
+ }
+
+ private final class DisplayStopHandler extends RequestHandler {
+ public DisplayStopHandler() {
+ super(SAMPLE_DISPLAY_STOP);
+ }
+
+ @Override
+ public void process(long sid, ObjectNode payload) {
+ log.debug("Stop Display");
+ cancelTask();
+ clearState();
+ clearForMode();
+ }
+ }
+
+ // === ------------
+
+ private void clearState() {
+ currentMode = Mode.IDLE;
+ elementOfNote = null;
+ linkSet = EMPTY_LINK_SET;
+ }
+
+ private void updateForMode(String id) {
+ log.debug("host service: {}", hostService);
+ log.debug("device service: {}", deviceService);
+
+ try {
+ HostId hid = HostId.hostId(id);
+ log.debug("host id {}", hid);
+ elementOfNote = hostService.getHost(hid);
+ log.debug("host element {}", elementOfNote);
+
+ } catch (Exception e) {
+ try {
+ DeviceId did = DeviceId.deviceId(id);
+ log.debug("device id {}", did);
+ elementOfNote = deviceService.getDevice(did);
+ log.debug("device element {}", elementOfNote);
+
+ } catch (Exception e2) {
+ log.debug("Unable to process ID [{}]", id);
+ elementOfNote = null;
+ }
+ }
+
+ switch (currentMode) {
+ case MOUSE:
+ sendMouseData();
+ break;
+
+ case LINK:
+ sendLinkData();
+ break;
+
+ default:
+ break;
+ }
+
+ }
+
+ private void clearForMode() {
+ sendHighlights(new Highlights());
+ }
+
+ private void sendHighlights(Highlights highlights) {
+ sendMessage(TopoJson.highlightsMessage(highlights));
+ }
+
+
+ private void sendMouseData() {
+ if (elementOfNote != null && elementOfNote instanceof Device) {
+ DeviceId devId = (DeviceId) elementOfNote.id();
+ Set<Link> links = linkService.getDeviceEgressLinks(devId);
+ sendHighlights(fromLinks(links, devId));
+ }
+ // Note: could also process Host, if available
+ }
+
+ private Highlights fromLinks(Set<Link> links, DeviceId devId) {
+ DemoLinkMap linkMap = new DemoLinkMap();
+ if (links != null) {
+ log.debug("Processing {} links", links.size());
+ links.forEach(linkMap::add);
+ } else {
+ log.debug("No egress links found for device {}", devId);
+ }
+
+ Highlights highlights = new Highlights();
+
+ for (DemoLink dlink : linkMap.biLinks()) {
+ dlink.makeImportant().setLabel("Yo!");
+ highlights.add(dlink.highlight(null));
+ }
+ return highlights;
+ }
+
+ private void initLinkSet() {
+ Set<Link> links = new HashSet<>();
+ for (Link link : linkService.getActiveLinks()) {
+ links.add(link);
+ }
+ linkSet = links.toArray(new Link[links.size()]);
+ linkIndex = 0;
+ log.debug("initialized link set to {}", linkSet.length);
+ }
+
+ private void sendLinkData() {
+ DemoLinkMap linkMap = new DemoLinkMap();
+ for (Link link : linkSet) {
+ linkMap.add(link);
+ }
+ DemoLink dl = linkMap.add(linkSet[linkIndex]);
+ dl.makeImportant().setLabel(Integer.toString(linkIndex));
+ log.debug("sending link data (index {})", linkIndex);
+
+ linkIndex += 1;
+ if (linkIndex >= linkSet.length) {
+ linkIndex = 0;
+ }
+
+ Highlights highlights = new Highlights();
+ for (DemoLink dlink : linkMap.biLinks()) {
+ highlights.add(dlink.highlight(null));
+ }
+
+ sendHighlights(highlights);
+ }
+
+ private synchronized void scheduleTask() {
+ if (demoTask == null) {
+ log.debug("Starting up demo task...");
+ demoTask = new DisplayUpdateTask();
+ timer.schedule(demoTask, UPDATE_PERIOD_MS, UPDATE_PERIOD_MS);
+ } else {
+ log.debug("(demo task already running");
+ }
+ }
+
+ private synchronized void cancelTask() {
+ if (demoTask != null) {
+ demoTask.cancel();
+ demoTask = null;
+ }
+ }
+
+
+ private class DisplayUpdateTask extends TimerTask {
+ @Override
+ public void run() {
+ try {
+ switch (currentMode) {
+ case LINK:
+ sendLinkData();
+ break;
+
+ default:
+ break;
+ }
+ } catch (Exception e) {
+ log.warn("Unable to process demo task: {}", e.getMessage());
+ log.debug("Oops", e);
+ }
+ }
+ }
+
+} \ No newline at end of file
diff --git a/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/java/AppUiTopovOverlay.java b/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/java/AppUiTopovOverlay.java
new file mode 100644
index 00000000..98999825
--- /dev/null
+++ b/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/java/AppUiTopovOverlay.java
@@ -0,0 +1,75 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+/*
+ * 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 ${package};
+
+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.*;
+
+/**
+ * Our topology overlay.
+ */
+public class AppUiTopovOverlay extends UiTopoOverlay {
+
+ // NOTE: this must match the ID defined in sampleTopov.js
+ private static final String OVERLAY_ID = "meowster-overlay";
+
+ private static final String MY_TITLE = "My App Rocks!";
+ private static final String MY_VERSION = "Beta-1.0.0042";
+ private static final String MY_DEVICE_TITLE = "I changed the title";
+
+ private static final ButtonId FOO_BUTTON = new ButtonId("foo");
+ private static final ButtonId BAR_BUTTON = new ButtonId("bar");
+
+ public AppUiTopovOverlay() {
+ super(OVERLAY_ID);
+ }
+
+
+ @Override
+ public void modifySummary(PropertyPanel pp) {
+ pp.title(MY_TITLE)
+ .typeId(Glyphs.CROWN)
+ .removeProps(
+ TOPOLOGY_SSCS,
+ INTENTS,
+ TUNNELS,
+ FLOWS,
+ VERSION
+ )
+ .addProp(VERSION, MY_VERSION);
+ }
+
+ @Override
+ public void modifyDeviceDetails(PropertyPanel pp) {
+ pp.title(MY_DEVICE_TITLE);
+ pp.removeProps(LATITUDE, LONGITUDE);
+
+ pp.addButton(FOO_BUTTON)
+ .addButton(BAR_BUTTON);
+
+ pp.removeButtons(CoreButtons.SHOW_PORT_VIEW)
+ .removeButtons(CoreButtons.SHOW_GROUP_VIEW);
+ }
+
+}
diff --git a/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/java/DemoLink.java b/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/java/DemoLink.java
new file mode 100644
index 00000000..4a97f7bd
--- /dev/null
+++ b/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/java/DemoLink.java
@@ -0,0 +1,57 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+/*
+ * 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 ${package};
+
+import org.onosproject.net.Link;
+import org.onosproject.net.LinkKey;
+import org.onosproject.ui.topo.BiLink;
+import org.onosproject.ui.topo.LinkHighlight;
+import org.onosproject.ui.topo.LinkHighlight.Flavor;
+
+/**
+ * Our demo concrete class of a bi-link. We give it state so we can decide
+ * how to create link highlights.
+ */
+public class DemoLink extends BiLink {
+
+ private boolean important = false;
+ private String label = null;
+
+ public DemoLink(LinkKey key, Link link) {
+ super(key, link);
+ }
+
+ public DemoLink makeImportant() {
+ important = true;
+ return this;
+ }
+
+ public DemoLink setLabel(String label) {
+ this.label = label;
+ return this;
+ }
+
+ @Override
+ public LinkHighlight highlight(Enum<?> anEnum) {
+ Flavor flavor = important ? Flavor.PRIMARY_HIGHLIGHT
+ : Flavor.SECONDARY_HIGHLIGHT;
+ return new LinkHighlight(this.linkId(), flavor)
+ .setLabel(label);
+ }
+}
diff --git a/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/java/DemoLinkMap.java b/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/java/DemoLinkMap.java
new file mode 100644
index 00000000..cc13d998
--- /dev/null
+++ b/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/java/DemoLinkMap.java
@@ -0,0 +1,33 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+/*
+ * 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 ${package};
+
+import org.onosproject.net.Link;
+import org.onosproject.net.LinkKey;
+import org.onosproject.ui.topo.BiLinkMap;
+
+/**
+ * Our concrete link map.
+ */
+public class DemoLinkMap extends BiLinkMap<DemoLink> {
+ @Override
+ protected DemoLink create(LinkKey linkKey, Link link) {
+ return new DemoLink(linkKey, link);
+ }
+}
diff --git a/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/resources/app/view/sampleTopov/sampleTopov.css b/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/resources/app/view/sampleTopov/sampleTopov.css
new file mode 100644
index 00000000..cbf460f9
--- /dev/null
+++ b/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/resources/app/view/sampleTopov/sampleTopov.css
@@ -0,0 +1,2 @@
+/* css for sample app topology overlay */
+
diff --git a/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/resources/app/view/sampleTopov/sampleTopov.html b/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/resources/app/view/sampleTopov/sampleTopov.html
new file mode 100644
index 00000000..b1c9acbb
--- /dev/null
+++ b/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/resources/app/view/sampleTopov/sampleTopov.html
@@ -0,0 +1,4 @@
+<!-- partial HTML -->
+<div id="ov-sample-topov">
+ <p>This is a hidden view .. just a placeholder to house the javascript</p>
+</div>
diff --git a/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/resources/app/view/sampleTopov/sampleTopovDemo.js b/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/resources/app/view/sampleTopov/sampleTopovDemo.js
new file mode 100644
index 00000000..0b82d811
--- /dev/null
+++ b/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/resources/app/view/sampleTopov/sampleTopovDemo.js
@@ -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.
+ */
+
+/*
+ Sample Demo module. This contains the "business logic" for the topology
+ overlay that we are implementing.
+ */
+
+(function () {
+ 'use strict';
+
+ // injected refs
+ var $log, fs, flash, wss;
+
+ // constants
+ var displayStart = 'sampleDisplayStart',
+ displayUpdate = 'sampleDisplayUpdate',
+ displayStop = 'sampleDisplayStop';
+
+ // internal state
+ var currentMode = null;
+
+
+ // === ---------------------------
+ // === Helper functions
+
+ function sendDisplayStart(mode) {
+ wss.sendEvent(displayStart, {
+ mode: mode
+ });
+ }
+
+ function sendDisplayUpdate(what) {
+ wss.sendEvent(displayUpdate, {
+ id: what ? what.id : ''
+ });
+ }
+
+ function sendDisplayStop() {
+ wss.sendEvent(displayStop);
+ }
+
+ // === ---------------------------
+ // === Main API functions
+
+ function startDisplay(mode) {
+ if (currentMode === mode) {
+ $log.debug('(in mode', mode, 'already)');
+ } else {
+ currentMode = mode;
+ sendDisplayStart(mode);
+ flash.flash('Starting display mode: ' + mode);
+ }
+ }
+
+ function updateDisplay(m) {
+ if (currentMode) {
+ sendDisplayUpdate(m);
+ }
+ }
+
+ function stopDisplay() {
+ if (currentMode) {
+ currentMode = null;
+ sendDisplayStop();
+ flash.flash('Canceling display mode');
+ return true;
+ }
+ return false;
+ }
+
+ // === ---------------------------
+ // === Module Factory Definition
+
+ angular.module('ovSampleTopov', [])
+ .factory('SampleTopovDemoService',
+ ['$log', 'FnService', 'FlashService', 'WebSocketService',
+
+ function (_$log_, _fs_, _flash_, _wss_) {
+ $log = _$log_;
+ fs = _fs_;
+ flash = _flash_;
+ wss = _wss_;
+
+ return {
+ startDisplay: startDisplay,
+ updateDisplay: updateDisplay,
+ stopDisplay: stopDisplay
+ };
+ }]);
+}());
diff --git a/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/resources/app/view/sampleTopov/sampleTopovOverlay.js b/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/resources/app/view/sampleTopov/sampleTopovOverlay.js
new file mode 100644
index 00000000..12875e1f
--- /dev/null
+++ b/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/resources/app/view/sampleTopov/sampleTopovOverlay.js
@@ -0,0 +1,143 @@
+// sample topology overlay - client side
+//
+// This is the glue that binds our business logic (in sampleTopovDemo.js)
+// to the overlay framework.
+
+(function () {
+ 'use strict';
+
+ // injected refs
+ var $log, tov, stds;
+
+ // internal state should be kept in the service module (not here)
+
+ // our overlay definition
+ var overlay = {
+ // NOTE: this must match the ID defined in AppUiTopoOverlay
+ overlayId: 'meowster-overlay',
+ glyphId: '*star4',
+ tooltip: 'Sample Meowster Topo Overlay',
+
+ // These glyphs get installed using the overlayId as a prefix.
+ // e.g. 'star4' is installed as 'meowster-overlay-star4'
+ // They can be referenced (from this overlay) as '*star4'
+ // That is, the '*' prefix stands in for 'meowster-overlay-'
+ glyphs: {
+ star4: {
+ vb: '0 0 8 8',
+ d: 'M1,4l2,-1l1,-2l1,2l2,1l-2,1l-1,2l-1,-2z'
+ },
+ banner: {
+ vb: '0 0 6 6',
+ d: 'M1,1v4l2,-2l2,2v-4z'
+ }
+ },
+
+ activate: function () {
+ $log.debug("Sample topology overlay ACTIVATED");
+ },
+ deactivate: function () {
+ stds.stopDisplay();
+ $log.debug("Sample topology overlay DEACTIVATED");
+ },
+
+ // detail panel button definitions
+ buttons: {
+ foo: {
+ gid: 'chain',
+ tt: 'A FOO action',
+ cb: function (data) {
+ $log.debug('FOO action invoked with data:', data);
+ }
+ },
+ bar: {
+ gid: '*banner',
+ tt: 'A BAR action',
+ cb: function (data) {
+ $log.debug('BAR action invoked with data:', data);
+ }
+ }
+ },
+
+ // Key bindings for traffic overlay buttons
+ // NOTE: fully qual. button ID is derived from overlay-id and key-name
+ keyBindings: {
+ 0: {
+ cb: function () { stds.stopDisplay(); },
+ tt: 'Cancel Display Mode',
+ gid: 'xMark'
+ },
+ V: {
+ cb: function () { stds.startDisplay('mouse'); },
+ tt: 'Start Mouse Mode',
+ gid: '*banner'
+ },
+ F: {
+ cb: function () { stds.startDisplay('link'); },
+ tt: 'Start Link Mode',
+ gid: 'chain'
+ },
+ G: {
+ cb: buttonCallback,
+ tt: 'Uses the G key',
+ gid: 'crown'
+ },
+
+ _keyOrder: [
+ '0', 'V', 'F', 'G'
+ ]
+ },
+
+ hooks: {
+ // hook for handling escape key
+ // Must return true to consume ESC, false otherwise.
+ escape: function () {
+ // Must return true to consume ESC, false otherwise.
+ return stds.stopDisplay();
+ },
+
+ // hooks for when the selection changes...
+ empty: function () {
+ selectionCallback('empty');
+ },
+ single: function (data) {
+ selectionCallback('single', data);
+ },
+ multi: function (selectOrder) {
+ selectionCallback('multi', selectOrder);
+ tov.addDetailButton('foo');
+ tov.addDetailButton('bar');
+ },
+ mouseover: function (m) {
+ // m has id, class, and type properties
+ $log.debug('mouseover:', m);
+ stds.updateDisplay(m);
+ },
+ mouseout: function () {
+ $log.debug('mouseout');
+ stds.updateDisplay();
+ }
+ }
+ };
+
+
+ function buttonCallback(x) {
+ $log.debug('Toolbar-button callback', x);
+ }
+
+ function selectionCallback(x, d) {
+ $log.debug('Selection callback', x, d);
+ }
+
+ // invoke code to register with the overlay service
+ angular.module('ovSampleTopov')
+ .run(['$log', 'TopoOverlayService', 'SampleTopovDemoService',
+
+ function (_$log_, _tov_, _stds_) {
+ $log = _$log_;
+ tov = _tov_;
+ stds = _stds_;
+ tov.register(overlay);
+ }]);
+
+}());
diff --git a/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/resources/sampleTopov/css.html b/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/resources/sampleTopov/css.html
new file mode 100644
index 00000000..0ed6f53c
--- /dev/null
+++ b/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/resources/sampleTopov/css.html
@@ -0,0 +1 @@
+<link rel="stylesheet" href="app/view/sampleTopov/sampleTopov.css"> \ No newline at end of file
diff --git a/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/resources/sampleTopov/js.html b/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/resources/sampleTopov/js.html
new file mode 100644
index 00000000..4fed1f08
--- /dev/null
+++ b/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/resources/sampleTopov/js.html
@@ -0,0 +1,2 @@
+<script src="app/view/sampleTopov/sampleTopovDemo.js"></script>
+<script src="app/view/sampleTopov/sampleTopovOverlay.js"></script> \ No newline at end of file
diff --git a/framework/src/onos/tools/package/archetypes/uitopo/src/test/resources/projects/basic/archetype.properties b/framework/src/onos/tools/package/archetypes/uitopo/src/test/resources/projects/basic/archetype.properties
new file mode 100644
index 00000000..a1213b40
--- /dev/null
+++ b/framework/src/onos/tools/package/archetypes/uitopo/src/test/resources/projects/basic/archetype.properties
@@ -0,0 +1,21 @@
+#
+# 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.
+#
+
+#Thu Dec 04 09:24:50 PST 2014
+package=it.pkg
+version=0.1-SNAPSHOT
+groupId=archetype.it
+artifactId=basic
diff --git a/framework/src/onos/tools/package/archetypes/uitopo/src/test/resources/projects/basic/goal.txt b/framework/src/onos/tools/package/archetypes/uitopo/src/test/resources/projects/basic/goal.txt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/framework/src/onos/tools/package/archetypes/uitopo/src/test/resources/projects/basic/goal.txt
diff --git a/framework/src/onos/tools/package/config/samples/component-cfg.json b/framework/src/onos/tools/package/config/samples/component-cfg.json
new file mode 100644
index 00000000..f1168e44
--- /dev/null
+++ b/framework/src/onos/tools/package/config/samples/component-cfg.json
@@ -0,0 +1,5 @@
+{
+ "org.onosproject.proxyarp.ProxyArp": {
+ "ipv6NeighborDiscovery": true
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/tools/package/config/samples/network-cfg.json b/framework/src/onos/tools/package/config/samples/network-cfg.json
new file mode 100644
index 00000000..c2af8b81
--- /dev/null
+++ b/framework/src/onos/tools/package/config/samples/network-cfg.json
@@ -0,0 +1,66 @@
+{
+ "ports" : {
+ "of:0000000000000002/1" : {
+ "interfaces" : [
+ {
+ "ips" : [ "192.168.10.101/24" ],
+ "mac" : "08:9e:01:82:38:68",
+ "vlan" : "100"
+ }
+ ]
+ },
+ "of:0000000000000002/20" : {
+ "interfaces" : [
+ {
+ "ips" : [ "192.168.20.101/24" ],
+ "mac" : "08:9e:01:82:38:68",
+ "vlan" : "200"
+ }
+ ]
+ }
+ },
+ "devices" : {
+ "of:0000000000000002" : {
+ "segmentrouting" : {
+ "name" : "Leaf-R1",
+ "nodeSid" : 101,
+ "routerIp" : "10.0.1.254",
+ "routerMac" : "00:00:00:00:01:80",
+ "isEdgeRouter" : true,
+ "adjacencySids" : [
+ { "sid" : 100, "port" : [2, 3] },
+ { "sid" : 200, "port" : [4, 5] }
+ ]
+ }
+ },
+ "of:0000000000000191" : {
+ "segmentrouting" : {
+ "name" : "Spine-R1",
+ "nodeSid" : 105,
+ "routerIp" : "192.168.0.11",
+ "routerMac" : "00:00:01:00:11:80",
+ "isEdgeRouter" : false
+ }
+ }
+ },
+ "apps" : {
+ "org.onosproject.router" : {
+ "bgp" : {
+ "bgpSpeakers" : [
+ {
+ "connectPoint" : "of:00000000000000aa/10",
+ "peers" : [
+ "192.168.10.1"
+ ]
+ },
+ {
+ "connectPoint" : "of:00000000000000aa/20",
+ "peers" : [
+ "192.168.20.1"
+ ]
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/framework/src/onos/tools/test/bin/ogroup-opts b/framework/src/onos/tools/test/bin/ogroup-opts
index 41842bdd..f02b7a8f 100644
--- a/framework/src/onos/tools/test/bin/ogroup-opts
+++ b/framework/src/onos/tools/test/bin/ogroup-opts
@@ -44,7 +44,7 @@ function _cell-opts () {
fi
}
-complete -F _cell-opts cell
+complete -F _cell-opts cell vicell
# Tab completion settings for onos-create-app.
diff --git a/framework/src/onos/tools/test/bin/onos b/framework/src/onos/tools/test/bin/onos
index 89197db5..780a90dc 100755
--- a/framework/src/onos/tools/test/bin/onos
+++ b/framework/src/onos/tools/test/bin/onos
@@ -3,6 +3,27 @@
# ONOS remote command-line client.
# -----------------------------------------------------------------------------
+function _usage () {
+cat << _EOF_
+usage:
+ $(basename $0) [-w] [node]
+
+flags:
+- -w : Waits for ONOS instance to reach run-level 100, i.e. to be fully started.
+
+options:
+- [node] : the node to attach to
+
+summary:
+ ONOS remote command-line client.
+
+ The -w flag depends on 'onos-wait-for-start'. If [node] is unspecified, \$OCI
+ is used.
+
+_EOF_
+}
+[ "$1" = "-h" ] && _usage && exit 0
+
[ ! -d "$ONOS_ROOT" ] && echo "ONOS_ROOT is not defined" >&2 && exit 1
. $ONOS_ROOT/tools/build/envDefaults
. $ONOS_ROOT/tools/test/bin/find-node.sh
diff --git a/framework/src/onos/tools/test/bin/onos-archetypes-test b/framework/src/onos/tools/test/bin/onos-archetypes-test
index 7ae00332..331c4332 100755
--- a/framework/src/onos/tools/test/bin/onos-archetypes-test
+++ b/framework/src/onos/tools/test/bin/onos-archetypes-test
@@ -3,6 +3,19 @@
# Builds a set of projects using ONOS archetypes.
# -----------------------------------------------------------------------------
+function _usage () {
+cat << _EOF_
+usage:
+ $(basename $0)
+
+summary:
+ Builds a set of projects using ONOS archetypes.
+
+_EOF_
+}
+
+[ "$1" = "-h" ] && _usage && exit 0
+
set -e
export AROOT=/tmp/foo
diff --git a/framework/src/onos/tools/test/bin/onos-batch b/framework/src/onos/tools/test/bin/onos-batch
index 67864a22..ae288916 100755
--- a/framework/src/onos/tools/test/bin/onos-batch
+++ b/framework/src/onos/tools/test/bin/onos-batch
@@ -3,6 +3,28 @@
# Executes selected set of ONOS commands using the batch mode.
# -----------------------------------------------------------------------------
+function _usage () {
+cat << _EOF_
+usage:
+ $(basename $0) [node] <commands>
+
+options:
+- [node] <commands> : node to run <commands>
+
+summary:
+ Executes selected set of ONOS commands using the batch mode.
+
+ <commands> is a comma-separated list of ONOS CLI commands.
+
+ If [node] isn't specified, the defualt target becomes \$OCI. When no commands
+ are specified, the commands 'summary','intents','flows', and 'hosts' are
+ executed against \$OCI.
+
+_EOF_
+}
+
+[ "$1" = "-h" ] && _usage && exit 0
+
[ ! -d "$ONOS_ROOT" ] && echo "ONOS_ROOT is not defined" >&2 && exit 1
. $ONOS_ROOT/tools/build/envDefaults
diff --git a/framework/src/onos/tools/test/bin/onos-config b/framework/src/onos/tools/test/bin/onos-config
index 5c3ab024..348cb839 100755
--- a/framework/src/onos/tools/test/bin/onos-config
+++ b/framework/src/onos/tools/test/bin/onos-config
@@ -3,6 +3,28 @@
# Remotely configures & starts ONOS for the first time.
# -----------------------------------------------------------------------------
+function _usage () {
+cat << _EOF_
+usage:
+ $(basename $0) [node]
+
+options:
+- [node] : The node to configure
+
+summary:
+ Remotely configures and starts ONOS for the first time.
+
+ The procedure for configruing a node include determining base features,
+ applications to load at startup, and clustering and logical network view
+ configurations, among others.
+
+ If [node] isn't specified, the defualt target becomes \$OCI.
+
+_EOF_
+}
+
+[ "$1" = "-h" ] && _usage && exit 0
+
[ ! -d "$ONOS_ROOT" ] && echo "ONOS_ROOT is not defined" >&2 && exit 1
. $ONOS_ROOT/tools/build/envDefaults
diff --git a/framework/src/onos/tools/test/bin/onos-install b/framework/src/onos/tools/test/bin/onos-install
index 7384c2e3..139944e4 100755
--- a/framework/src/onos/tools/test/bin/onos-install
+++ b/framework/src/onos/tools/test/bin/onos-install
@@ -3,6 +3,32 @@
# Remotely pushes bits to a remote node and installs ONOS on it.
# -----------------------------------------------------------------------------
+function _usage () {
+cat << _EOF_
+usage:
+ $(basename $0) [-fn] [-m] <settings> [node]
+
+flags:
+- -f : forces uninstall of currently installed ONOS
+- -n : do not copy over onos.conf upstart configuration file.
+- -m <settings> : pass <settings> XML file to remote maven installation
+
+options:
+- [node] : remote node to install ONOS on.
+
+summary:
+ Remotely pushes bits to a remote node and installs ONOS on it.
+
+ The [-n] flag assumes that Upstart is used. The [-f] flag depends on
+ and 'onos-config'.
+
+ If [node] is not specified the default target is \$OCI.
+
+_EOF_
+}
+
+[ "$1" = "-h" ] && _usage && exit 0
+
[ ! -d "$ONOS_ROOT" ] && echo "ONOS_ROOT is not defined" >&2 && exit 1
. $ONOS_ROOT/tools/build/envDefaults
diff --git a/framework/src/onos/tools/test/bin/onos-push-bits b/framework/src/onos/tools/test/bin/onos-push-bits
index 8c9276fc..4d425c63 100755
--- a/framework/src/onos/tools/test/bin/onos-push-bits
+++ b/framework/src/onos/tools/test/bin/onos-push-bits
@@ -2,6 +2,24 @@
# -----------------------------------------------------------------------------
# Remotely pushes bits to a remote node in preparation for install.
# -----------------------------------------------------------------------------
+function _usage () {
+cat << _EOF_
+usage:
+ $(basename $0) [node]
+
+options:
+- [node] : the target node to prime for installation
+
+summary:
+ Remotely pushes bits to a remote node in preparation for install.
+
+ $(basename $0) is invoked as part of 'onos-install', and shouldn't be
+ directly invoked for the most part.
+
+_EOF_
+}
+
+[ "$1" = "-h" ] && _usage && exit 0
[ ! -d "$ONOS_ROOT" ] && echo "ONOS_ROOT is not defined" >&2 && exit 1
. $ONOS_ROOT/tools/build/envDefaults
diff --git a/framework/src/onos/tools/test/bin/onos-service b/framework/src/onos/tools/test/bin/onos-service
index cc694911..35764e6f 100755
--- a/framework/src/onos/tools/test/bin/onos-service
+++ b/framework/src/onos/tools/test/bin/onos-service
@@ -34,7 +34,6 @@ fi
case $2 in
start|stop|restart|status)
-
# Select the target
if [ "${1}" = "--cell" ]; then
nodes=$(env | sort | egrep "OC[0-9]+" | cut -d= -f2)
diff --git a/framework/src/onos/tools/test/bin/onos-set-controllers b/framework/src/onos/tools/test/bin/onos-set-controllers
index 5b3cd6f7..27cc16c8 100755
--- a/framework/src/onos/tools/test/bin/onos-set-controllers
+++ b/framework/src/onos/tools/test/bin/onos-set-controllers
@@ -6,7 +6,7 @@
controllers=""
for node in $ONOS_INSTANCES; do
- controllers="$controllers tcp:$node:${OF_PORT:-6633}"
+ controllers="$controllers tcp:$node:${OF_PORT:-6653}"
done
ssh ${ONOS_USER:-sdn}@$OCN "
diff --git a/framework/src/onos/tools/test/bin/onos-uninstall b/framework/src/onos/tools/test/bin/onos-uninstall
index 7a8b9a5f..ff8ff536 100755
--- a/framework/src/onos/tools/test/bin/onos-uninstall
+++ b/framework/src/onos/tools/test/bin/onos-uninstall
@@ -3,6 +3,24 @@
# Remotely stops & uninstalls ONOS on the specified node.
# -----------------------------------------------------------------------------
+function _usage () {
+cat << _EOF_
+usage:
+ $(basename $0) [node]
+
+options:
+- [node] : The remote instance to uninstall ONOS from.
+
+summary:
+ Remotely stops and uninstalls ONOS on the specified node.
+
+ If [node] isn't specified, \$OCI becomes the target.
+
+_EOF_
+}
+
+[ "$1" = "-h" ] && _usage && exit 0
+
[ ! -d "$ONOS_ROOT" ] && echo "ONOS_ROOT is not defined" >&2 && exit 1
. $ONOS_ROOT/tools/build/envDefaults
@@ -16,9 +34,12 @@ ssh $remote "
[ -z \"\$(ps -ef | grep karaf.jar | grep -v grep)\" ] && break
sleep 1
done
- [ -z \"\$(ps -ef | grep karaf.jar | grep -v grep)\" ] || echo 'ONOS failed to stop.'
+ [ -z \"\$(ps -ef | grep karaf.jar | grep -v grep)\" ] || \
+ (echo 'ONOS failed to stop.'; status=1)
# Remove onos directory and init file
- sudo rm -fr $ONOS_INSTALL_DIR
- [ -f /etc/init/onos.conf ] && sudo rm /etc/init/onos.conf
+ [ -d $ONOS_INSTALL_DIR ] && sudo rm -fr $ONOS_INSTALL_DIR
+ [ -f /etc/init/onos.conf ] && sudo rm -f /etc/init/onos.conf
+
+ exit \${status:-0};
"
diff --git a/framework/src/onos/tools/test/bin/onos-watch b/framework/src/onos/tools/test/bin/onos-watch
index 28e88c2f..11962f9e 100755
--- a/framework/src/onos/tools/test/bin/onos-watch
+++ b/framework/src/onos/tools/test/bin/onos-watch
@@ -2,6 +2,30 @@
# -----------------------------------------------------------------------------
# Monitors selected set of ONOS commands using the system watch command.
# -----------------------------------------------------------------------------
+function _usage () {
+cat << _EOF_
+usage:
+ $(basename $0) [node] <commands> [watchflags]
+
+options:
+- [node] <commands> : the node to run the commands against
+- [watchflags] : flags to be passed to the watch command.
+
+summary:
+ Monitors selected set of ONOS commands using the system watch command.
+
+ <commands> is a comma-sepatarted list of ONOS CLI commands. If no commands
+ are supplied, the commands run are 'summary', 'intents', 'flows', and
+ 'hosts' against \$OCI.
+
+ Note that [watchflags] only applies to platforms with the Linux-like watch
+ command. For other platforms, the default behavior of watch (refresh every 2
+ s) is emulated.
+
+_EOF_
+}
+
+[ "$1" = "-h" ] && _usage && exit 0
[ ! -d "$ONOS_ROOT" ] && echo "ONOS_ROOT is not defined" >&2 && exit 1
. $ONOS_ROOT/tools/build/envDefaults
@@ -14,4 +38,10 @@ aux=/tmp/onos-watch.$$
trap "rm -f $aux" EXIT
echo "$commands" | tr ',' '\n' > $aux
-watch $3 "onos $node -b <$aux 2>/dev/null"
+
+# emulate watch if not Linux.
+if [ "$(uname)" != "Linux" ]; then
+ while clear; "onos $node -b <$aux 2>/dev/null" ; do sleep 2; done
+else
+ watch $3 "onos $node -b <$aux 2>/dev/null"
+fi
diff --git a/framework/src/onos/tools/test/cells/andrea b/framework/src/onos/tools/test/cells/andrea
new file mode 100644
index 00000000..1f9f22fe
--- /dev/null
+++ b/framework/src/onos/tools/test/cells/andrea
@@ -0,0 +1,11 @@
+# Andrea's ProxMox ONOS instances 1,2,3 & ONOS mininet box
+
+export ONOS_NIC="10.128.12.*"
+export OC1="10.128.12.1"
+export OC2="10.128.12.2"
+export OC3="10.128.12.3"
+export OCN="10.128.12.4"
+
+export OCT=$OC1
+export ONOS_USE_SSH=true
+export ONOS_APPS=drivers,openflow,proxyarp,ovsdb
diff --git a/framework/src/onos/tools/test/cells/tomx b/framework/src/onos/tools/test/cells/tomx
index 3e528ee8..91036e67 100644
--- a/framework/src/onos/tools/test/cells/tomx
+++ b/framework/src/onos/tools/test/cells/tomx
@@ -7,4 +7,5 @@ export OC3="10.128.11.3"
export OCN="10.128.11.4"
export OCT=$OC1
-export ONOS_APPS=drivers,openflow,proxyarp \ No newline at end of file
+export ONOS_USE_SSH=true
+export ONOS_APPS=drivers,openflow,proxyarp,mobility \ No newline at end of file
diff --git a/framework/src/onos/tools/test/scenarios/archetypes.xml b/framework/src/onos/tools/test/scenarios/archetypes.xml
index 8244a32f..5440b55f 100644
--- a/framework/src/onos/tools/test/scenarios/archetypes.xml
+++ b/framework/src/onos/tools/test/scenarios/archetypes.xml
@@ -44,6 +44,24 @@
<step name="Verify-UI" requires="^"
exec="onos-check-views ${OCI} id=sample"/>
+ <step name="Create-App-UI-Table-Overlay" requires="Reinstall-App-With-UI"
+ exec="onos-create-app uitab org.test.app test-app 1.2.3 org.test.app -DinteractiveMode=false"/>
+ <step name="Build-App-With-UI-Table" requires="^"
+ exec="mvn clean install"/>
+ <step name="Reinstall-App-With-UI-Table" requires="^,~Verify-UI"
+ exec="onos-app ${OCI} reinstall! target/test-app-1.2.3.oar"/>
+ <step name="Verify-UI-Table" requires="^"
+ exec="onos-check-views ${OCI} id=sample"/>
+
+ <step name="Create-App-UI-Topo-Overlay" requires="Reinstall-App-With-UI-Table"
+ exec="onos-create-app uitopo org.test.app test-app 1.2.3 org.test.app -DinteractiveMode=false"/>
+ <step name="Build-App-With-UI-Topo" requires="^"
+ exec="mvn clean install"/>
+ <step name="Reinstall-App-With-UI-Topo" requires="^,~Verify-UI-Table"
+ exec="onos-app ${OCI} reinstall! target/test-app-1.2.3.oar"/>
+ <step name="Verify-UI-Topo" requires="^"
+ exec="onos-check-views ${OCI} id=sample"/>
+
<step name="Uninstall-App" requires="^"
exec="onos-app ${OCI} uninstall org.foo.app"/>
</group>
diff --git a/framework/src/onos/tools/test/topos/onos.py b/framework/src/onos/tools/test/topos/onos.py
index ae6045e3..f9d4ba23 100755
--- a/framework/src/onos/tools/test/topos/onos.py
+++ b/framework/src/onos/tools/test/topos/onos.py
@@ -31,7 +31,7 @@ class ONOS( Controller ):
Controller.__init__( self, name, **kwargs )
# the following have been done for us:
#self.ip = ip ('127.0.0.1')
- #self.port = port (6633)
+ #self.port = port (6653)
#self.protocol = protocol ('tcp')
#self.checkListening()
diff --git a/framework/src/onos/tools/test/topos/optical2.py b/framework/src/onos/tools/test/topos/optical2.py
index 36cdbadd..b778592c 100644
--- a/framework/src/onos/tools/test/topos/optical2.py
+++ b/framework/src/onos/tools/test/topos/optical2.py
@@ -69,7 +69,7 @@ topos = {'optical': ( lambda: OpticalTopo() )}
def run():
- c = RemoteController('c','127.0.0.1',6633)
+ c = RemoteController('c','127.0.0.1',6653)
net = Mininet( topo=OpticalTopo(),controller=None,autoSetMacs=True)
net.addController(c)
net.start()
diff --git a/framework/src/onos/tools/test/topos/solar.py b/framework/src/onos/tools/test/topos/solar.py
index ea11b664..f316162a 100644
--- a/framework/src/onos/tools/test/topos/solar.py
+++ b/framework/src/onos/tools/test/topos/solar.py
@@ -23,7 +23,7 @@ class Solar(object):
# We are creating the controller with local-loopback on purpose to avoid
# having the switches connect immediately. Instead, we'll set controller
# explicitly for each switch after configuring it as we want.
- self.ctrls = [ RemoteController(cname, cip, 6633) for cip in cips ]
+ self.ctrls = [ RemoteController(cname, cip, 6653) for cip in cips ]
self.net = Mininet(controller=RemoteController, switch = OVSKernelSwitch,
build=False)
diff --git a/framework/src/onos/tools/test/topos/sys-nonlinear-10.config b/framework/src/onos/tools/test/topos/sys-nonlinear-10.config
index 2b999d39..b3a718dd 100644
--- a/framework/src/onos/tools/test/topos/sys-nonlinear-10.config
+++ b/framework/src/onos/tools/test/topos/sys-nonlinear-10.config
@@ -56,7 +56,7 @@
[{switch,1,
[{backend,linc_us4_oe},
{datapath_id,"00:00:ff:ff:ff:ff:ff:01"},
- {controllers,[{"Switch0-Controller","10.1.8.147",6633,tcp}]},
+ {controllers,[{"Switch0-Controller","10.1.8.147",6653,tcp}]},
{controllers_listener,disabled},
{queues_status,disabled},
{ports,
@@ -66,7 +66,7 @@
{switch,2,
[{backend,linc_us4_oe},
{datapath_id,"00:00:ff:ff:ff:ff:ff:02"},
- {controllers,[{"Switch0-Controller","10.1.8.147",6633,tcp}]},
+ {controllers,[{"Switch0-Controller","10.1.8.147",6653,tcp}]},
{controllers_listener,disabled},
{queues_status,disabled},
{ports,
@@ -76,7 +76,7 @@
{switch,3,
[{backend,linc_us4_oe},
{datapath_id,"00:00:ff:ff:ff:ff:ff:03"},
- {controllers,[{"Switch0-Controller","10.1.8.147",6633,tcp}]},
+ {controllers,[{"Switch0-Controller","10.1.8.147",6653,tcp}]},
{controllers_listener,disabled},
{queues_status,disabled},
{ports,
@@ -86,7 +86,7 @@
{switch,4,
[{backend,linc_us4_oe},
{datapath_id,"00:00:ff:ff:ff:ff:ff:04"},
- {controllers,[{"Switch0-Controller","10.1.8.147",6633,tcp}]},
+ {controllers,[{"Switch0-Controller","10.1.8.147",6653,tcp}]},
{controllers_listener,disabled},
{queues_status,disabled},
{ports,
@@ -96,7 +96,7 @@
{switch,5,
[{backend,linc_us4_oe},
{datapath_id,"00:00:ff:ff:ff:ff:ff:05"},
- {controllers,[{"Switch0-Controller","10.1.8.147",6633,tcp}]},
+ {controllers,[{"Switch0-Controller","10.1.8.147",6653,tcp}]},
{controllers_listener,disabled},
{queues_status,disabled},
{ports,
@@ -107,7 +107,7 @@
{switch,7,
[{backend,linc_us4_oe},
{datapath_id,"00:00:ff:ff:ff:ff:ff:07"},
- {controllers,[{"Switch0-Controller","10.1.8.147",6633,tcp}]},
+ {controllers,[{"Switch0-Controller","10.1.8.147",6653,tcp}]},
{controllers_listener,disabled},
{queues_status,disabled},
{ports,
@@ -118,7 +118,7 @@
{switch,8,
[{backend,linc_us4_oe},
{datapath_id,"00:00:ff:ff:ff:ff:ff:08"},
- {controllers,[{"Switch0-Controller","10.1.8.147",6633,tcp}]},
+ {controllers,[{"Switch0-Controller","10.1.8.147",6653,tcp}]},
{controllers_listener,disabled},
{queues_status,disabled},
{ports,
@@ -128,7 +128,7 @@
{switch,9,
[{backend,linc_us4_oe},
{datapath_id,"00:00:ff:ff:ff:ff:ff:09"},
- {controllers,[{"Switch0-Controller","10.1.8.147",6633,tcp}]},
+ {controllers,[{"Switch0-Controller","10.1.8.147",6653,tcp}]},
{controllers_listener,disabled},
{queues_status,disabled},
{ports,
@@ -138,7 +138,7 @@
{switch,10,
[{backend,linc_us4_oe},
{datapath_id,"00:00:ff:ff:ff:ff:ff:0A"},
- {controllers,[{"Switch0-Controller","10.1.8.147",6633,tcp}]},
+ {controllers,[{"Switch0-Controller","10.1.8.147",6653,tcp}]},
{controllers_listener,disabled},
{queues_status,disabled},
{ports,
@@ -148,7 +148,7 @@
{switch,6,
[{backend,linc_us4_oe},
{datapath_id,"00:00:ff:ff:ff:ff:ff:06"},
- {controllers,[{"Switch0-Controller","10.1.8.147",6633,tcp}]},
+ {controllers,[{"Switch0-Controller","10.1.8.147",6653,tcp}]},
{controllers_listener,disabled},
{queues_status,disabled},
{ports,
diff --git a/framework/src/onos/tools/test/topos/sys-nonlinear-4.config b/framework/src/onos/tools/test/topos/sys-nonlinear-4.config
index b843146a..b1451bee 100644
--- a/framework/src/onos/tools/test/topos/sys-nonlinear-4.config
+++ b/framework/src/onos/tools/test/topos/sys-nonlinear-4.config
@@ -18,7 +18,7 @@
[{switch,1,
[{backend,linc_us4_oe},
{datapath_id,"00:00:ff:ff:ff:ff:ff:01"},
- {controllers,[{"Switch0-Controller","10.1.8.147",6633,tcp}]},
+ {controllers,[{"Switch0-Controller","10.1.8.147",6653,tcp}]},
{controllers_listener,disabled},
{queues_status,disabled},
{ports,
@@ -28,7 +28,7 @@
{switch,3,
[{backend,linc_us4_oe},
{datapath_id,"00:00:ff:ff:ff:ff:ff:03"},
- {controllers,[{"Switch0-Controller","10.1.8.147",6633,tcp}]},
+ {controllers,[{"Switch0-Controller","10.1.8.147",6653,tcp}]},
{controllers_listener,disabled},
{queues_status,disabled},
{ports,
@@ -37,7 +37,7 @@
{switch,2,
[{backend,linc_us4_oe},
{datapath_id,"00:00:ff:ff:ff:ff:ff:02"},
- {controllers,[{"Switch0-Controller","10.1.8.147",6633,tcp}]},
+ {controllers,[{"Switch0-Controller","10.1.8.147",6653,tcp}]},
{controllers_listener,disabled},
{queues_status,disabled},
{ports,
@@ -47,7 +47,7 @@
{switch,4,
[{backend,linc_us4_oe},
{datapath_id,"00:00:ff:ff:ff:ff:ff:04"},
- {controllers,[{"Switch0-Controller","10.1.8.147",6633,tcp}]},
+ {controllers,[{"Switch0-Controller","10.1.8.147",6653,tcp}]},
{controllers_listener,disabled},
{queues_status,disabled},
{ports,
diff --git a/framework/src/onos/tools/test/topos/sys.config b/framework/src/onos/tools/test/topos/sys.config
index 2b999d39..b3a718dd 100644
--- a/framework/src/onos/tools/test/topos/sys.config
+++ b/framework/src/onos/tools/test/topos/sys.config
@@ -56,7 +56,7 @@
[{switch,1,
[{backend,linc_us4_oe},
{datapath_id,"00:00:ff:ff:ff:ff:ff:01"},
- {controllers,[{"Switch0-Controller","10.1.8.147",6633,tcp}]},
+ {controllers,[{"Switch0-Controller","10.1.8.147",6653,tcp}]},
{controllers_listener,disabled},
{queues_status,disabled},
{ports,
@@ -66,7 +66,7 @@
{switch,2,
[{backend,linc_us4_oe},
{datapath_id,"00:00:ff:ff:ff:ff:ff:02"},
- {controllers,[{"Switch0-Controller","10.1.8.147",6633,tcp}]},
+ {controllers,[{"Switch0-Controller","10.1.8.147",6653,tcp}]},
{controllers_listener,disabled},
{queues_status,disabled},
{ports,
@@ -76,7 +76,7 @@
{switch,3,
[{backend,linc_us4_oe},
{datapath_id,"00:00:ff:ff:ff:ff:ff:03"},
- {controllers,[{"Switch0-Controller","10.1.8.147",6633,tcp}]},
+ {controllers,[{"Switch0-Controller","10.1.8.147",6653,tcp}]},
{controllers_listener,disabled},
{queues_status,disabled},
{ports,
@@ -86,7 +86,7 @@
{switch,4,
[{backend,linc_us4_oe},
{datapath_id,"00:00:ff:ff:ff:ff:ff:04"},
- {controllers,[{"Switch0-Controller","10.1.8.147",6633,tcp}]},
+ {controllers,[{"Switch0-Controller","10.1.8.147",6653,tcp}]},
{controllers_listener,disabled},
{queues_status,disabled},
{ports,
@@ -96,7 +96,7 @@
{switch,5,
[{backend,linc_us4_oe},
{datapath_id,"00:00:ff:ff:ff:ff:ff:05"},
- {controllers,[{"Switch0-Controller","10.1.8.147",6633,tcp}]},
+ {controllers,[{"Switch0-Controller","10.1.8.147",6653,tcp}]},
{controllers_listener,disabled},
{queues_status,disabled},
{ports,
@@ -107,7 +107,7 @@
{switch,7,
[{backend,linc_us4_oe},
{datapath_id,"00:00:ff:ff:ff:ff:ff:07"},
- {controllers,[{"Switch0-Controller","10.1.8.147",6633,tcp}]},
+ {controllers,[{"Switch0-Controller","10.1.8.147",6653,tcp}]},
{controllers_listener,disabled},
{queues_status,disabled},
{ports,
@@ -118,7 +118,7 @@
{switch,8,
[{backend,linc_us4_oe},
{datapath_id,"00:00:ff:ff:ff:ff:ff:08"},
- {controllers,[{"Switch0-Controller","10.1.8.147",6633,tcp}]},
+ {controllers,[{"Switch0-Controller","10.1.8.147",6653,tcp}]},
{controllers_listener,disabled},
{queues_status,disabled},
{ports,
@@ -128,7 +128,7 @@
{switch,9,
[{backend,linc_us4_oe},
{datapath_id,"00:00:ff:ff:ff:ff:ff:09"},
- {controllers,[{"Switch0-Controller","10.1.8.147",6633,tcp}]},
+ {controllers,[{"Switch0-Controller","10.1.8.147",6653,tcp}]},
{controllers_listener,disabled},
{queues_status,disabled},
{ports,
@@ -138,7 +138,7 @@
{switch,10,
[{backend,linc_us4_oe},
{datapath_id,"00:00:ff:ff:ff:ff:ff:0A"},
- {controllers,[{"Switch0-Controller","10.1.8.147",6633,tcp}]},
+ {controllers,[{"Switch0-Controller","10.1.8.147",6653,tcp}]},
{controllers_listener,disabled},
{queues_status,disabled},
{ports,
@@ -148,7 +148,7 @@
{switch,6,
[{backend,linc_us4_oe},
{datapath_id,"00:00:ff:ff:ff:ff:ff:06"},
- {controllers,[{"Switch0-Controller","10.1.8.147",6633,tcp}]},
+ {controllers,[{"Switch0-Controller","10.1.8.147",6653,tcp}]},
{controllers_listener,disabled},
{queues_status,disabled},
{ports,
diff --git a/framework/src/onos/utils/junit/src/main/java/org/onlab/junit/TestUtils.java b/framework/src/onos/utils/junit/src/main/java/org/onlab/junit/TestUtils.java
index 1afc4948..686a9a59 100644
--- a/framework/src/onos/utils/junit/src/main/java/org/onlab/junit/TestUtils.java
+++ b/framework/src/onos/utils/junit/src/main/java/org/onlab/junit/TestUtils.java
@@ -64,27 +64,40 @@ public final class TestUtils {
/**
* Gets the field, bypassing scope restriction.
*
- * @param subject Object where the field belongs
+ * @param subject Object where the field belongs
* @param fieldName name of the field to get
+ * @param <T> subject type
+ * @param <U> fieldO value type
* @return value of the field.
- * @param <T> subject type
- * @param <U> field value type
* @throws TestUtilsException if there are reflection errors while getting
- * the field
+ * the field
*/
public static <T, U> U getField(T subject, String fieldName)
throws TestUtilsException {
try {
+ NoSuchFieldException exception = null;
@SuppressWarnings("unchecked")
- Class<T> clazz = (Class<T>) subject.getClass();
- Field field = clazz.getDeclaredField(fieldName);
- field.setAccessible(true);
+ Class clazz = subject.getClass();
+ while (clazz != null) {
+ try {
+ Field field = clazz.getDeclaredField(fieldName);
+ field.setAccessible(true);
- @SuppressWarnings("unchecked")
- U result = (U) field.get(subject);
- return result;
- } catch (NoSuchFieldException | SecurityException |
- IllegalArgumentException | IllegalAccessException e) {
+ @SuppressWarnings("unchecked")
+ U result = (U) field.get(subject);
+ return result;
+ } catch (NoSuchFieldException e) {
+ exception = e;
+ if (clazz == clazz.getSuperclass()) {
+ break;
+ }
+ clazz = clazz.getSuperclass();
+ }
+ }
+ throw new TestUtilsException("Field not found. " + fieldName, exception);
+
+ } catch (SecurityException |
+ IllegalArgumentException | IllegalAccessException e) {
throw new TestUtilsException("getField failed", e);
}
}
diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/DisjointPathPair.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/DisjointPathPair.java
index b62d3b24..206a34c8 100644
--- a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/DisjointPathPair.java
+++ b/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/DisjointPathPair.java
@@ -19,52 +19,67 @@ package org.onlab.graph;
import java.util.List;
import java.util.Objects;
-import java.util.Set;
-import static com.google.common.collect.ImmutableSet.of;
import static com.google.common.base.MoreObjects.toStringHelper;
-
+/**
+ * Pair of disjoint paths.
+ *
+ * @param <V> type of vertex
+ * @param <E> type of edge
+ */
public class DisjointPathPair<V extends Vertex, E extends Edge<V>> implements Path<V, E> {
- public Path<V, E> path1, path2;
- boolean usingPath1 = true;
+
+ private Path<V, E> primary, secondary;
+ boolean primaryActive = true;
/**
- * Creates a Disjoint Path Pair from two paths.
+ * Creates a disjoint path pair from two paths.
*
- * @param p1 first path
- * @param p2 second path
+ * @param primary primary path
+ * @param secondary secondary path
*/
- public DisjointPathPair(Path<V, E> p1, Path<V, E> p2) {
- path1 = p1;
- path2 = p2;
+ public DisjointPathPair(Path<V, E> primary, Path<V, E> secondary) {
+ this.primary = primary;
+ this.secondary = secondary;
}
@Override
public V src() {
- return path1.src();
+ return primary.src();
}
@Override
public V dst() {
- return path1.dst();
+ return primary.dst();
+ }
+
+ /**
+ * Returns the primary path.
+ *
+ * @return primary path
+ */
+ public Path<V, E> primary() {
+ return primary;
+ }
+
+ /**
+ * Returns the secondary path.
+ *
+ * @return primary path
+ */
+ public Path<V, E> secondary() {
+ return secondary;
}
@Override
public double cost() {
- if (!hasBackup()) {
- return path1.cost();
- }
- return path1.cost() + path2.cost();
+ return hasBackup() ? primary.cost() + secondary.cost() : primary.cost();
}
@Override
public List<E> edges() {
- if (usingPath1 || !hasBackup()) {
- return path1.edges();
- } else {
- return path2.edges();
- }
+ return primaryActive || !hasBackup() ? primary.edges() : secondary.edges();
}
/**
@@ -73,7 +88,7 @@ public class DisjointPathPair<V extends Vertex, E extends Edge<V>> implements Pa
* @return boolean representing whether it has backup
*/
public boolean hasBackup() {
- return path2 != null && path2.edges() != null;
+ return secondary != null && secondary.edges() != null;
}
@Override
@@ -88,13 +103,8 @@ public class DisjointPathPair<V extends Vertex, E extends Edge<V>> implements Pa
@Override
public int hashCode() {
- Set<Path<V, E>> paths;
- if (!hasBackup()) {
- paths = of(path1);
- } else {
- paths = of(path1, path2);
- }
- return Objects.hash(paths);
+ return hasBackup() ? Objects.hash(primary) + Objects.hash(secondary) :
+ Objects.hash(primary);
}
@Override
@@ -106,10 +116,10 @@ public class DisjointPathPair<V extends Vertex, E extends Edge<V>> implements Pa
final DisjointPathPair other = (DisjointPathPair) obj;
return Objects.equals(this.src(), other.src()) &&
Objects.equals(this.dst(), other.dst()) &&
- (Objects.equals(this.path1, other.path1) &&
- Objects.equals(this.path2, other.path2)) ||
- (Objects.equals(this.path1, other.path2) &&
- Objects.equals(this.path2, other.path1));
+ (Objects.equals(this.primary, other.primary) &&
+ Objects.equals(this.secondary, other.secondary)) ||
+ (Objects.equals(this.primary, other.secondary) &&
+ Objects.equals(this.secondary, other.primary));
}
return false;
}
@@ -120,9 +130,6 @@ public class DisjointPathPair<V extends Vertex, E extends Edge<V>> implements Pa
* @return number of paths
*/
public int size() {
- if (hasBackup()) {
- return 2;
- }
- return 1;
+ return hasBackup() ? 2 : 1;
}
}
diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrGroup.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrGroup.java
index 891a0193..be4ab19a 100644
--- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrGroup.java
+++ b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrGroup.java
@@ -241,7 +241,7 @@ public class PIMAddrGroup {
return false;
}
final PIMAddrGroup other = (PIMAddrGroup) obj;
- if (this.family != this.family) {
+ if (this.family != other.family) {
return false;
}
diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrSource.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrSource.java
index 2d4a7816..21526408 100644
--- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrSource.java
+++ b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrSource.java
@@ -265,7 +265,7 @@ public class PIMAddrSource {
return false;
}
final PIMAddrSource other = (PIMAddrSource) obj;
- if (this.family != this.family) {
+ if (this.family != other.family) {
return false;
}
diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrUnicast.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrUnicast.java
index 0c2d676b..a6ba3895 100644
--- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrUnicast.java
+++ b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrUnicast.java
@@ -166,7 +166,7 @@ public class PIMAddrUnicast {
return false;
}
final PIMAddrUnicast other = (PIMAddrUnicast) obj;
- if (this.family != this.family) {
+ if (this.family != other.family) {
return false;
}
diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/HexDump.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/HexDump.java
new file mode 100755
index 00000000..cfb79390
--- /dev/null
+++ b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/HexDump.java
@@ -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.onlab.util;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * HexDump class an utility to dump buffer in hex format.
+ */
+public final class HexDump {
+ protected static final Logger log = LoggerFactory.getLogger(HexDump.class);
+
+ private HexDump() {
+ }
+
+ /**
+ * Dump the buffer content in hex format.
+ *
+ * @param buff buffer content to dump in hex format
+ */
+ public static void dump(ChannelBuffer buff) {
+ try {
+ byte[] yTemp;
+ yTemp = buff.array();
+
+ int iStartIndex = buff.readerIndex();
+ int iEndIndex = buff.writerIndex();
+ do {
+ StringBuilder sb = new StringBuilder();
+ for (int k = 0; (k < 16) && (iStartIndex < iEndIndex); ++k) {
+ if (0 == k % 4) {
+ sb.append(String.format(" ")); // blank after 4 bytes
+ }
+ sb.append(String.format("%02X ", yTemp[iStartIndex++]));
+ }
+ log.debug(sb.toString());
+ } while (iStartIndex < iEndIndex);
+ } catch (Exception e) {
+ log.error("[HexDump] Invalid buffer: " + e.toString());
+ }
+ }
+}
diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/Tools.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/Tools.java
index abc48ccf..1b788145 100644
--- a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/Tools.java
+++ b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/Tools.java
@@ -299,12 +299,14 @@ public abstract class Tools {
*
* @param path file path
* @return file contents
+ * @deprecated in Emu release
*/
+ @Deprecated
public static List<String> slurp(File path) {
- try {
+ try (
BufferedReader br = new BufferedReader(
new InputStreamReader(new FileInputStream(path), StandardCharsets.UTF_8));
-
+ ) {
List<String> lines = new ArrayList<>();
String line;
while ((line = br.readLine()) != null) {
diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/SRLGGraphSearchTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/SRLGGraphSearchTest.java
index 885fbe5c..8bfd270c 100644
--- a/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/SRLGGraphSearchTest.java
+++ b/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/SRLGGraphSearchTest.java
@@ -17,44 +17,37 @@
package org.onlab.graph;
import org.junit.Test;
-import java.util.Set;
+
+import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
-import java.util.HashMap;
+import java.util.Set;
import static com.google.common.collect.ImmutableSet.of;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-
-
+import static org.onlab.graph.GraphPathSearch.ALL_PATHS;
/**
* Test of the Suurballe backup path algorithm.
*/
public class SRLGGraphSearchTest extends BreadthFirstSearchTest {
+
@Override
protected AbstractGraphPathSearch<TestVertex, TestEdge> graphSearch() {
- return new SRLGGraphSearch<TestVertex, TestEdge>(null);
+ return new SRLGGraphSearch<>(null);
}
- public void setWeights() {
- weight = new EdgeWeight<TestVertex, TestEdge>() {
- @Override
- public double weight(TestEdge edge) {
- return edge.weight();
- }
- };
- }
public void setDefaultWeights() {
weight = null;
}
+
@Override
public void defaultGraphTest() {
-
}
@Override
public void defaultHopCountWeight() {
-
}
@Test
@@ -66,34 +59,34 @@ public class SRLGGraphSearchTest extends BreadthFirstSearchTest {
TestEdge dC = new TestEdge(D, C, 1);
Graph<TestVertex, TestEdge> graph = new AdjacencyListsGraph<>(of(A, B, C, D),
of(aB, bC, aD, dC));
- Map<TestEdge, Integer> riskProfile = new HashMap<TestEdge, Integer>();
+ Map<TestEdge, Integer> riskProfile = new HashMap<>();
riskProfile.put(aB, 0);
riskProfile.put(bC, 0);
riskProfile.put(aD, 1);
riskProfile.put(dC, 1);
- SRLGGraphSearch<TestVertex, TestEdge> search =
- new SRLGGraphSearch<TestVertex, TestEdge>(2, riskProfile);
- Set<Path<TestVertex, TestEdge>> paths = search.search(graph, A, C, weight, GraphPathSearch.ALL_PATHS).paths();
+ SRLGGraphSearch<TestVertex, TestEdge> search = new SRLGGraphSearch<>(2, riskProfile);
+ Set<Path<TestVertex, TestEdge>> paths = search.search(graph, A, C, weight, ALL_PATHS).paths();
System.out.println("\n\n\n" + paths + "\n\n\n");
- assertTrue("one disjoint path pair found", paths.size() == 1);
+ assertEquals("one disjoint path pair found", 1, paths.size());
checkIsDisjoint(paths.iterator().next(), riskProfile);
}
+
public void checkIsDisjoint(Path<TestVertex, TestEdge> p, Map<TestEdge, Integer> risks) {
assertTrue("The path is not a DisjointPathPair", (p instanceof DisjointPathPair));
DisjointPathPair<TestVertex, TestEdge> q = (DisjointPathPair) p;
- Set<Integer> p1Risks = new HashSet<Integer>();
- Set<Integer> p2Risks = new HashSet<Integer>();
- for (TestEdge e: q.edges()) {
+ Set<Integer> p1Risks = new HashSet<>();
+ for (TestEdge e : q.edges()) {
p1Risks.add(risks.get(e));
}
if (!q.hasBackup()) {
return;
}
- Path<TestVertex, TestEdge> pq = q.path2;
+ Path<TestVertex, TestEdge> pq = q.secondary();
for (TestEdge e: pq.edges()) {
assertTrue("The paths are not disjoint", !p1Risks.contains(risks.get(e)));
}
}
+
@Test
public void complexGraphTest() {
setDefaultWeights();
@@ -105,16 +98,15 @@ public class SRLGGraphSearchTest extends BreadthFirstSearchTest {
TestEdge bE = new TestEdge(B, E, 1);
Graph<TestVertex, TestEdge> graph = new AdjacencyListsGraph<>(of(A, B, C, D, E),
of(aB, bC, aD, dC, cE, bE));
- Map<TestEdge, Integer> riskProfile = new HashMap<TestEdge, Integer>();
+ Map<TestEdge, Integer> riskProfile = new HashMap<>();
riskProfile.put(aB, 0);
riskProfile.put(bC, 0);
riskProfile.put(aD, 1);
riskProfile.put(dC, 1);
riskProfile.put(cE, 2);
riskProfile.put(bE, 3);
- SRLGGraphSearch<TestVertex, TestEdge> search =
- new SRLGGraphSearch<TestVertex, TestEdge>(4, riskProfile);
- Set<Path<TestVertex, TestEdge>> paths = search.search(graph, A, E, weight, GraphPathSearch.ALL_PATHS).paths();
+ SRLGGraphSearch<TestVertex, TestEdge> search = new SRLGGraphSearch<>(4, riskProfile);
+ search.search(graph, A, E, weight, ALL_PATHS).paths();
}
@Test
@@ -128,19 +120,19 @@ public class SRLGGraphSearchTest extends BreadthFirstSearchTest {
TestEdge cE = new TestEdge(C, E, 1);
Graph<TestVertex, TestEdge> graph = new AdjacencyListsGraph<>(of(A, B, C, D, E),
of(aB, bE, aD, dE, aC, cE));
- Map<TestEdge, Integer> riskProfile = new HashMap<TestEdge, Integer>();
+ Map<TestEdge, Integer> riskProfile = new HashMap<>();
riskProfile.put(aB, 0);
riskProfile.put(bE, 1);
riskProfile.put(aD, 2);
riskProfile.put(dE, 3);
riskProfile.put(aC, 4);
riskProfile.put(cE, 5);
- SRLGGraphSearch<TestVertex, TestEdge> search =
- new SRLGGraphSearch<TestVertex, TestEdge>(6, riskProfile);
- Set<Path<TestVertex, TestEdge>> paths = search.search(graph, A, E, weight, GraphPathSearch.ALL_PATHS).paths();
+ SRLGGraphSearch<TestVertex, TestEdge> search = new SRLGGraphSearch<>(6, riskProfile);
+ Set<Path<TestVertex, TestEdge>> paths = search.search(graph, A, E, weight, ALL_PATHS).paths();
assertTrue("> one disjoint path pair found", paths.size() >= 1);
checkIsDisjoint(paths.iterator().next(), riskProfile);
}
+
@Test
public void onePath() {
setDefaultWeights();
@@ -150,17 +142,17 @@ public class SRLGGraphSearchTest extends BreadthFirstSearchTest {
TestEdge dC = new TestEdge(D, C, 1);
Graph<TestVertex, TestEdge> graph = new AdjacencyListsGraph<>(of(A, B, C, D),
of(aB, bC, aD, dC));
- Map<TestEdge, Integer> riskProfile = new HashMap<TestEdge, Integer>();
+ Map<TestEdge, Integer> riskProfile = new HashMap<>();
riskProfile.put(aB, 0);
riskProfile.put(bC, 0);
riskProfile.put(aD, 1);
riskProfile.put(dC, 0);
- SRLGGraphSearch<TestVertex, TestEdge> search =
- new SRLGGraphSearch<TestVertex, TestEdge>(2, riskProfile);
- Set<Path<TestVertex, TestEdge>> paths = search.search(graph, A, C, weight, GraphPathSearch.ALL_PATHS).paths();
+ SRLGGraphSearch<TestVertex, TestEdge> search = new SRLGGraphSearch<>(2, riskProfile);
+ Set<Path<TestVertex, TestEdge>> paths = search.search(graph, A, C, weight, ALL_PATHS).paths();
System.out.println(paths);
assertTrue("no disjoint path pairs found", paths.size() == 0);
}
+
@Test
public void noPath() {
setDefaultWeights();
@@ -175,9 +167,8 @@ public class SRLGGraphSearchTest extends BreadthFirstSearchTest {
riskProfile.put(bC, 0);
riskProfile.put(aD, 1);
riskProfile.put(dC, 0);
- SRLGGraphSearch<TestVertex, TestEdge> search =
- new SRLGGraphSearch<>(2, riskProfile);
- Set<Path<TestVertex, TestEdge>> paths = search.search(graph, A, E, weight, GraphPathSearch.ALL_PATHS).paths();
+ SRLGGraphSearch<TestVertex, TestEdge> search = new SRLGGraphSearch<>(2, riskProfile);
+ Set<Path<TestVertex, TestEdge>> paths = search.search(graph, A, E, weight, ALL_PATHS).paths();
assertTrue("no disjoint path pairs found", paths.size() == 0);
}
}
diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/AbstractAccumulatorTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/AbstractAccumulatorTest.java
index 02f0deb1..db7224ad 100644
--- a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/AbstractAccumulatorTest.java
+++ b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/AbstractAccumulatorTest.java
@@ -15,23 +15,24 @@
*/
package org.onlab.util;
-import org.junit.Ignore;
import org.junit.Test;
import java.util.List;
-import java.util.Timer;
import java.util.stream.IntStream;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.onlab.junit.TestTools.assertAfter;
-import static org.onlab.junit.TestTools.delay;
/**
* Tests the operation of the accumulator.
*/
public class AbstractAccumulatorTest {
- private final Timer timer = new Timer();
+
+ private final ManuallyAdvancingTimer timer = new ManuallyAdvancingTimer();
+
@Test
public void basics() throws Exception {
@@ -42,7 +43,6 @@ public class AbstractAccumulatorTest {
assertEquals("incorrect idle ms", 70, accumulator.maxIdleMillis());
}
- @Ignore("FIXME: timing sensitive test failing randomly.")
@Test
public void eventTrigger() {
TestAccumulator accumulator = new TestAccumulator();
@@ -52,43 +52,40 @@ public class AbstractAccumulatorTest {
accumulator.add(new TestItem("d"));
assertTrue("should not have fired yet", accumulator.batch.isEmpty());
accumulator.add(new TestItem("e"));
- delay(20);
+ timer.advanceTimeMillis(20, 10);
assertFalse("should have fired", accumulator.batch.isEmpty());
assertEquals("incorrect batch", "abcde", accumulator.batch);
}
- @Ignore("FIXME: timing sensitive test failing randomly.")
@Test
public void timeTrigger() {
TestAccumulator accumulator = new TestAccumulator();
accumulator.add(new TestItem("a"));
- delay(30);
+ timer.advanceTimeMillis(30, 1);
assertTrue("should not have fired yet", accumulator.batch.isEmpty());
accumulator.add(new TestItem("b"));
- delay(30);
+ timer.advanceTimeMillis(30, 1);
assertTrue("should not have fired yet", accumulator.batch.isEmpty());
accumulator.add(new TestItem("c"));
- delay(30);
+ timer.advanceTimeMillis(30, 1);
assertTrue("should not have fired yet", accumulator.batch.isEmpty());
accumulator.add(new TestItem("d"));
- delay(60);
+ timer.advanceTimeMillis(10, 10);
assertFalse("should have fired", accumulator.batch.isEmpty());
assertEquals("incorrect batch", "abcd", accumulator.batch);
}
- @Ignore("FIXME: timing sensitive test failing randomly.")
@Test
public void idleTrigger() {
TestAccumulator accumulator = new TestAccumulator();
accumulator.add(new TestItem("a"));
assertTrue("should not have fired yet", accumulator.batch.isEmpty());
accumulator.add(new TestItem("b"));
- delay(80);
+ timer.advanceTimeMillis(70, 10);
assertFalse("should have fired", accumulator.batch.isEmpty());
assertEquals("incorrect batch", "ab", accumulator.batch);
}
- @Ignore("FIXME: timing sensitive test failing randomly.")
@Test
public void readyIdleTrigger() {
TestAccumulator accumulator = new TestAccumulator();
@@ -96,30 +93,28 @@ public class AbstractAccumulatorTest {
accumulator.add(new TestItem("a"));
assertTrue("should not have fired yet", accumulator.batch.isEmpty());
accumulator.add(new TestItem("b"));
- delay(80);
+ timer.advanceTimeMillis(80, 1);
assertTrue("should not have fired yet", accumulator.batch.isEmpty());
accumulator.ready = true;
- delay(80);
+ timer.advanceTimeMillis(80, 10);
assertFalse("should have fired", accumulator.batch.isEmpty());
assertEquals("incorrect batch", "ab", accumulator.batch);
}
- @Ignore("FIXME: timing sensitive test failing randomly.")
@Test
public void readyLongTrigger() {
TestAccumulator accumulator = new TestAccumulator();
accumulator.ready = false;
- delay(120);
+ timer.advanceTimeMillis(120, 1);
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;
- delay(80);
+ timer.advanceTimeMillis(120, 10);
assertFalse("should have fired", accumulator.batch.isEmpty());
assertEquals("incorrect batch", "a", accumulator.batch);
}
- @Ignore("FIXME: timing sensitive test failing randomly.")
@Test
public void readyMaxTrigger() {
TestAccumulator accumulator = new TestAccumulator();
@@ -133,16 +128,16 @@ public class AbstractAccumulatorTest {
assertTrue("should not have fired yet", accumulator.batch.isEmpty());
accumulator.ready = true;
accumulator.add(new TestItem("g"));
- delay(5);
+ timer.advanceTimeMillis(10, 10);
assertFalse("should have fired", accumulator.batch.isEmpty());
assertEquals("incorrect batch", "abcdefg", accumulator.batch);
}
- @Ignore("FIXME: timing sensitive test failing randomly.")
@Test
public void stormTest() {
TestAccumulator accumulator = new TestAccumulator();
IntStream.range(0, 1000).forEach(i -> accumulator.add(new TestItem("#" + i)));
+ timer.advanceTimeMillis(1);
assertAfter(100, () -> assertEquals("wrong item count", 1000, accumulator.itemCount));
assertEquals("wrong batch count", 200, accumulator.batchCount);
}
@@ -180,5 +175,4 @@ public class AbstractAccumulatorTest {
return ready;
}
}
-
}
diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/ManuallyAdvancingTimer.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/ManuallyAdvancingTimer.java
new file mode 100644
index 00000000..4116cbef
--- /dev/null
+++ b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/ManuallyAdvancingTimer.java
@@ -0,0 +1,504 @@
+/*
+ * 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.onlab.util;
+
+import com.google.common.collect.Lists;
+import org.onlab.junit.TestUtils;
+import org.slf4j.Logger;
+
+import java.util.Date;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.TimerTask;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.junit.TestTools.delay;
+import static org.slf4j.LoggerFactory.getLogger;
+
+
+/**
+ * Provides manually scheduled timer utility. All schedulable methods are subject to overflow (you can set a period of
+ * max long). Additionally if a skip skips a period of time greater than one period for a periodic task that task will
+ * only be executed once for that skip and scheduled it's period after the last execution.
+ */
+public class ManuallyAdvancingTimer extends java.util.Timer {
+
+ /* States whether or not the static values from timer task have been set ensures population will only occur once.*/
+ private boolean staticsPopulated = false;
+
+ /* Virgin value from timer task */
+ private int virginState;
+
+ /* Scheduled value from timer task */
+ private int scheduledState;
+
+ /* Executed value from timer task */
+ private int executedState;
+
+ /* Cancelled value from timer task */
+ private int cancelledState;
+
+ private final Logger logger = getLogger(getClass());
+
+ /* Service for executing timer tasks */
+ private final ExecutorService executorService = Executors.newSingleThreadExecutor();
+
+ /* Internal time representation independent of system time, manually advanced */
+ private final TimerKeeper timerKeeper = new TimerKeeper();
+
+ /* Data structure for tracking tasks */
+ private final TaskQueue queue = new TaskQueue();
+
+ @Override
+ public void schedule(TimerTask task, long delay) {
+ if (!staticsPopulated) {
+ populateStatics(task);
+ }
+ if (!submitTask(task, delay > 0 ? timerKeeper.currentTimeInMillis() + delay :
+ timerKeeper.currentTimeInMillis() - delay, 0)) {
+ logger.error("Failed to submit task");
+ }
+ }
+
+ @Override
+ public void schedule(TimerTask task, Date time) {
+ if (!staticsPopulated) {
+ populateStatics(task);
+ }
+ if (!submitTask(task, time.getTime(), 0)) {
+ logger.error("Failed to submit task");
+ }
+ }
+
+ @Override
+ public void schedule(TimerTask task, long delay, long period) {
+ if (!staticsPopulated) {
+ populateStatics(task);
+ }
+ if (!submitTask(task, delay > 0 ? timerKeeper.currentTimeInMillis() + delay :
+ timerKeeper.currentTimeInMillis() - delay, period)) {
+ logger.error("Failed to submit task");
+ }
+ }
+
+ @Override
+ public void schedule(TimerTask task, Date firstTime, long period) {
+ if (!staticsPopulated) {
+ populateStatics(task);
+ }
+ if (!submitTask(task, firstTime.getTime(), period)) {
+ logger.error("Failed to submit task");
+ }
+ }
+
+ /*################################################WARNING################################################*/
+ /* Schedule at fixed rate methods do not work exactly as in the java timer. They are clones of the periodic
+ *scheduling methods. */
+ @Override
+ public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
+ if (!staticsPopulated) {
+ populateStatics(task);
+ }
+ if (!submitTask(task, delay > 0 ? timerKeeper.currentTimeInMillis() + delay :
+ timerKeeper.currentTimeInMillis() - delay, period)) {
+ logger.error("Failed to submit task");
+ }
+ }
+
+ @Override
+ public void scheduleAtFixedRate(TimerTask task, Date firstTime, long period) {
+ if (!staticsPopulated) {
+ populateStatics(task);
+ }
+ if (!submitTask(task, firstTime.getTime(), period)) {
+ logger.error("Failed to submit task");
+ }
+ }
+
+ @Override
+ public void cancel() {
+ executorService.shutdown();
+ queue.clear();
+ }
+
+ @Override
+ public int purge() {
+ return queue.removeCancelled();
+ }
+
+ /**
+ * Returns the virtual current time in millis.
+ *
+ * @return long representing simulated current time.
+ */
+ public long currentTimeInMillis() {
+ return timerKeeper.currentTimeInMillis();
+ }
+
+ /**
+ * Returns the new simulated current time in millis after advancing the absolute value of millis to advance.
+ * Triggers event execution of all events scheduled for execution at times up to and including the returned time.
+ * Passing in the number zero has no effect.
+ *
+ * @param millisToAdvance the number of millis to advance.
+ * @return a long representing the current simulated time in millis
+ */
+ public long advanceTimeMillis(long millisToAdvance) {
+ return timerKeeper.advanceTimeMillis(millisToAdvance);
+ }
+
+ /**
+ * Advances the virtual time a certain number of millis triggers execution delays a certain amount to
+ * allow time for execution.
+ *
+ * @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);
+ }
+
+ /**
+ * Sets up the task and submits it to the queue.
+ *
+ * @param task the task to be added to the queue
+ * @param runtime the first runtime of the task
+ * @param period the period between runs thereafter
+ * @return returns true if the task was successfully submitted, false otherwise
+ */
+ private boolean submitTask(TimerTask task, long runtime, long period) {
+ checkNotNull(task);
+ try {
+ TestUtils.setField(task, "state", scheduledState);
+ TestUtils.setField(task, "nextExecutionTime", runtime);
+ TestUtils.setField(task, "period", period);
+ } catch (TestUtils.TestUtilsException e) {
+ e.printStackTrace();
+ return false;
+ }
+ queue.insertOrdered(task);
+ return true;
+ }
+
+ /**
+ * Executes the given task (only if it is in the scheduled state) and proceeds to reschedule it or mark it as
+ * executed. Does not remove from the queue (this must be done outside).
+ *
+ * @param task the timer task to be executed
+ */
+ private boolean executeTask(TimerTask task) {
+ checkNotNull(task);
+ int currentState;
+ try {
+ currentState = TestUtils.getField(task, "state");
+ } catch (TestUtils.TestUtilsException e) {
+ logger.error("Could not get state of task.");
+ e.printStackTrace();
+ return false;
+ }
+ //If cancelled or already executed stop here.
+ if (currentState == executedState || currentState == cancelledState) {
+ return false;
+ } else if (currentState == virginState) {
+ logger.error("Task was set for execution without being scheduled.");
+ return false;
+ } else if (currentState == scheduledState) {
+ long period;
+
+ try {
+ period = TestUtils.getField(task, "period");
+ } catch (TestUtils.TestUtilsException e) {
+ logger.error("Could not read period of task.");
+ e.printStackTrace();
+ return false;
+ }
+ //Period of zero means one time execution.
+ if (period == 0) {
+ try {
+ TestUtils.setField(task, "state", executedState);
+ } catch (TestUtils.TestUtilsException e) {
+ logger.error("Could not set executed state.");
+ e.printStackTrace();
+ return false;
+ }
+ executorService.execute(task);
+ return true;
+ } else {
+ //Calculate next execution time, using absolute value of period
+ long nextTime = (period > 0) ? (timerKeeper.currentTimeInMillis() + period) :
+ (timerKeeper.currentTimeInMillis() - period);
+ try {
+ TestUtils.setField(task, "nextExecutionTime", nextTime);
+ } catch (TestUtils.TestUtilsException e) {
+ logger.error("Could not set next execution time.");
+ e.printStackTrace();
+ return false;
+ }
+ //Schedule next execution
+ queue.insertOrdered(task);
+ executorService.execute(task);
+ return true;
+ }
+ }
+ logger.error("State property of {} is in an illegal state and did not execute.", task);
+ return false;
+ }
+
+ /**
+ * Executes all tasks in the queue scheduled for execution up to and including the current time.
+ *
+ * @return the total number of tasks run, -1 if failure
+ */
+ private int executeEventsUpToPresent() {
+ int totalRun = 0;
+ if (queue.isEmpty()) {
+ return -1;
+ }
+ TimerTask currTask = queue.peek();
+ long currExecTime;
+ try {
+ currExecTime = TestUtils.getField(currTask, "nextExecutionTime");
+ } catch (TestUtils.TestUtilsException e) {
+ e.printStackTrace();
+ throw new RuntimeException("Could not get nextExecutionTime");
+ }
+ while (currExecTime <= timerKeeper.currentTimeInMillis()) {
+ if (executeTask(queue.pop())) {
+ totalRun++;
+ }
+ if (queue.isEmpty()) {
+ break;
+ }
+ currTask = queue.peek();
+ try {
+ currExecTime = TestUtils.getField(currTask, "nextExecutionTime");
+ } catch (TestUtils.TestUtilsException e) {
+ e.printStackTrace();
+ throw new RuntimeException("Could not get nextExecutionTime");
+ }
+ }
+ return totalRun;
+ }
+
+ /**
+ * Populates the static fields from timer task. Should only be called once.
+ */
+ private void populateStatics(TimerTask task) {
+ try {
+ virginState = TestUtils.getField(task, "VIRGIN");
+ scheduledState = TestUtils.getField(task, "SCHEDULED");
+ executedState = TestUtils.getField(task, "EXECUTED");
+ cancelledState = TestUtils.getField(task, "CANCELLED");
+ staticsPopulated = true;
+ } catch (TestUtils.TestUtilsException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * A class used to maintain the virtual time.
+ */
+ private class TimerKeeper {
+
+ private long currentTime = 0;
+
+ /**
+ * Returns the virtual current time in millis.
+ *
+ * @return long representing simulated current time.
+ */
+ long currentTimeInMillis() {
+ return currentTime;
+ }
+
+ /**
+ * Returns the new simulated current time in millis after advancing the absolute value of millis to advance.
+ * Triggers event execution of all events scheduled for execution at times up to and including the returned
+ * time. Passing in the number zero has no effect.
+ *
+ * @param millisToAdvance the number of millis to advance.
+ * @return a long representing the current simulated time in millis
+ */
+ long advanceTimeMillis(long millisToAdvance) {
+ currentTime = (millisToAdvance >= 0) ? (currentTime + millisToAdvance) : (currentTime - millisToAdvance);
+ if (millisToAdvance != 0) {
+ executeEventsUpToPresent();
+ }
+ return currentTime;
+ }
+ }
+
+ /**
+ * A queue backed by a linked list. Keeps elements sorted in ascending order of execution time. All calls are safe
+ * even on empty queue's.
+ */
+ private class TaskQueue {
+ private final LinkedList<TimerTask> taskList = Lists.newLinkedList();
+
+ /**
+ * Adds the task to the queue in ascending order of scheduled execution. If execution time has already passed
+ * execute immediately.
+ *
+ * @param task the task to be added to the queue
+ */
+ void insertOrdered(TimerTask task) {
+ //Using O(N) insertion because random access is expensive in linked lists worst case is 2N links followed
+ // for binary insertion vs N for simple insertion.
+ checkNotNull(task);
+ if (!staticsPopulated) {
+ populateStatics(task);
+ }
+ long insertTime;
+ try {
+ insertTime = TestUtils.getField(task, "nextExecutionTime");
+ TestUtils.setField(task, "state", scheduledState);
+ } catch (TestUtils.TestUtilsException e) {
+ e.printStackTrace();
+ return;
+ }
+ //If the task was scheduled in the past or for the current time run it immediately and do not add to the
+ // queue, subsequent executions will be scheduled as normal
+ if (insertTime <= timerKeeper.currentTimeInMillis()) {
+ executeTask(task);
+ return;
+ }
+
+ Iterator<TimerTask> iter = taskList.iterator();
+ int positionCounter = 0;
+ long nextTaskTime;
+ TimerTask currentTask;
+ while (iter.hasNext()) {
+ currentTask = iter.next();
+ try {
+ nextTaskTime = TestUtils.getField(currentTask, "nextExecutionTime");
+ } catch (TestUtils.TestUtilsException e) {
+ e.printStackTrace();
+ return;
+ }
+ if (insertTime < nextTaskTime) {
+ taskList.add(positionCounter, task);
+ return;
+ }
+ positionCounter++;
+ }
+ taskList.addLast(task);
+ }
+
+ /**
+ * Returns the first item in the queue (next scheduled for execution) without removing it, returns null if the
+ * queue is empty.
+ *
+ * @return the next TimerTask to run or null if the queue is empty
+ */
+ TimerTask peek() {
+ if (taskList.isEmpty()) {
+ return null;
+ }
+ return taskList.getFirst();
+ }
+
+ /**
+ * Returns and removes the first item in the queue or null if it is empty.
+ *
+ * @return the first element of the queue or null if the queue is empty
+ */
+ TimerTask pop() {
+ if (taskList.isEmpty()) {
+ return null;
+ }
+ return taskList.pop();
+ }
+
+ /**
+ * Performs a sort on the set of timer tasks, earliest task is first. Does nothing if queue is empty.
+ */
+ void sort() {
+ if (taskList.isEmpty()) {
+ return;
+ }
+ taskList.sort((o1, o2) -> {
+ checkNotNull(o1);
+ checkNotNull(o2);
+ long executionTimeOne;
+ long executionTimeTwo;
+ try {
+ executionTimeOne = TestUtils.getField(o1, "nextExecutionTime");
+ executionTimeTwo = TestUtils.getField(o2, "nextExecutionTime");
+ } catch (TestUtils.TestUtilsException e) {
+ e.printStackTrace();
+ throw new RuntimeException("Could not get next execution time.");
+ }
+ if (executionTimeOne == executionTimeTwo) {
+ return 0;
+ } else if (executionTimeOne < executionTimeTwo) {
+ return -1;
+ } else {
+ return 1;
+ }
+ });
+ }
+
+ /**
+ * Returns whether the queue is currently empty.
+ *
+ * @return true if the queue is empty, false otherwise
+ */
+ boolean isEmpty() {
+ return taskList.isEmpty();
+ }
+
+ /**
+ * Clears the underlying list of the queue.
+ */
+ void clear() {
+ taskList.clear();
+ }
+
+ /**
+ * Removes all cancelled tasks from the queue. Has no effect on behavior.
+ *
+ * @return returns the total number of items removed, -1 if list is empty or failure occurs.
+ */
+ int removeCancelled() {
+ if (taskList.isEmpty()) {
+ return -1;
+ }
+ int removedCount = 0;
+ Iterator<TimerTask> taskIterator = taskList.iterator();
+ TimerTask currTask;
+ int currState;
+ while (taskIterator.hasNext()) {
+ currTask = taskIterator.next();
+ try {
+ currState = TestUtils.getField(currTask, "state");
+ } catch (TestUtils.TestUtilsException e) {
+ logger.error("Could not get task state.");
+ e.printStackTrace();
+ return -1;
+ }
+ if (currState == cancelledState) {
+ removedCount++;
+ taskIterator.remove();
+ }
+ }
+ return removedCount;
+ }
+ }
+}
diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/ManuallyAdvancingTimerTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/ManuallyAdvancingTimerTest.java
new file mode 100644
index 00000000..b8e1e85e
--- /dev/null
+++ b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/ManuallyAdvancingTimerTest.java
@@ -0,0 +1,263 @@
+/*
+ * 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.onlab.util;
+
+import com.google.common.collect.Lists;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.TimerTask;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.onlab.junit.TestTools.delay;
+
+/**
+ * Testing class for manually advancing timer.
+ */
+public class ManuallyAdvancingTimerTest {
+
+ private ManuallyAdvancingTimer timer;
+
+ /* Generates unique id's for TestTasks */
+ private AtomicInteger idGenerator;
+
+ /* Tracks TestTasks in order of creation, tasks are automatically added at creation. */
+ private ArrayList<TestTask> taskList;
+
+ /* Total number of tasks run */
+ 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;
+
+ /**
+ * Sets up the testing environment.
+ */
+ @Before
+ public void setup() {
+ timer = new ManuallyAdvancingTimer();
+ idGenerator = new AtomicInteger(1);
+ tasksRunCount = new AtomicInteger(0);
+ taskList = Lists.newArrayList();
+ }
+
+ /**
+ * Tests the one time schedule with delay.
+ *
+ * @throws Exception throws an exception if the test fails
+ */
+ @Test
+ public void testScheduleByDelay() throws Exception {
+ /* Test scheduling in the future as normal. */
+ timer.schedule(new TestTask(), 10);
+ timer.advanceTimeMillis(5);
+ assertFalse(taskList.get(0).hasRun());
+ timer.advanceTimeMillis(10, REAL_TIME_DELAY);
+ assertTrue(taskList.get(0).hasRun());
+
+ /* Test scheduling with negative numbers */
+ timer.schedule(new TestTask(), -10);
+ timer.advanceTimeMillis(5);
+ assertFalse(taskList.get(1).hasRun());
+ timer.advanceTimeMillis(10, REAL_TIME_DELAY);
+ assertTrue(taskList.get(1).hasRun());
+
+ /* Reset list, counter and timer for next test */
+ taskList.clear();
+ idGenerator.set(1);
+ tasksRunCount.set(0);
+
+ for (int i = 0; i < 50; i++) {
+ timer.schedule(new TestTask(), i);
+ }
+ /* Test that a task scheduled for present is run and not placed in the queue */
+ assertEquals("Only the first task should have run.", 1, tasksRunCount.get());
+
+ for (int i = 2; i <= 50; i++) {
+ timer.advanceTimeMillis(1, REAL_TIME_DELAY);
+ assertEquals("One task should be executed per loop", i, tasksRunCount.get());
+ }
+ /* Below tests ordered insertion, this will only be done once, it is the same for all schedule methods. */
+
+ tasksRunCount.set(0);
+
+ for (int i = 0; i < 10; i++) {
+ timer.schedule(new TestTask(), 500);
+ }
+
+ assertEquals("No new tasks should have been run since run count reset.", 0, tasksRunCount.get());
+ timer.schedule(new TestTask(), 10);
+ assertEquals("No new tasks should have been run since run count reset.", 0, tasksRunCount.get());
+ timer.advanceTimeMillis(10, REAL_TIME_DELAY);
+ assertEquals("One new tasks should have been run since run count reset.", 1, tasksRunCount.get());
+ timer.advanceTimeMillis(510, REAL_TIME_DELAY);
+ assertEquals("Eleven new tasks should have been run since run count reset.", 11, tasksRunCount.get());
+ }
+
+ /**
+ * Tests scheduling for a particular date or time which may be in the past.
+ *
+ * @throws Exception throws an exception if the test fails
+ */
+ @Test
+ public void testScheduleByDate() throws Exception {
+ /* Tests basic scheduling for future times. */
+ timer.schedule(new TestTask(), new Date(10));
+ timer.advanceTimeMillis(5);
+ assertFalse(taskList.get(0).hasRun());
+ timer.advanceTimeMillis(10, REAL_TIME_DELAY);
+ assertTrue(taskList.get(0).hasRun());
+
+ /* Test scheduling with past times numbers */
+ timer.schedule(new TestTask(), new Date(0));
+ delay(REAL_TIME_DELAY);
+ assertTrue(taskList.get(1).hasRun());
+
+ /* Tests cancellation on non-periodic events */
+ TestTask task = new TestTask();
+ timer.schedule(task, new Date(timer.currentTimeInMillis() + 10));
+ task.cancel();
+ timer.advanceTimeMillis(12, REAL_TIME_DELAY);
+ assertFalse(task.hasRun());
+
+ }
+
+ /**
+ * Test scheduling beginning after a delay and recurring periodically.
+ *
+ * @throws Exception throws an exception if the test fails
+ */
+ @Test
+ public void testScheduleByDelayPeriodic() throws Exception {
+ /* Test straightforward periodic execution */
+ timer.schedule(new TestTask(), 0, 10);
+ delay(REAL_TIME_DELAY);
+ assertEquals("Task should have run once when added.", 1, taskList.get(0).timesRun());
+
+ /* Tests whether things that are not added to the queue are scheduled for future executions (ones which execute
+ immediately on add). */
+ timer.advanceTimeMillis(10, REAL_TIME_DELAY);
+ assertEquals("Task should have run once when added.", 2, taskList.get(0).timesRun());
+
+ /* Tests whether cancellation works on periodic events. */
+ taskList.get(0).cancel();
+
+ timer.advanceTimeMillis(10, REAL_TIME_DELAY);
+ assertEquals("The task should not have run another time.", 2, taskList.get(0).timesRun());
+
+ TestTask task = new TestTask();
+ timer.schedule(task, 0, 10);
+ timer.advanceTimeMillis(100, REAL_TIME_DELAY);
+ assertEquals("Should have run immeditaley and subsequently once during the larger skip", task.timesRun(), 2);
+
+ }
+
+ /**
+ * Test scheduling beginning at a specified date and recurring periodically.
+ *
+ * @throws Exception throws an exception if the test fails
+ */
+ @Test
+ public void testScheduleByDatePeriodic() throws Exception {
+ /* Test straightforward periodic execution */
+ timer.schedule(new TestTask(), new Date(timer.currentTimeInMillis()), 10);
+ delay(REAL_TIME_DELAY);
+ assertEquals("Task should have run once when added.", 1, taskList.get(0).timesRun());
+
+ /* Tests whether things that are not added to the queue are scheduled for future executions (ones which execute
+ immediately on add). */
+ timer.advanceTimeMillis(10, REAL_TIME_DELAY);
+ assertEquals("Task should have run once when added.", 2, taskList.get(0).timesRun());
+
+ /* Tests whether cancellation works on periodic events. */
+ taskList.get(0).cancel();
+
+ timer.advanceTimeMillis(10, REAL_TIME_DELAY);
+ assertEquals("The task should not have run another time.", 2, taskList.get(0).timesRun());
+
+ TestTask task = new TestTask();
+ timer.schedule(task, new Date(timer.currentTimeInMillis()), 10);
+ timer.advanceTimeMillis(100, REAL_TIME_DELAY);
+ assertEquals("Should have run immediately and subsequently once during the larger skip", task.timesRun(), 2);
+ }
+
+ /* Schedule at fixed rate runs exactly like the two scheduling methods just tested so tests are not included */
+
+ /**
+ * Timer task with added functions to make it better for testing.
+ */
+ private class TestTask extends TimerTask {
+
+ /* Remains true once the task has been run at least once */
+ private boolean hasRun;
+
+ /* Unique id per event. */
+ private int id;
+
+ /* Specifies the number of times an event has run */
+ private int timesRun;
+
+ /**
+ * Constructor initializes id, timesRun, and id fields.
+ */
+ public TestTask() {
+ id = idGenerator.getAndIncrement();
+ timesRun = 0;
+ hasRun = false;
+ taskList.add(this);
+ }
+
+ @Override
+ public void run() {
+ this.hasRun = true;
+ tasksRunCount.incrementAndGet();
+ timesRun++;
+ }
+
+ /**
+ * Returns whether this event has run.
+ *
+ * @return true if the event has run, false otherwise.
+ */
+ public boolean hasRun() {
+ return hasRun;
+ }
+
+ /**
+ * Returns the number of times this task has run.
+ *
+ * @return an int representing the number of times this task has been run
+ */
+ public int timesRun() {
+ return timesRun;
+ }
+
+ /**
+ * Returns the unique identifier of this task.
+ *
+ * @return a unique integer identifier
+ */
+ public int getId() {
+ return id;
+ }
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/utils/osgi/src/test/java/org/onlab/osgi/ComponentContextAdapter.java b/framework/src/onos/utils/osgi/src/test/java/org/onlab/osgi/ComponentContextAdapter.java
index 0278ccd6..b8718c3c 100644
--- a/framework/src/onos/utils/osgi/src/test/java/org/onlab/osgi/ComponentContextAdapter.java
+++ b/framework/src/onos/utils/osgi/src/test/java/org/onlab/osgi/ComponentContextAdapter.java
@@ -22,14 +22,53 @@ import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.ComponentInstance;
import java.util.Dictionary;
+import java.util.Enumeration;
/**
* Adapter implementation of OSGI component context.
*/
public class ComponentContextAdapter implements ComponentContext {
+ private static class MockDictionary extends Dictionary {
+
+ @Override
+ public int size() {
+ return 0;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return false;
+ }
+
+ @Override
+ public Enumeration keys() {
+ return null;
+ }
+
+ @Override
+ public Enumeration elements() {
+ return null;
+ }
+
+ @Override
+ public Object get(Object key) {
+ return null;
+ }
+
+ @Override
+ public Object put(Object key, Object value) {
+ return null;
+ }
+
+ @Override
+ public Object remove(Object key) {
+ return null;
+ }
+ }
+
@Override
public Dictionary getProperties() {
- return null;
+ return new MockDictionary();
}
@Override
diff --git a/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/FlowsWebResource.java b/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/FlowsWebResource.java
index 325e191b..0e88e34e 100644
--- a/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/FlowsWebResource.java
+++ b/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/FlowsWebResource.java
@@ -66,9 +66,9 @@ public class FlowsWebResource extends AbstractWebResource {
public Response getFlows() {
final Iterable<Device> devices = get(DeviceService.class).getDevices();
for (final Device device : devices) {
- final Iterable<FlowEntry> deviceEntries = service.getFlowEntries(device.id());
- if (deviceEntries != null) {
- for (final FlowEntry entry : deviceEntries) {
+ final Iterable<FlowEntry> flowEntries = service.getFlowEntries(device.id());
+ if (flowEntries != null) {
+ for (final FlowEntry entry : flowEntries) {
flowsNode.add(codec(FlowEntry.class).encode(entry, this));
}
}
@@ -88,13 +88,13 @@ public class FlowsWebResource extends AbstractWebResource {
@Produces(MediaType.APPLICATION_JSON)
@Path("{deviceId}")
public Response getFlowByDeviceId(@PathParam("deviceId") String deviceId) {
- final Iterable<FlowEntry> deviceEntries =
+ final Iterable<FlowEntry> flowEntries =
service.getFlowEntries(DeviceId.deviceId(deviceId));
- if (!deviceEntries.iterator().hasNext()) {
+ if (!flowEntries.iterator().hasNext()) {
throw new ItemNotFoundException(DEVICE_NOT_FOUND);
}
- for (final FlowEntry entry : deviceEntries) {
+ for (final FlowEntry entry : flowEntries) {
flowsNode.add(codec(FlowEntry.class).encode(entry, this));
}
return ok(root).build();
@@ -113,13 +113,13 @@ public class FlowsWebResource extends AbstractWebResource {
@Path("{deviceId}/{flowId}")
public Response getFlowByDeviceIdAndFlowId(@PathParam("deviceId") String deviceId,
@PathParam("flowId") long flowId) {
- final Iterable<FlowEntry> deviceEntries =
+ final Iterable<FlowEntry> flowEntries =
service.getFlowEntries(DeviceId.deviceId(deviceId));
- if (!deviceEntries.iterator().hasNext()) {
+ if (!flowEntries.iterator().hasNext()) {
throw new ItemNotFoundException(DEVICE_NOT_FOUND);
}
- for (final FlowEntry entry : deviceEntries) {
+ for (final FlowEntry entry : flowEntries) {
if (entry.id().value() == flowId) {
flowsNode.add(codec(FlowEntry.class).encode(entry, this));
}
@@ -175,14 +175,14 @@ public class FlowsWebResource extends AbstractWebResource {
@Path("{deviceId}/{flowId}")
public void deleteFlowByDeviceIdAndFlowId(@PathParam("deviceId") String deviceId,
@PathParam("flowId") long flowId) {
- final Iterable<FlowEntry> deviceEntries =
+ final Iterable<FlowEntry> flowEntries =
service.getFlowEntries(DeviceId.deviceId(deviceId));
- if (!deviceEntries.iterator().hasNext()) {
+ if (!flowEntries.iterator().hasNext()) {
throw new ItemNotFoundException(DEVICE_NOT_FOUND);
}
- StreamSupport.stream(deviceEntries.spliterator(), false)
+ StreamSupport.stream(flowEntries.spliterator(), false)
.filter(entry -> entry.id().value() == flowId)
.forEach(service::removeFlowRules);
}
diff --git a/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/NetworkConfigWebResource.java b/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/NetworkConfigWebResource.java
index 9e2b6273..808fcc16 100644
--- a/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/NetworkConfigWebResource.java
+++ b/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/NetworkConfigWebResource.java
@@ -49,73 +49,77 @@ public class NetworkConfigWebResource extends AbstractWebResource {
public Response download() {
NetworkConfigService service = get(NetworkConfigService.class);
ObjectNode root = mapper().createObjectNode();
- service.getSubjectClasses().forEach(sc ->
- produceJson(service, newObject(root, service.getSubjectFactory(sc).subjectKey()), sc));
+ service.getSubjectClasses().forEach(sc -> {
+ SubjectFactory subjectFactory = service.getSubjectFactory(sc);
+ produceJson(service, newObject(root, subjectFactory.subjectClassKey()),
+ subjectFactory, sc);
+ });
return ok(root).build();
}
/**
* Get all network configuration for a subject class.
*
- * @param subjectKey subject class key
+ * @param subjectClassKey subject class key
* @return network configuration JSON
*/
@GET
- @Path("{subjectKey}")
+ @Path("{subjectClassKey}")
@Produces(MediaType.APPLICATION_JSON)
@SuppressWarnings("unchecked")
- public Response download(@PathParam("subjectKey") String subjectKey) {
+ public Response download(@PathParam("subjectClassKey") String subjectClassKey) {
NetworkConfigService service = get(NetworkConfigService.class);
ObjectNode root = mapper().createObjectNode();
- produceJson(service, root, service.getSubjectFactory(subjectKey).subjectClass());
+ SubjectFactory subjectFactory = service.getSubjectFactory(subjectClassKey);
+ produceJson(service, root, subjectFactory, subjectFactory.subjectClass());
return ok(root).build();
}
/**
- * Get all network configuration for a subject.
+ * Get all network configuration for a subjectKey.
*
- * @param subjectKey subject class key
- * @param subject subject key
+ * @param subjectClassKey subjectKey class key
+ * @param subjectKey subjectKey key
* @return network configuration JSON
*/
@GET
- @Path("{subjectKey}/{subject}")
+ @Path("{subjectClassKey}/{subjectKey}")
@Produces(MediaType.APPLICATION_JSON)
@SuppressWarnings("unchecked")
- public Response download(@PathParam("subjectKey") String subjectKey,
- @PathParam("subject") String subject) {
+ public Response download(@PathParam("subjectClassKey") String subjectClassKey,
+ @PathParam("subjectKey") String subjectKey) {
NetworkConfigService service = get(NetworkConfigService.class);
ObjectNode root = mapper().createObjectNode();
- produceSubjectJson(service, root,
- service.getSubjectFactory(subjectKey).createSubject(subject));
+ SubjectFactory subjectFactory = service.getSubjectFactory(subjectClassKey);
+ produceSubjectJson(service, root, subjectFactory.createSubject(subjectKey));
return ok(root).build();
}
/**
- * Get specific network configuration for a subject.
+ * Get specific network configuration for a subjectKey.
*
- * @param subjectKey subject class key
- * @param subject subject key
- * @param configKey configuration class key
+ * @param subjectClassKey subjectKey class key
+ * @param subjectKey subjectKey key
+ * @param configKey configuration class key
* @return network configuration JSON
*/
@GET
- @Path("{subjectKey}/{subject}/{configKey}")
+ @Path("{subjectClassKey}/{subjectKey}/{configKey}")
@Produces(MediaType.APPLICATION_JSON)
@SuppressWarnings("unchecked")
- public Response download(@PathParam("subjectKey") String subjectKey,
- @PathParam("subject") String subject,
+ public Response download(@PathParam("subjectClassKey") String subjectClassKey,
+ @PathParam("subjectKey") String subjectKey,
@PathParam("configKey") String configKey) {
NetworkConfigService service = get(NetworkConfigService.class);
- return ok(service.getConfig(service.getSubjectFactory(subjectKey).createSubject(subject),
- service.getConfigClass(subjectKey, configKey)).node()).build();
+ return ok(service.getConfig(service.getSubjectFactory(subjectClassKey).createSubject(subjectKey),
+ service.getConfigClass(subjectClassKey, configKey)).node()).build();
}
@SuppressWarnings("unchecked")
private void produceJson(NetworkConfigService service, ObjectNode node,
- Class subjectClass) {
+ SubjectFactory subjectFactory, Class subjectClass) {
service.getSubjects(subjectClass).forEach(s ->
- produceSubjectJson(service, newObject(node, s.toString()), s));
+ produceSubjectJson(service, newObject(node, subjectFactory.subjectKey(s)), s));
}
private void produceSubjectJson(NetworkConfigService service, ObjectNode node,
@@ -128,8 +132,8 @@ public class NetworkConfigWebResource extends AbstractWebResource {
* Upload bulk network configuration.
*
* @param request network configuration JSON rooted at the top node
- * @throws IOException if unable to parse the request
* @return empty response
+ * @throws IOException if unable to parse the request
*/
@POST
@Consumes(MediaType.APPLICATION_JSON)
@@ -146,78 +150,78 @@ public class NetworkConfigWebResource extends AbstractWebResource {
/**
* Upload multiple network configurations for a subject class.
*
- * @param subjectKey subject class key
- * @param request network configuration JSON rooted at the top node
+ * @param subjectClassKey subject class key
+ * @param request network configuration JSON rooted at the top node
* @return empty response
* @throws IOException if unable to parse the request
*/
@POST
- @Path("{subjectKey}")
+ @Path("{subjectClassKey}")
@Consumes(MediaType.APPLICATION_JSON)
@SuppressWarnings("unchecked")
- public Response upload(@PathParam("subjectKey") String subjectKey,
+ public Response upload(@PathParam("subjectClassKey") String subjectClassKey,
InputStream request) throws IOException {
NetworkConfigService service = get(NetworkConfigService.class);
ObjectNode root = (ObjectNode) mapper().readTree(request);
- consumeJson(service, root, service.getSubjectFactory(subjectKey));
+ consumeJson(service, root, service.getSubjectFactory(subjectClassKey));
return Response.ok().build();
}
/**
- * Upload mutliple network configurations for a subject.
+ * Upload mutliple network configurations for a subjectKey.
*
- * @param subjectKey subject class key
- * @param subject subject key
- * @param request network configuration JSON rooted at the top node
+ * @param subjectClassKey subjectKey class key
+ * @param subjectKey subjectKey key
+ * @param request network configuration JSON rooted at the top node
* @return empty response
* @throws IOException if unable to parse the request
*/
@POST
- @Path("{subjectKey}/{subject}")
+ @Path("{subjectClassKey}/{subjectKey}")
@Consumes(MediaType.APPLICATION_JSON)
@SuppressWarnings("unchecked")
- public Response upload(@PathParam("subjectKey") String subjectKey,
- @PathParam("subject") String subject,
+ public Response upload(@PathParam("subjectClassKey") String subjectClassKey,
+ @PathParam("subjectKey") String subjectKey,
InputStream request) throws IOException {
NetworkConfigService service = get(NetworkConfigService.class);
ObjectNode root = (ObjectNode) mapper().readTree(request);
consumeSubjectJson(service, root,
- service.getSubjectFactory(subjectKey).createSubject(subject),
- subjectKey);
+ service.getSubjectFactory(subjectClassKey).createSubject(subjectKey),
+ subjectClassKey);
return Response.ok().build();
}
/**
- * Upload specific network configuration for a subject.
+ * Upload specific network configuration for a subjectKey.
*
- * @param subjectKey subject class key
- * @param subject subject key
- * @param configKey configuration class key
- * @param request network configuration JSON rooted at the top node
+ * @param subjectClassKey subjectKey class key
+ * @param subjectKey subjectKey key
+ * @param configKey configuration class key
+ * @param request network configuration JSON rooted at the top node
* @return empty response
* @throws IOException if unable to parse the request
*/
@POST
- @Path("{subjectKey}/{subject}/{configKey}")
+ @Path("{subjectClassKey}/{subjectKey}/{configKey}")
@Consumes(MediaType.APPLICATION_JSON)
@SuppressWarnings("unchecked")
- public Response upload(@PathParam("subjectKey") String subjectKey,
- @PathParam("subject") String subject,
+ public Response upload(@PathParam("subjectClassKey") String subjectClassKey,
+ @PathParam("subjectKey") String subjectKey,
@PathParam("configKey") String configKey,
InputStream request) throws IOException {
NetworkConfigService service = get(NetworkConfigService.class);
ObjectNode root = (ObjectNode) mapper().readTree(request);
- service.applyConfig(service.getSubjectFactory(subjectKey).createSubject(subject),
- service.getConfigClass(subjectKey, configKey), root);
+ service.applyConfig(service.getSubjectFactory(subjectClassKey).createSubject(subjectKey),
+ service.getConfigClass(subjectClassKey, configKey), root);
return Response.ok().build();
}
private void consumeJson(NetworkConfigService service, ObjectNode classNode,
SubjectFactory subjectFactory) {
classNode.fieldNames().forEachRemaining(s ->
- consumeSubjectJson(service, (ObjectNode) classNode.path(s),
- subjectFactory.createSubject(s),
- subjectFactory.subjectKey()));
+ consumeSubjectJson(service, (ObjectNode) classNode.path(s),
+ subjectFactory.createSubject(s),
+ subjectFactory.subjectClassKey()));
}
private void consumeSubjectJson(NetworkConfigService service,
@@ -225,7 +229,7 @@ public class NetworkConfigWebResource extends AbstractWebResource {
String subjectKey) {
subjectNode.fieldNames().forEachRemaining(c ->
service.applyConfig(subject, service.getConfigClass(subjectKey, c),
- (ObjectNode) subjectNode.path(c)));
+ subjectNode.path(c)));
}
@@ -241,64 +245,62 @@ public class NetworkConfigWebResource extends AbstractWebResource {
service.getSubjectClasses()
.forEach(subjectClass -> service.getSubjects(subjectClass)
.forEach(subject -> service.getConfigs(subject)
- .forEach(config -> service
- .removeConfig(subject, config.getClass()))));
+ .forEach(config -> service.removeConfig(subject, config.getClass()))));
return Response.ok().build();
}
/**
* Clear all network configurations for a subject class.
*
- * @param subjectKey subject class key
+ * @param subjectClassKey subject class key
* @return empty response
*/
@DELETE
- @Path("{subjectKey}")
+ @Path("{subjectClassKey}")
@SuppressWarnings("unchecked")
- public Response delete(@PathParam("subjectKey") String subjectKey) {
+ public Response delete(@PathParam("subjectClassKey") String subjectClassKey) {
NetworkConfigService service = get(NetworkConfigService.class);
- service.getSubjects(service.getSubjectFactory(subjectKey).getClass())
+ service.getSubjects(service.getSubjectFactory(subjectClassKey).getClass())
.forEach(subject -> service.getConfigs(subject)
- .forEach(config -> service
- .removeConfig(subject, config.getClass())));
+ .forEach(config -> service.removeConfig(subject, config.getClass())));
return Response.ok().build();
}
/**
- * Clear all network configurations for a subject.
+ * Clear all network configurations for a subjectKey.
*
- * @param subjectKey subject class key
- * @param subject subject key
+ * @param subjectClassKey subjectKey class key
+ * @param subjectKey subjectKey key
* @return empty response
*/
@DELETE
- @Path("{subjectKey}/{subject}")
+ @Path("{subjectClassKey}/{subjectKey}")
@SuppressWarnings("unchecked")
- public Response delete(@PathParam("subjectKey") String subjectKey,
- @PathParam("subject") String subject) {
+ public Response delete(@PathParam("subjectClassKey") String subjectClassKey,
+ @PathParam("subjectKey") String subjectKey) {
NetworkConfigService service = get(NetworkConfigService.class);
- Object s = service.getSubjectFactory(subjectKey).createSubject(subject);
+ Object s = service.getSubjectFactory(subjectClassKey).createSubject(subjectKey);
service.getConfigs(s).forEach(c -> service.removeConfig(s, c.getClass()));
return Response.ok().build();
}
/**
- * Clear specific network configuration for a subject.
+ * Clear specific network configuration for a subjectKey.
*
- * @param subjectKey subject class key
- * @param subject subject key
- * @param configKey configuration class key
+ * @param subjectClassKey subjectKey class key
+ * @param subjectKey subjectKey key
+ * @param configKey configuration class key
* @return empty response
*/
@DELETE
- @Path("{subjectKey}/{subject}/{configKey}")
+ @Path("{subjectClassKey}/{subjectKey}/{configKey}")
@SuppressWarnings("unchecked")
- public Response delete(@PathParam("subjectKey") String subjectKey,
- @PathParam("subject") String subject,
+ public Response delete(@PathParam("subjectClassKey") String subjectClassKey,
+ @PathParam("subjectKey") String subjectKey,
@PathParam("configKey") String configKey) {
NetworkConfigService service = get(NetworkConfigService.class);
- service.removeConfig(service.getSubjectFactory(subjectKey).createSubject(subject),
- service.getConfigClass(subjectKey, configKey));
+ service.removeConfig(service.getSubjectFactory(subjectClassKey).createSubject(subjectKey),
+ service.getConfigClass(subjectClassKey, configKey));
return Response.ok().build();
}
diff --git a/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/PathsWebResource.java b/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/PathsWebResource.java
index baa1b1e6..9714690c 100644
--- a/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/PathsWebResource.java
+++ b/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/PathsWebResource.java
@@ -15,7 +15,11 @@
*/
package org.onosproject.rest.resources;
-import java.util.Set;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.ElementId;
+import org.onosproject.net.HostId;
+import org.onosproject.net.topology.PathService;
+import org.onosproject.rest.AbstractWebResource;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
@@ -23,14 +27,7 @@ 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.net.DeviceId;
-import org.onosproject.net.ElementId;
-import org.onosproject.net.HostId;
-import org.onosproject.net.topology.PathService;
-
-import com.fasterxml.jackson.databind.node.ObjectNode;
-import org.onosproject.rest.AbstractWebResource;
+import java.util.Set;
/**
* Compute paths in the network graph.
@@ -50,6 +47,17 @@ public class PathsWebResource extends AbstractWebResource {
}
/**
+ * Returns either host id or device id, depending on the ID format.
+ *
+ * @param id host or device id string
+ * @return element id
+ */
+ private ElementId elementId(String id) {
+ ElementId elementId = isHostId(id);
+ return elementId != null ? elementId : DeviceId.deviceId(id);
+ }
+
+ /**
* Get all shortest paths between any two hosts or devices.
* Returns array of all shortest paths between any two elements.
*
@@ -63,23 +71,27 @@ public class PathsWebResource extends AbstractWebResource {
public Response getPath(@PathParam("src") String src,
@PathParam("dst") String dst) {
PathService pathService = get(PathService.class);
-
- ElementId srcElement = isHostId(src);
- ElementId dstElement = isHostId(dst);
-
- if (srcElement == null) {
- // Doesn't look like a host, assume it is a device
- srcElement = DeviceId.deviceId(src);
- }
-
- if (dstElement == null) {
- // Doesn't look like a host, assume it is a device
- dstElement = DeviceId.deviceId(dst);
- }
-
- Set<org.onosproject.net.Path> paths = pathService.getPaths(srcElement, dstElement);
- ObjectNode root = encodeArray(org.onosproject.net.Path.class, "paths", paths);
- return ok(root).build();
+ Set<org.onosproject.net.Path> paths =
+ pathService.getPaths(elementId(src), elementId(dst));
+ return ok(encodeArray(org.onosproject.net.Path.class, "paths", paths)).build();
}
+ /**
+ * Get all shortest disjoint paths between any two hosts or devices.
+ * Returns array of all shortest disjoint paths between any two elements.
+ *
+ * @param src source identifier
+ * @param dst destination identifier
+ * @return path data
+ */
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("{src}/{dst}/disjoint")
+ public Response getDisjointPath(@PathParam("src") String src,
+ @PathParam("dst") String dst) {
+ PathService pathService = get(PathService.class);
+ Set<org.onosproject.net.DisjointPath> paths =
+ pathService.getDisjointPaths(elementId(src), elementId(dst));
+ return ok(encodeArray(org.onosproject.net.DisjointPath.class, "paths", paths)).build();
+ }
}
diff --git a/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/StatisticsWebResource.java b/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/StatisticsWebResource.java
index 2ffa2295..c91cb6d0 100644
--- a/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/StatisticsWebResource.java
+++ b/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/StatisticsWebResource.java
@@ -21,6 +21,7 @@ import java.util.stream.StreamSupport;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
@@ -31,7 +32,12 @@ import javax.ws.rs.core.UriInfo;
import org.onosproject.codec.JsonCodec;
import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
import org.onosproject.net.Link;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.flow.FlowRuleService;
+import org.onosproject.net.flow.TableStatisticsEntry;
import org.onosproject.net.link.LinkService;
import org.onosproject.net.statistic.Load;
import org.onosproject.net.statistic.StatisticService;
@@ -92,4 +98,59 @@ public class StatisticsWebResource extends AbstractWebResource {
result.set("loads", loads);
return ok(result).build();
}
+
+ /**
+ * Get table statistics for all tables of all devices.
+ *
+ * @return JSON encoded array of table statistics
+ */
+ @GET
+ @Path("flows/tables")
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getTableStatistics() {
+ final FlowRuleService service = get(FlowRuleService.class);
+ final Iterable<Device> devices = get(DeviceService.class).getDevices();
+ final ObjectNode root = mapper().createObjectNode();
+ final ArrayNode rootArrayNode = root.putArray("device-table-statistics");
+ for (final Device device : devices) {
+ final ObjectNode deviceStatsNode = mapper().createObjectNode();
+ deviceStatsNode.put("device", device.id().toString());
+ final ArrayNode statisticsNode = deviceStatsNode.putArray("table-statistics");
+ final Iterable<TableStatisticsEntry> tableStatsEntries = service.getFlowTableStatistics(device.id());
+ if (tableStatsEntries != null) {
+ for (final TableStatisticsEntry entry : tableStatsEntries) {
+ statisticsNode.add(codec(TableStatisticsEntry.class).encode(entry, this));
+ }
+ }
+ rootArrayNode.add(deviceStatsNode);
+ }
+
+ return ok(root).build();
+ }
+
+ /**
+ * Get table statistics for all tables of a specified device.
+ *
+ * @param deviceId device ID
+ * @return JSON encoded array of table statistics
+ */
+ @GET
+ @Path("flows/tables/{deviceId}")
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getTableStatisticsByDeviceId(@PathParam("deviceId") String deviceId) {
+ final FlowRuleService service = get(FlowRuleService.class);
+ final Iterable<TableStatisticsEntry> tableStatisticsEntries =
+ service.getFlowTableStatistics(DeviceId.deviceId(deviceId));
+ final ObjectNode root = mapper().createObjectNode();
+ final ArrayNode rootArrayNode = root.putArray("table-statistics");
+
+ final ObjectNode deviceStatsNode = mapper().createObjectNode();
+ deviceStatsNode.put("device", deviceId);
+ final ArrayNode statisticsNode = deviceStatsNode.putArray("table-statistics");
+ for (final TableStatisticsEntry entry : tableStatisticsEntries) {
+ statisticsNode.add(codec(TableStatisticsEntry.class).encode(entry, this));
+ }
+ rootArrayNode.add(deviceStatsNode);
+ return ok(root).build();
+ }
}
diff --git a/framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/DeviceViewMessageHandler.java b/framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/DeviceViewMessageHandler.java
index fb83cdd7..53b16a65 100644
--- a/framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/DeviceViewMessageHandler.java
+++ b/framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/DeviceViewMessageHandler.java
@@ -25,12 +25,16 @@ import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Link;
import org.onosproject.net.Port;
+import org.onosproject.net.config.NetworkConfigService;
+import org.onosproject.net.config.basics.BasicDeviceConfig;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.link.LinkService;
import org.onosproject.ui.RequestHandler;
import org.onosproject.ui.UiMessageHandler;
import org.onosproject.ui.table.TableModel;
import org.onosproject.ui.table.TableRequestHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collection;
@@ -38,7 +42,10 @@ import java.util.Collections;
import java.util.List;
import java.util.Set;
+import static com.google.common.base.Strings.emptyToNull;
+import static com.google.common.base.Strings.isNullOrEmpty;
import static org.apache.commons.lang.WordUtils.capitalizeFully;
+import static org.onosproject.net.DeviceId.deviceId;
/**
* Message handler for device view related messages.
@@ -53,6 +60,11 @@ public class DeviceViewMessageHandler extends UiMessageHandler {
private static final String DEV_DETAILS_RESP = "deviceDetailsResponse";
private static final String DETAILS = "details";
+ private static final String DEV_NAME_CHANGE_REQ = "deviceNameChangeRequest";
+ private static final String DEV_NAME_CHANGE_RESP = "deviceNameChangeResponse";
+
+ private static final String ZERO_URI = "of:0000000000000000";
+
private static final String ID = "id";
private static final String TYPE = "type";
private static final String AVAILABLE = "available";
@@ -72,25 +84,41 @@ public class DeviceViewMessageHandler extends UiMessageHandler {
private static final String ENABLED = "enabled";
private static final String SPEED = "speed";
private static final String NAME = "name";
+ private static final String WARN = "warn";
private static final String[] COL_IDS = {
- AVAILABLE, AVAILABLE_IID, TYPE_IID, ID,
- NUM_PORTS, MASTER_ID, MFR, HW, SW,
+ AVAILABLE, AVAILABLE_IID, TYPE_IID,
+ NAME, ID, MASTER_ID, NUM_PORTS, MFR, HW, SW,
PROTOCOL, CHASSIS_ID, SERIAL
};
private static final String ICON_ID_ONLINE = "active";
private static final String ICON_ID_OFFLINE = "inactive";
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+
@Override
protected Collection<RequestHandler> createRequestHandlers() {
return ImmutableSet.of(
new DataRequestHandler(),
+ new NameChangeHandler(),
new DetailRequestHandler()
);
}
+ // Get friendly name of the device from the annotations
+ private static String deviceName(Device device) {
+ String name = device.annotations().value(AnnotationKeys.NAME);
+ return isNullOrEmpty(name) ? device.id().toString() : name;
+ }
+
+ private static String deviceProtocol(Device device) {
+ String protocol = device.annotations().value(PROTOCOL);
+ return protocol != null ? protocol : "";
+ }
+
private static String getTypeIconId(Device d) {
return DEV_ICON_PREFIX + d.type().toString();
}
@@ -121,16 +149,15 @@ public class DeviceViewMessageHandler extends UiMessageHandler {
boolean available = ds.isAvailable(id);
String iconId = available ? ICON_ID_ONLINE : ICON_ID_OFFLINE;
- String protocol = dev.annotations().value(PROTOCOL);
-
row.cell(ID, id)
+ .cell(NAME, deviceName(dev))
.cell(AVAILABLE, available)
.cell(AVAILABLE_IID, iconId)
.cell(TYPE_IID, getTypeIconId(dev))
.cell(MFR, dev.manufacturer())
.cell(HW, dev.hwVersion())
.cell(SW, dev.swVersion())
- .cell(PROTOCOL, protocol != null ? protocol : "")
+ .cell(PROTOCOL, deviceProtocol(dev))
.cell(NUM_PORTS, ds.getPorts(id).size())
.cell(MASTER_ID, ms.getMasterFor(id));
}
@@ -144,15 +171,16 @@ public class DeviceViewMessageHandler extends UiMessageHandler {
@Override
public void process(long sid, ObjectNode payload) {
- String id = string(payload, "id", "of:0000000000000000");
+ String id = string(payload, ID, ZERO_URI);
- DeviceId deviceId = DeviceId.deviceId(id);
+ DeviceId deviceId = deviceId(id);
DeviceService service = get(DeviceService.class);
MastershipService ms = get(MastershipService.class);
Device device = service.getDevice(deviceId);
- ObjectNode data = MAPPER.createObjectNode();
+ ObjectNode data = objectNode();
data.put(ID, deviceId.toString());
+ data.put(NAME, deviceName(device));
data.put(TYPE, capitalizeFully(device.type().toString()));
data.put(TYPE_IID, getTypeIconId(device));
data.put(MFR, device.manufacturer());
@@ -161,9 +189,9 @@ public class DeviceViewMessageHandler extends UiMessageHandler {
data.put(SERIAL, device.serialNumber());
data.put(CHASSIS_ID, device.chassisId().toString());
data.put(MASTER_ID, ms.getMasterFor(deviceId).toString());
- data.put(PROTOCOL, device.annotations().value(PROTOCOL));
+ data.put(PROTOCOL, deviceProtocol(device));
- ArrayNode ports = MAPPER.createArrayNode();
+ ArrayNode ports = arrayNode();
List<Port> portList = new ArrayList<>(service.getPorts(deviceId));
Collections.sort(portList, (p1, p2) -> {
@@ -176,13 +204,13 @@ public class DeviceViewMessageHandler extends UiMessageHandler {
}
data.set(PORTS, ports);
- ObjectNode rootNode = MAPPER.createObjectNode();
+ ObjectNode rootNode = objectNode();
rootNode.set(DETAILS, data);
sendMessage(DEV_DETAILS_RESP, 0, rootNode);
}
private ObjectNode portData(Port p, DeviceId id) {
- ObjectNode port = MAPPER.createObjectNode();
+ ObjectNode port = objectNode();
LinkService ls = get(LinkService.class);
String name = p.annotations().value(AnnotationKeys.PORT_NAME);
@@ -206,4 +234,29 @@ public class DeviceViewMessageHandler extends UiMessageHandler {
return port;
}
}
+
+
+ // handler for changing device friendly name
+ private final class NameChangeHandler extends RequestHandler {
+ private NameChangeHandler() {
+ super(DEV_NAME_CHANGE_REQ);
+ }
+
+ @Override
+ public void process(long sid, ObjectNode payload) {
+ DeviceId deviceId = deviceId(string(payload, ID, ZERO_URI));
+ String name = emptyToNull(string(payload, NAME, null));
+ log.debug("Name change request: {} -- '{}'", deviceId, name);
+
+ NetworkConfigService service = get(NetworkConfigService.class);
+ BasicDeviceConfig cfg =
+ service.addConfig(deviceId, BasicDeviceConfig.class);
+
+ // Name attribute missing from the payload (or empty string)
+ // means that the friendly name should be unset.
+ cfg.name(name);
+ cfg.apply();
+ sendMessage(DEV_NAME_CHANGE_RESP, 0, payload);
+ }
+ }
}
diff --git a/framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/ProcessorViewMessageHandler.java b/framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/ProcessorViewMessageHandler.java
new file mode 100644
index 00000000..5d97504e
--- /dev/null
+++ b/framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/ProcessorViewMessageHandler.java
@@ -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.ui.impl;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.ImmutableSet;
+import org.onosproject.net.packet.PacketProcessorEntry;
+import org.onosproject.net.packet.PacketService;
+import org.onosproject.ui.RequestHandler;
+import org.onosproject.ui.UiMessageHandler;
+import org.onosproject.ui.table.TableModel;
+import org.onosproject.ui.table.TableRequestHandler;
+import org.onosproject.ui.table.cell.NumberFormatter;
+
+import java.util.Collection;
+
+import static org.onosproject.net.packet.PacketProcessor.ADVISOR_MAX;
+import static org.onosproject.net.packet.PacketProcessor.DIRECTOR_MAX;
+
+/**
+ * Message handler for packet processor view related messages.
+ */
+public class ProcessorViewMessageHandler extends UiMessageHandler {
+
+ private static final String PROCESSOR_DATA_REQ = "processorDataRequest";
+ private static final String PROCESSOR_DATA_RESP = "processorDataResponse";
+ private static final String PROCESSORS = "processors";
+
+ private static final String OBSERVER = "observer";
+ private static final String DIRECTOR = "director";
+ private static final String ADVISOR = "advisor";
+
+ private static final String ID = "id";
+ private static final String TYPE = "type";
+ private static final String PRIORITY = "priority";
+ private static final String PROCESSOR = "processor";
+ private static final String PACKETS = "packets";
+ private static final String AVG_MS = "avgMillis";
+
+ private static final long NANOS_IN_MS = 1_000_000;
+
+ private static final String[] COL_IDS = {
+ ID, TYPE, PRIORITY, PROCESSOR, PACKETS, AVG_MS
+ };
+
+ @Override
+ protected Collection<RequestHandler> createRequestHandlers() {
+ return ImmutableSet.of(new ProcessorDataRequest());
+ }
+
+ // handler for packet processor table requests
+ private final class ProcessorDataRequest extends TableRequestHandler {
+ private ProcessorDataRequest() {
+ super(PROCESSOR_DATA_REQ, PROCESSOR_DATA_RESP, PROCESSORS);
+ }
+
+ @Override
+ protected String[] getColumnIds() {
+ return COL_IDS;
+ }
+
+ @Override
+ protected TableModel createTableModel() {
+ TableModel tm = super.createTableModel();
+ tm.setFormatter(AVG_MS, new NumberFormatter());
+ return tm;
+ }
+
+ @Override
+ protected void populateTable(TableModel tm, ObjectNode payload) {
+ PacketService ps = get(PacketService.class);
+ ps.getProcessors().forEach(entry -> populateRow(tm.addRow(), entry));
+ }
+
+ private void populateRow(TableModel.Row row, PacketProcessorEntry entry) {
+ row.cell(ID, entry.priority())
+ .cell(TYPE, processorType(entry.priority()))
+ .cell(PRIORITY, processorPriority(entry.priority()))
+ .cell(PROCESSOR, entry.processor().getClass().getName())
+ .cell(PACKETS, entry.invocations())
+ .cell(AVG_MS, (double) entry.averageNanos() / NANOS_IN_MS);
+ }
+
+ private String processorType(int p) {
+ return p > DIRECTOR_MAX ? OBSERVER : p > ADVISOR_MAX ? DIRECTOR : ADVISOR;
+ }
+
+ private int processorPriority(int p) {
+ return p > DIRECTOR_MAX ? (p - DIRECTOR_MAX - 1) :
+ p > ADVISOR_MAX ? (p - ADVISOR_MAX - 1) : (p - 1);
+ }
+
+ }
+}
diff --git a/framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/UiExtensionManager.java b/framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/UiExtensionManager.java
index 2bd0bb61..86cf038b 100644
--- a/framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/UiExtensionManager.java
+++ b/framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/UiExtensionManager.java
@@ -77,6 +77,7 @@ public class UiExtensionManager implements UiExtensionService, SpriteService {
new UiView(PLATFORM, "app", "Applications", "nav_apps"),
new UiView(PLATFORM, "settings", "Settings", "nav_settings"),
new UiView(PLATFORM, "cluster", "Cluster Nodes", "nav_cluster"),
+ new UiView(PLATFORM, "processor", "Packet Processors", "nav_processors"),
new UiView(NETWORK, "topo", "Topology", "nav_topo"),
new UiView(NETWORK, "device", "Devices", "nav_devs"),
new UiViewHidden("flow"),
@@ -102,6 +103,7 @@ public class UiExtensionManager implements UiExtensionService, SpriteService {
new ApplicationViewMessageHandler(),
new SettingsViewMessageHandler(),
new ClusterViewMessageHandler(),
+ new ProcessorViewMessageHandler(),
new TunnelViewMessageHandler()
);
diff --git a/framework/src/onos/web/gui/src/main/webapp/app/fw/svg/glyph.js b/framework/src/onos/web/gui/src/main/webapp/app/fw/svg/glyph.js
index 838a2ac0..28f262a1 100644
--- a/framework/src/onos/web/gui/src/main/webapp/app/fw/svg/glyph.js
+++ b/framework/src/onos/web/gui/src/main/webapp/app/fw/svg/glyph.js
@@ -55,6 +55,15 @@
unknown: "M35,40a5,5,0,0,1,5-5h30a5,5,0,0,1,5,5v30a5,5,0,0,1-5,5" +
"h-30a5,5,0,0,1-5-5z",
+ query: "M51.4,69.9c0-0.9,0-1.6,0-2.1c0-2.7,0.4-5.1,1.2-7.1" +
+ "c0.6-1.5,1.5-3,2.8-4.5c0.9-1.1,2.6-2.7,5.1-4.8c2.4-2.1,4-3.8," +
+ "4.8-5.1 c0.7-1.3,1.1-2.6,1.1-4.1c0-2.7-1.1-5.1-3.2-7.1c-2.1-2" +
+ "-4.8-3.1-7.9-3.1c-3,0-5.5,0.9-7.5,2.8c-2,1.9-3.3,4.8-4,8.7l-7.2" +
+ "-0.8 c0.7-5.3,2.6-9.3,5.8-12.1c3.2-2.8,7.5-4.2,12.8-4.2c5.6,0," +
+ "10.1,1.5,13.4,4.5c3.3,3,5,6.7,5,10.9c0,2.5-0.6,4.8-1.8,6.8 " +
+ "s-3.5,4.6-6.9,7.6c-2.3,2-3.8,3.5-4.5,4.4c-0.7,1-1.2,2-1.6,3.3" +
+ "c-0.3,1.2-0.5,3.2-0.6,6H51.4z M51,83.8v-7.9h8v7.9H51z",
+
node: "M15,100a5,5,0,0,1-5-5v-65a5,5,0,0,1,5-5h80a5,5,0,0,1,5,5" +
"v65a5,5,0,0,1-5,5zM14,22.5l11-11a10,3,0,0,1,10-2h40a10,3,0,0,1," +
"10,2l11,11zM16,35a5,5,0,0,1,10,0a5,5,0,0,1-10,0z",
@@ -84,6 +93,22 @@
"M50,29l12,0,0-8,18,13-18,13,0-8-12,0zM60,57l-12,0,0-8-18,13," +
"18,13,0-8,12,0z",
+ microwave: "M85,71.2c-8.9,10.5-29.6,8.7-45.3-3.5C23.9,55.4,19.8," +
+ "37,28.6,26.5C29.9,38.6,71.5,69.9,85,71.2z M92.7,76.2M16.2,15 " +
+ "M69.5,100.7v-4c0-1.4-1.2-2.2-2.6-2.2H19.3c-1.4,0-2.8,0.7-2.8,2.2" +
+ "v3.9c0,0.7,0.8,1,1.5,1h50.3C69,101.5,69.5,101.3,69.5,100.7z " +
+ "M77.3,7.5l0,3.7c9,0.1,16.3,7.1,16.2,15.7l3.9,0C97.5,16.3,88.5," +
+ "7.6,77.3,7.5z M77.6,14.7l0,2.5c5.3,0,9.7,4.2,9.6,9.3l2.6,0C89.9" +
+ ",20,84.4,14.7,77.6,14.7z M82.3,22.2c-1.3-1.2-2.9-1.9-4.7-1.9" +
+ "l0,1.2c1.4,0,2.8,0.6,3.8,1.5c1,1,1.6,2.3,1.6,3.7l1.3,0C84.3,25.1," +
+ "83.6,23.4,82.3,22.2z M38.9,69.5l-5.1,23h16.5l-2.5-17.2C44.1,73.3," +
+ "38.9,69.5,38.9,69.5zM58.1,54.1c13.7,10.1,26.5,16.8,29.2,13.7" +
+ "c2.7-3.1-5.6-13-19.3-24.4 M62.9,34.2 M62,37.9C47.7,27.3,33.7,20," +
+ "31,23.1c-2.7,3.2,7,14.2,20.6,26 M73.9,25.7c-2.9,0.1-5.2,2.3-5.1," +
+ "4.8c0,0.7,0.2,1.4,0.6,2l0,0L53.8,49.7l3.3,2.5L72.7,35l-0.4-0.3" +
+ "c0.6,0.2,1.3,0.3,1.9,0.3c2.9-0.1,5.2-2.3,5.1-4.9C79.3,27.6,76.8," +
+ "25.6,73.9,25.7z",
+
chain: "M60.4,77.6c-4.9,5.2-9.6,11.3-15.3,16.3c-8.6,7.5-20.4,6.8" +
"-28-0.8c-7.7-7.7-8.4-19.6-0.8-28.4c6.5-7.4,13.5-14.4,20.9-20.9" +
"c7.5-6.7,19.2-6.7,26.5-0.8c3.5,2.8,4.4,6.1,2.2,8.7c-2.7,3.1" +
@@ -570,6 +595,10 @@
return glyphs.get(id);
}
+ function glyphDefined(id) {
+ return glyphs.has(id);
+ }
+
// Note: defs should be a D3 selection of a single <defs> element
function loadDefs(defs, glyphIds, noClear) {
var list = fs.isA(glyphIds) || ids(),
@@ -633,6 +662,7 @@
registerGlyphSet: registerGlyphSet,
ids: ids,
glyph: glyph,
+ glyphDefined: glyphDefined,
loadDefs: loadDefs,
addGlyph: addGlyph
};
diff --git a/framework/src/onos/web/gui/src/main/webapp/app/fw/svg/icon.js b/framework/src/onos/web/gui/src/main/webapp/app/fw/svg/icon.js
index ba794313..15b44bc9 100644
--- a/framework/src/onos/web/gui/src/main/webapp/app/fw/svg/icon.js
+++ b/framework/src/onos/web/gui/src/main/webapp/app/fw/svg/icon.js
@@ -64,7 +64,8 @@
nav_devs: 'switch',
nav_links: 'ports',
nav_hosts: 'endstation',
- nav_intents: 'relatedIntents'
+ nav_intents: 'relatedIntents',
+ nav_processors: 'allTraffic'
};
function ensureIconLibDefs() {
@@ -162,6 +163,7 @@
// Returns the D3 selection of the icon.
function addDeviceIcon(elem, glyphId) {
var cfg = config.device,
+ gid = gs.glyphDefined(glyphId) ? glyphId : 'query',
g = elem.append('g')
.attr('class', 'svgIcon deviceIcon');
@@ -174,7 +176,7 @@
});
g.append('use').attr({
- 'xlink:href': '#' + glyphId,
+ 'xlink:href': '#' + gid,
width: cfg.dim,
height: cfg.dim
});
diff --git a/framework/src/onos/web/gui/src/main/webapp/app/fw/util/keys.js b/framework/src/onos/web/gui/src/main/webapp/app/fw/util/keys.js
index 2985565c..5ff4f7f4 100644
--- a/framework/src/onos/web/gui/src/main/webapp/app/fw/util/keys.js
+++ b/framework/src/onos/web/gui/src/main/webapp/app/fw/util/keys.js
@@ -25,6 +25,7 @@
// internal state
var enabled = true,
+ globalEnabled = true,
keyHandler = {
globalKeys: {},
maskedKeys: {},
@@ -116,6 +117,9 @@
}
function quickHelp(view, key, code, ev) {
+ if (!globalEnabled) {
+ return false;
+ }
qhs.showQuickHelp(keyHandler);
return true;
}
@@ -126,6 +130,9 @@
}
function toggleTheme(view, key, code, ev) {
+ if (!globalEnabled) {
+ return false;
+ }
ts.toggleTheme();
return true;
}
@@ -173,6 +180,23 @@
keyHandler.viewGestures = [];
}
+ function checkNotGlobal(o) {
+ var oops = [];
+ if (fs.isO(o)) {
+ angular.forEach(o, function (val, key) {
+ if (keyHandler.globalKeys[key]) {
+ oops.push(key);
+ }
+ });
+ if (oops.length) {
+ $log.warn('Ignoring reserved global key(s):', oops.join(','));
+ oops.forEach(function (key) {
+ delete o[key];
+ });
+ }
+ }
+ }
+
angular.module('onosUtil')
.factory('KeyService',
['$log', 'FnService', 'ThemeService', 'NavService',
@@ -208,7 +232,11 @@
},
enableKeys: function (b) {
enabled = b;
- }
+ },
+ enableGlobalKeys: function (b) {
+ globalEnabled = b;
+ },
+ checkNotGlobal: checkNotGlobal
};
}]);
diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/device/device.css b/framework/src/onos/web/gui/src/main/webapp/app/view/device/device.css
index fc08f68b..e0e9cf57 100644
--- a/framework/src/onos/web/gui/src/main/webapp/app/view/device/device.css
+++ b/framework/src/onos/web/gui/src/main/webapp/app/view/device/device.css
@@ -75,6 +75,15 @@
margin: 8px 0;
}
+#device-details-panel .editable {
+ cursor: pointer;
+ border-bottom: 1px dashed darkgreen;
+}
+
+#device-details-panel h2 input {
+ font-size: 1.0em;
+}
+
#device-details-panel .top div.left {
float: left;
padding: 0 18px 0 0;
diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/device/device.html b/framework/src/onos/web/gui/src/main/webapp/app/view/device/device.html
index 5d51d1d4..63a04db8 100644
--- a/framework/src/onos/web/gui/src/main/webapp/app/view/device/device.html
+++ b/framework/src/onos/web/gui/src/main/webapp/app/view/device/device.html
@@ -35,13 +35,14 @@
<tr>
<td colId="available" class="table-icon" sortable></td>
<td colId="type" class="table-icon" sortable></td>
+ <td colId="name" sortable>Friendly Name </td>
<td colId="id" sortable>Device ID </td>
<td colId="masterid" sortable>Master Instance </td>
- <td colId="num_ports" sortable>Ports </td>
+ <td colId="num_ports" col-width="60px" sortable>Ports </td>
<td colId="mfr" sortable>Vendor </td>
<td colId="hw" sortable>H/W Version </td>
<td colId="sw" sortable>S/W Version </td>
- <td colId="protocol" sortable>Protocol </td>
+ <td colId="protocol" col-width="80px" sortable>Protocol </td>
</tr>
</table>
</div>
@@ -64,6 +65,7 @@
<td class="table-icon">
<div icon icon-id="{{dev._iconid_type}}"></div>
</td>
+ <td>{{dev.name}}</td>
<td>{{dev.id}}</td>
<td>{{dev.masterid}}</td>
<td>{{dev.num_ports}}</td>
diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/device/device.js b/framework/src/onos/web/gui/src/main/webapp/app/view/device/device.js
index 7a2dc4f9..5b7120fd 100644
--- a/framework/src/onos/web/gui/src/main/webapp/app/view/device/device.js
+++ b/framework/src/onos/web/gui/src/main/webapp/app/view/device/device.js
@@ -22,13 +22,17 @@
'use strict';
// injected refs
- var $log, $scope, $location, fs, mast, ps, wss, is, ns;
+ var $log, $scope, $loc, fs, mast, ps, wss, is, ns, ks;
// internal state
var detailsPanel,
- pStartY, pHeight,
- top, bottom, iconDiv,
- wSize;
+ pStartY,
+ pHeight,
+ top,
+ bottom,
+ iconDiv,
+ wSize,
+ editingName = false;
// constants
var topPdg = 13,
@@ -39,13 +43,15 @@
pName = 'device-details-panel',
detailsReq = 'deviceDetailsRequest',
detailsResp = 'deviceDetailsResponse',
+ nameChangeReq = 'deviceNameChangeRequest',
+ nameChangeResp = 'deviceNameChangeResponse',
propOrder = [
- 'type', 'masterid', 'chassisid',
+ 'id', 'type', 'masterid', 'chassisid',
'mfr', 'hw', 'sw', 'protocol', 'serial'
],
friendlyProps = [
- 'Type', 'Master ID', 'Chassis ID',
+ 'URI', 'Type', 'Master ID', 'Chassis ID',
'Vendor', 'H/W Version', 'S/W Version', 'Protocol', 'Serial #'
],
portCols = [
@@ -59,7 +65,9 @@
if (detailsPanel.isVisible()) {
$scope.selId = null;
detailsPanel.hide();
+ return true;
}
+ return false;
}
function addCloseBtn(div) {
@@ -68,6 +76,59 @@
div.on('click', closePanel);
}
+ function exitEditMode(nameH2, name) {
+ nameH2.html(name);
+ nameH2.classed('editable', true);
+ editingName = false;
+ ks.enableGlobalKeys(true);
+ }
+
+ function editNameSave() {
+ var nameH2 = top.select('h2'),
+ id = $scope.panelData.id,
+ val,
+ newVal;
+
+ if (editingName) {
+ val = nameH2.select('input').property('value').trim();
+ newVal = val || id;
+
+ exitEditMode(nameH2, newVal);
+ $scope.panelData.name = newVal;
+ wss.sendEvent(nameChangeReq, { id: id, name: val });
+ }
+ }
+
+ function editNameCancel() {
+ if (editingName) {
+ exitEditMode(top.select('h2'), $scope.panelData.name);
+ return true;
+ }
+ return false;
+ }
+
+ function editName() {
+ var nameH2 = top.select('h2'),
+ tf, el;
+
+ if (!editingName) {
+ nameH2.classed('editable', false);
+ nameH2.html('');
+ tf = nameH2.append('input').classed('name-input', true)
+ .attr('type', 'text')
+ .attr('value', $scope.panelData.name);
+ el = tf[0][0];
+ el.focus();
+ el.select();
+ editingName = true;
+ ks.enableGlobalKeys(false);
+ }
+ }
+
+ function handleEscape() {
+ return editNameCancel() || closePanel();
+ }
+
function setUpPanel() {
var container, closeBtn, tblDiv;
detailsPanel.empty();
@@ -78,7 +139,7 @@
closeBtn = top.append('div').classed('close-btn', true);
addCloseBtn(closeBtn);
iconDiv = top.append('div').classed('dev-icon', true);
- top.append('h2');
+ top.append('h2').classed('editable', true).on('click', editName);
tblDiv = top.append('div').classed('top-tables', true);
tblDiv.append('div').classed('left', true).append('table');
@@ -110,11 +171,11 @@
.append('tbody');
is.loadEmbeddedIcon(iconDiv, details._iconid_type, 40);
- top.select('h2').html(details.id);
+ top.select('h2').html(details.name);
propOrder.forEach(function (prop, i) {
// properties are split into two tables
- addProp(i < 3 ? leftTbl : rightTbl, i, details[prop]);
+ addProp(i < 4 ? leftTbl : rightTbl, i, details[prop]);
});
}
@@ -156,14 +217,23 @@
detailsPanel.width(tbWidth + ctnrPdg);
}
+ function populateName(div, name) {
+ var lab = div.select('.label'),
+ val = div.select('.value');
+ lab.html('Friendly Name:');
+ val.html(name);
+ }
+
function populateDetails(details) {
- var topTbs, btmTbl, ports;
+ var nameDiv, topTbs, btmTbl, ports;
setUpPanel();
+ nameDiv = top.select('.name-div');
topTbs = top.select('.top-tables');
btmTbl = bottom.select('table');
ports = details.ports;
+ populateName(nameDiv, details.name);
populateTop(topTbs, details);
populateBottom(btmTbl, ports);
@@ -175,6 +245,13 @@
$scope.$apply();
}
+ function respNameCb(data) {
+ if (data.warn) {
+ $log.warn(data.warn, data.id);
+ top.select('h2').html(data.id);
+ }
+ }
+
function createDetailsPane() {
detailsPanel = ps.createPanel(pName, {
width: wSize.width,
@@ -193,21 +270,26 @@
.controller('OvDeviceCtrl',
['$log', '$scope', '$location', 'TableBuilderService', 'FnService',
'MastService', 'PanelService', 'WebSocketService', 'IconService',
- 'NavService',
+ 'NavService', 'KeyService',
function (_$log_, _$scope_, _$location_,
- tbs, _fs_, _mast_, _ps_, _wss_, _is_, _ns_) {
+ tbs, _fs_, _mast_, _ps_, _wss_, _is_, _ns_, _ks_) {
+ var params,
+ handlers = {};
+
$log = _$log_;
$scope = _$scope_;
- $location = _$location_;
+ $loc = _$location_;
fs = _fs_;
mast = _mast_;
ps = _ps_;
wss = _wss_;
is = _is_;
ns = _ns_;
- var params = $location.search(),
- handlers = {};
+ ks = _ks_;
+
+ params = $loc.search();
+
$scope.panelData = {};
$scope.flowTip = 'Show flow view for selected device';
$scope.portTip = 'Show port view for selected device';
@@ -215,6 +297,7 @@
// details panel handlers
handlers[detailsResp] = respDetailsCb;
+ handlers[nameChangeResp] = respNameCb;
wss.bindHandlers(handlers);
// query for if a certain device needs to be highlighted
@@ -278,7 +361,8 @@
}
// create key bindings to handle panel
ks.keyBindings({
- esc: [closePanel, 'Close the details panel'],
+ enter: editNameSave,
+ esc: [handleEscape, 'Close the details panel'],
_helpFormat: ['esc']
});
ks.gestureNotes([
diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/processor/processor.css b/framework/src/onos/web/gui/src/main/webapp/app/view/processor/processor.css
new file mode 100644
index 00000000..12cf6377
--- /dev/null
+++ b/framework/src/onos/web/gui/src/main/webapp/app/view/processor/processor.css
@@ -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.
+ */
+
+/*
+ ONOS GUI -- Processor View -- CSS file
+ */
+
+#ov-processor h2 {
+ display: inline-block;
+}
+
+#ov-processor div.ctrl-btns {
+ width: 40px;
+}
+
+.light #ov-processor .current-view use {
+ fill: white;
+}
+.dark #ov-processor .current-view use {
+ fill: #304860;
+}
+
+.light #ov-processor .current-view rect {
+ fill: deepskyblue;
+}
+.dark #ov-processor .current-view rect {
+ fill: #eee;
+}
+
+#ov-processor td.number {
+ text-align: right;
+}
+
+#ov-processor tr.no-data td {
+ text-align: center;
+}
diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/processor/processor.html b/framework/src/onos/web/gui/src/main/webapp/app/view/processor/processor.html
new file mode 100644
index 00000000..1c615041
--- /dev/null
+++ b/framework/src/onos/web/gui/src/main/webapp/app/view/processor/processor.html
@@ -0,0 +1,63 @@
+<!-- processor partial HTML -->
+<div id="ov-processor">
+ <div class="tabular-header">
+ <h2>
+ Packet Processors ({{tableData.length}} Processors total)
+ </h2>
+ <div class="ctrl-btns">
+ <div class="refresh" ng-class="{active: autoRefresh}"
+ icon icon-size="36" icon-id="refresh"
+ tooltip tt-msg="autoRefreshTip"
+ ng-click="toggleRefresh()"></div>
+ <!--
+ <div class="separator"></div>
+
+ <div class="current-view"
+ icon icon-id="processorTable" icon-size="36"></div>
+
+ <div class="active"
+ icon icon-id="requestTable" icon-size="36"git sta
+ tooltip tt-msg="requestTip"
+ ng-click="nav('request')"></div>
+ -->
+ </div>
+ </div>
+
+ <div class="summary-list" onos-table-resize>
+ <div ng-show="loading" class="loading-wheel"
+ icon icon-id="loading" icon-size="75"></div>
+
+ <div class="table-header" onos-sortable-header>
+ <table>
+ <tr>
+ <td class="number" colId="priority" sortable col-width="80px">Priority </td>
+ <td colId="type" sortable col-width="80px">Type </td>
+ <td colId="processor" sortable col-width="500px">Class </td>
+ <td class="number" colId="packets" sortable col-width="100px">Packets </td>
+ <td class="number" colId="avgMillis" sortable col-width="100px">Average (ms) </td>
+ </tr>
+ </table>
+ </div>
+
+ <div class="table-body">
+ <table onos-flash-changes id-prop="id">
+ <tr ng-if="!tableData.length" class="no-data">
+ <td colspan="5">
+ No Processors found
+ </td>
+ </tr>
+
+ <tr ng-repeat="processor in tableData track by $index"
+ ng-repeat-complete row-id="{{processor.id}}">
+ <td class="number">{{processor.priority}}</td>
+ <td>{{processor.type}}</td>
+ <td>{{processor.processor}}</td>
+ <td class="number">{{processor.packets}}</td>
+ <td class="number">{{processor.avgMillis}}</td>
+ </tr>
+ </table>
+ </div>
+
+ </div>
+
+</div>
diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/processor/processor.js b/framework/src/onos/web/gui/src/main/webapp/app/view/processor/processor.js
new file mode 100644
index 00000000..89d717b6
--- /dev/null
+++ b/framework/src/onos/web/gui/src/main/webapp/app/view/processor/processor.js
@@ -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.
+ */
+
+/*
+ ONOS GUI -- Packet Processor View Module
+ */
+
+(function () {
+ 'use strict';
+
+ // injected references
+ var $log, $scope, $location, fs, tbs, ns;
+
+ angular.module('ovProcessor', [])
+ .controller('OvProcessorCtrl',
+ ['$log', '$scope', '$location',
+ 'FnService', 'TableBuilderService', 'NavService',
+
+ function (_$log_, _$scope_, _$location_, _fs_, _tbs_, _ns_) {
+ var params;
+ $log = _$log_;
+ $scope = _$scope_;
+ $location = _$location_;
+ fs = _fs_;
+ tbs = _tbs_;
+ ns = _ns_;
+ $scope.requestTip = 'Show packet requests';
+
+ params = $location.search();
+
+ tbs.buildTable({
+ scope: $scope,
+ tag: 'processor',
+ query: params
+ });
+
+ $scope.nav = function (path) {
+ if ($scope.devId) {
+ ns.navTo(path);
+ }
+ };
+
+ $log.log('OvProcessorCtrl has been created');
+ }]);
+}());
diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/settings/settings.html b/framework/src/onos/web/gui/src/main/webapp/app/view/settings/settings.html
index ee069d37..61081017 100644
--- a/framework/src/onos/web/gui/src/main/webapp/app/view/settings/settings.html
+++ b/framework/src/onos/web/gui/src/main/webapp/app/view/settings/settings.html
@@ -17,7 +17,7 @@
<div class="table-header" onos-sortable-header>
<table>
<tr>
- <td colId="component" sortable col-width="200px">Component </td>
+ <td colId="component" sortable col-width="300px">Component </td>
<td colId="id" sortable>Property </td>
<td colId="type" sortable col-width="70px">Type </td>
<td colId="value" sortable>Value </td>
diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topo.js b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topo.js
index 21894100..42b6f4bd 100644
--- a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topo.js
+++ b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topo.js
@@ -95,6 +95,9 @@
// and include them in the quick-help panel
function mergeKeys(extra) {
var _hf = actionMap._helpFormat[2];
+
+ ks.checkNotGlobal(extra);
+
extra._keyOrder.forEach(function (k) {
var d = extra[k],
cb = d && d.cb,
diff --git a/framework/src/onos/web/gui/src/main/webapp/index.html b/framework/src/onos/web/gui/src/main/webapp/index.html
index 154f9416..5df3c664 100644
--- a/framework/src/onos/web/gui/src/main/webapp/index.html
+++ b/framework/src/onos/web/gui/src/main/webapp/index.html
@@ -121,6 +121,7 @@
<script src="app/view/app/app.js"></script>
<script src="app/view/settings/settings.js"></script>
<script src="app/view/cluster/cluster.js"></script>
+ <script src="app/view/processor/processor.js"></script>
<script src="app/view/tunnel/tunnel.js"></script>
<!-- This is where contributed javascript will get injected -->
@@ -139,6 +140,7 @@
<link rel="stylesheet" href="app/view/app/app.css">
<link rel="stylesheet" href="app/view/settings/settings.css">
<link rel="stylesheet" href="app/view/cluster/cluster.css">
+ <link rel="stylesheet" href="app/view/processor/processor.css">
<link rel="stylesheet" href="app/view/tunnel/tunnel.css">
<!-- This is where contributed stylesheets will get injected -->
diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_10_addDevice_s9_ids.json b/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_10_addDevice_s9_ids.json
new file mode 100644
index 00000000..232d4edb
--- /dev/null
+++ b/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_10_addDevice_s9_ids.json
@@ -0,0 +1,18 @@
+{
+ "event": "addDevice",
+ "payload": {
+ "id": "of:0000000000000009",
+ "type": "ids",
+ "online": true,
+ "master": "ONOS",
+ "labels": [
+ "",
+ "ids",
+ "of:0000000000000009"
+ ],
+ "metaUi": {
+ "x": 200,
+ "y": 400
+ }
+ }
+}
diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_11_addDevice_s10_controller.json b/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_11_addDevice_s10_controller.json
new file mode 100644
index 00000000..abd24d66
--- /dev/null
+++ b/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_11_addDevice_s10_controller.json
@@ -0,0 +1,18 @@
+{
+ "event": "addDevice",
+ "payload": {
+ "id": "of:00000000000000010",
+ "type": "controller",
+ "online": true,
+ "master": "ONOS",
+ "labels": [
+ "",
+ "controller",
+ "of:0000000000000010"
+ ],
+ "metaUi": {
+ "x": 350,
+ "y": 400
+ }
+ }
+}
diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_12_addDevice_s11_virtual.json b/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_12_addDevice_s11_virtual.json
new file mode 100644
index 00000000..1fe1837b
--- /dev/null
+++ b/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_12_addDevice_s11_virtual.json
@@ -0,0 +1,18 @@
+{
+ "event": "addDevice",
+ "payload": {
+ "id": "of:00000000000000011",
+ "type": "virtual",
+ "online": true,
+ "master": "ONOS",
+ "labels": [
+ "",
+ "virtual",
+ "of:0000000000000011"
+ ],
+ "metaUi": {
+ "x": 500,
+ "y": 400
+ }
+ }
+}
diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_13_addDevice_s12_fiber_switch.json b/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_13_addDevice_s12_fiber_switch.json
new file mode 100644
index 00000000..954376cd
--- /dev/null
+++ b/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_13_addDevice_s12_fiber_switch.json
@@ -0,0 +1,18 @@
+{
+ "event": "addDevice",
+ "payload": {
+ "id": "of:00000000000000012",
+ "type": "fiber_switch",
+ "online": true,
+ "master": "ONOS",
+ "labels": [
+ "",
+ "fiber_switch",
+ "of:0000000000000012"
+ ],
+ "metaUi": {
+ "x": 650,
+ "y": 400
+ }
+ }
+}
diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_14_addDevice_s13_microwave.json b/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_14_addDevice_s13_microwave.json
new file mode 100644
index 00000000..3d40ceca
--- /dev/null
+++ b/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_14_addDevice_s13_microwave.json
@@ -0,0 +1,18 @@
+{
+ "event": "addDevice",
+ "payload": {
+ "id": "of:00000000000000013",
+ "type": "microwave",
+ "online": true,
+ "master": "ONOS",
+ "labels": [
+ "",
+ "microwave",
+ "of:0000000000000013"
+ ],
+ "metaUi": {
+ "x": 300,
+ "y": 500
+ }
+ }
+}
diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_15_addDevice_s14_other.json b/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_15_addDevice_s14_other.json
new file mode 100644
index 00000000..e33532d7
--- /dev/null
+++ b/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_15_addDevice_s14_other.json
@@ -0,0 +1,18 @@
+{
+ "event": "addDevice",
+ "payload": {
+ "id": "of:00000000000000014",
+ "type": "other",
+ "online": true,
+ "master": "ONOS",
+ "labels": [
+ "",
+ "other",
+ "of:0000000000000014"
+ ],
+ "metaUi": {
+ "x": 450,
+ "y": 500
+ }
+ }
+}
diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_16_addDevice_s15_unmatched.json b/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_16_addDevice_s15_unmatched.json
new file mode 100644
index 00000000..1773c917
--- /dev/null
+++ b/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_16_addDevice_s15_unmatched.json
@@ -0,0 +1,18 @@
+{
+ "event": "addDevice",
+ "payload": {
+ "id": "of:00000000000000015",
+ "type": "-unmatched-",
+ "online": true,
+ "master": "ONOS-B",
+ "labels": [
+ "",
+ "-unmatched-",
+ "of:0000000000000015"
+ ],
+ "metaUi": {
+ "x": 600,
+ "y": 500
+ }
+ }
+}
diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_1_addInstance.json b/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_1_addInstance.json
new file mode 100644
index 00000000..20be9e2b
--- /dev/null
+++ b/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_1_addInstance.json
@@ -0,0 +1,14 @@
+{
+ "event": "addInstance",
+ "payload": {
+ "id": "ONOS",
+ "ip": "192.168.56.101",
+ "online": true,
+ "uiAttached": true,
+ "switches": 4,
+ "labels": [
+ "ONOS",
+ "192.168.56.101"
+ ]
+ }
+}
diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_2_addDevice_s1_switch.json b/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_2_addDevice_s1_switch.json
new file mode 100644
index 00000000..5f8ad66e
--- /dev/null
+++ b/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_2_addDevice_s1_switch.json
@@ -0,0 +1,18 @@
+{
+ "event": "addDevice",
+ "payload": {
+ "id": "of:0000000000000001",
+ "type": "switch",
+ "online": true,
+ "master": "ONOS",
+ "labels": [
+ "",
+ "switch",
+ "of:0000000000000001"
+ ],
+ "metaUi": {
+ "x": 200,
+ "y": 200
+ }
+ }
+}
diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_3_addDevice_s2_router.json b/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_3_addDevice_s2_router.json
new file mode 100644
index 00000000..b6da44ce
--- /dev/null
+++ b/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_3_addDevice_s2_router.json
@@ -0,0 +1,18 @@
+{
+ "event": "addDevice",
+ "payload": {
+ "id": "of:0000000000000002",
+ "type": "router",
+ "online": true,
+ "master": "ONOS",
+ "labels": [
+ "",
+ "router",
+ "of:0000000000000002"
+ ],
+ "metaUi": {
+ "x": 350,
+ "y": 200
+ }
+ }
+}
diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_4_addDevice_s3_roadm.json b/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_4_addDevice_s3_roadm.json
new file mode 100644
index 00000000..468749ef
--- /dev/null
+++ b/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_4_addDevice_s3_roadm.json
@@ -0,0 +1,18 @@
+{
+ "event": "addDevice",
+ "payload": {
+ "id": "of:0000000000000003",
+ "type": "roadm",
+ "online": true,
+ "master": "ONOS",
+ "labels": [
+ "",
+ "roadm",
+ "of:0000000000000003"
+ ],
+ "metaUi": {
+ "x": 500,
+ "y": 200
+ }
+ }
+}
diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_5_addDevice_s4_otn.json b/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_5_addDevice_s4_otn.json
new file mode 100644
index 00000000..c8e234be
--- /dev/null
+++ b/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_5_addDevice_s4_otn.json
@@ -0,0 +1,18 @@
+{
+ "event": "addDevice",
+ "payload": {
+ "id": "of:0000000000000004",
+ "type": "otn",
+ "online": true,
+ "master": "ONOS",
+ "labels": [
+ "",
+ "otn",
+ "of:0000000000000004"
+ ],
+ "metaUi": {
+ "x": 650,
+ "y": 200
+ }
+ }
+}
diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_6_addDevice_s5_roadm_otn.json b/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_6_addDevice_s5_roadm_otn.json
new file mode 100644
index 00000000..c54cc4ae
--- /dev/null
+++ b/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_6_addDevice_s5_roadm_otn.json
@@ -0,0 +1,18 @@
+{
+ "event": "addDevice",
+ "payload": {
+ "id": "of:0000000000000005",
+ "type": "roadm_otn",
+ "online": true,
+ "master": "ONOS",
+ "labels": [
+ "",
+ "roadm_otn",
+ "of:0000000000000005"
+ ],
+ "metaUi": {
+ "x": 300,
+ "y": 300
+ }
+ }
+}
diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_7_addDevice_s6_firewall.json b/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_7_addDevice_s6_firewall.json
new file mode 100644
index 00000000..19d50d45
--- /dev/null
+++ b/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_7_addDevice_s6_firewall.json
@@ -0,0 +1,18 @@
+{
+ "event": "addDevice",
+ "payload": {
+ "id": "of:0000000000000006",
+ "type": "firewall",
+ "online": true,
+ "master": "ONOS",
+ "labels": [
+ "",
+ "firewall",
+ "of:0000000000000006"
+ ],
+ "metaUi": {
+ "x": 450,
+ "y": 300
+ }
+ }
+}
diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_8_addDevice_s7_balancer.json b/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_8_addDevice_s7_balancer.json
new file mode 100644
index 00000000..d9a3b795
--- /dev/null
+++ b/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_8_addDevice_s7_balancer.json
@@ -0,0 +1,18 @@
+{
+ "event": "addDevice",
+ "payload": {
+ "id": "of:0000000000000007",
+ "type": "balancer",
+ "online": true,
+ "master": "ONOS",
+ "labels": [
+ "",
+ "balancer",
+ "of:0000000000000007"
+ ],
+ "metaUi": {
+ "x": 600,
+ "y": 300
+ }
+ }
+}
diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_9_addDevice_s8_ips.json b/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_9_addDevice_s8_ips.json
new file mode 100644
index 00000000..c89f565e
--- /dev/null
+++ b/framework/src/onos/web/gui/src/test/_karma/ev/devices/ev_9_addDevice_s8_ips.json
@@ -0,0 +1,18 @@
+{
+ "event": "addDevice",
+ "payload": {
+ "id": "of:0000000000000008",
+ "type": "ips",
+ "online": true,
+ "master": "ONOS",
+ "labels": [
+ "",
+ "ips",
+ "of:0000000000000008"
+ ],
+ "metaUi": {
+ "x": 750,
+ "y": 300
+ }
+ }
+}
diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/devices/scenario.json b/framework/src/onos/web/gui/src/test/_karma/ev/devices/scenario.json
new file mode 100644
index 00000000..ee3c1eaf
--- /dev/null
+++ b/framework/src/onos/web/gui/src/test/_karma/ev/devices/scenario.json
@@ -0,0 +1,12 @@
+{
+ "comments": [
+ "Showing all device types"
+ ],
+ "title": "Show Device Types",
+ "params": {
+ "lastAuto": 16
+ },
+ "description": [
+ "Show all device types."
+ ]
+}