From 643ee33289bd2cb9e6afbfb09b4ed72d467ba1c2 Mon Sep 17 00:00:00 2001 From: Ashlee Young Date: Tue, 3 Nov 2015 14:08:10 -0800 Subject: This updates ONOS src tree to commit id 03fa5e571cabbd001ddb1598847e1150b11c7333 Change-Id: I13b554026d6f902933e35887d29bd5fdb669c0bd Signed-off-by: Ashlee Young --- .../aaa/src/main/java/org/onosproject/aaa/AAA.java | 1 + .../main/java/org/onosproject/cordvtn/CordVtn.java | 68 +- .../onosproject/cordvtn/CordVtnConfigManager.java | 19 +- .../org/onosproject/cordvtn/DefaultOvsdbNode.java | 2 +- framework/src/onos/apps/dhcp/api/pom.xml | 64 + .../java/org/onosproject/dhcp/DhcpService.java | 81 ++ .../main/java/org/onosproject/dhcp/DhcpStore.java | 109 ++ .../java/org/onosproject/dhcp/IpAssignment.java | 215 +++ .../java/org/onosproject/dhcp/package-info.java | 20 + .../org/onosproject/dhcp/IpAssignmentTest.java | 100 ++ framework/src/onos/apps/dhcp/app/app.xml | 23 + framework/src/onos/apps/dhcp/app/features.xml | 25 + framework/src/onos/apps/dhcp/app/pom.xml | 166 +++ .../org/onosproject/dhcp/cli/DhcpLeaseDetails.java | 41 + .../onosproject/dhcp/cli/DhcpListAllMappings.java | 44 + .../dhcp/cli/DhcpRemoveStaticMapping.java | 56 + .../onosproject/dhcp/cli/DhcpSetStaticMapping.java | 61 + .../org/onosproject/dhcp/cli/FreeIpCompleter.java | 48 + .../org/onosproject/dhcp/cli/MacIdCompleter.java | 48 + .../org/onosproject/dhcp/cli/package-info.java | 20 + .../java/org/onosproject/dhcp/impl/DhcpConfig.java | 319 +++++ .../org/onosproject/dhcp/impl/DhcpManager.java | 699 ++++++++++ .../java/org/onosproject/dhcp/impl/DhcpUi.java | 74 ++ .../dhcp/impl/DhcpViewMessageHandler.java | 97 ++ .../dhcp/impl/DistributedDhcpStore.java | 328 +++++ .../org/onosproject/dhcp/impl/package-info.java | 20 + .../org/onosproject/dhcp/rest/DHCPWebResource.java | 164 +++ .../org/onosproject/dhcp/rest/package-info.java | 20 + .../resources/OSGI-INF/blueprint/shell-config.xml | 43 + .../app/src/main/resources/app/view/dhcp/dhcp.css | 27 + .../app/src/main/resources/app/view/dhcp/dhcp.html | 47 + .../app/src/main/resources/app/view/dhcp/dhcp.js | 51 + .../apps/dhcp/app/src/main/resources/gui/css.html | 1 + .../apps/dhcp/app/src/main/resources/gui/js.html | 1 + .../apps/dhcp/app/src/main/webapp/WEB-INF/web.xml | 43 + .../org/onosproject/dhcp/impl/DhcpManagerTest.java | 392 ++++++ .../apps/dhcp/app/src/test/resources/dhcp-cfg.json | 22 + framework/src/onos/apps/dhcp/pom.xml | 143 +- .../java/org/onosproject/dhcp/DhcpService.java | 81 -- .../main/java/org/onosproject/dhcp/DhcpStore.java | 109 -- .../java/org/onosproject/dhcp/IpAssignment.java | 215 --- .../org/onosproject/dhcp/cli/DhcpLeaseDetails.java | 41 - .../onosproject/dhcp/cli/DhcpListAllMappings.java | 44 - .../dhcp/cli/DhcpRemoveStaticMapping.java | 56 - .../onosproject/dhcp/cli/DhcpSetStaticMapping.java | 61 - .../org/onosproject/dhcp/cli/FreeIpCompleter.java | 48 - .../org/onosproject/dhcp/cli/MacIdCompleter.java | 48 - .../org/onosproject/dhcp/cli/package-info.java | 20 - .../java/org/onosproject/dhcp/impl/DhcpConfig.java | 319 ----- .../org/onosproject/dhcp/impl/DhcpManager.java | 699 ---------- .../java/org/onosproject/dhcp/impl/DhcpUi.java | 74 -- .../dhcp/impl/DhcpViewMessageHandler.java | 97 -- .../dhcp/impl/DistributedDhcpStore.java | 328 ----- .../org/onosproject/dhcp/impl/package-info.java | 20 - .../java/org/onosproject/dhcp/package-info.java | 20 - .../org/onosproject/dhcp/rest/DHCPWebResource.java | 164 --- .../org/onosproject/dhcp/rest/package-info.java | 20 - .../resources/OSGI-INF/blueprint/shell-config.xml | 43 - .../dhcp/src/main/resources/app/view/dhcp/dhcp.css | 27 - .../src/main/resources/app/view/dhcp/dhcp.html | 47 - .../dhcp/src/main/resources/app/view/dhcp/dhcp.js | 51 - .../onos/apps/dhcp/src/main/resources/gui/css.html | 1 - .../onos/apps/dhcp/src/main/resources/gui/js.html | 1 - .../onos/apps/dhcp/src/main/webapp/WEB-INF/web.xml | 43 - .../org/onosproject/dhcp/IpAssignmentTest.java | 100 -- .../org/onosproject/dhcp/impl/DhcpManagerTest.java | 392 ------ .../apps/dhcp/src/test/resources/dhcp-cfg.json | 22 - .../org/onosproject/igmp/impl/package-info.java | 20 + .../org/onosproject/mfwd/rest/package-info.java | 20 + .../java/org/onosproject/mlb/package-info.java | 20 + framework/src/onos/apps/openstackswitching/pom.xml | 121 ++ .../openstackswitching/OpenstackArpHandler.java | 51 + .../openstackswitching/OpenstackDhcpHandler.java | 45 + .../openstackswitching/OpenstackNetwork.java | 112 ++ .../openstackswitching/OpenstackPort.java | 350 +++++ .../OpenstackSwitchingManager.java | 437 +++++++ .../OpenstackSwitchingRulePopulator.java | 228 ++++ .../OpenstackSwitchingService.java | 49 + .../openstackswitching/package-info.java | 20 + .../web/OpenstackNetworkCodec.java | 64 + .../web/OpenstackNetworkWebResource.java | 62 + .../openstackswitching/web/OpenstackPortCodec.java | 104 ++ .../web/OpenstackPortWebResource.java | 106 ++ .../openstackswitching/web/package-info.java | 20 + .../src/main/webapp/WEB-INF/web.xml | 44 + .../optical/OpticalPathProvisioner.java | 18 +- framework/src/onos/apps/pom.xml | 6 +- .../onosproject/sdnip/PeerConnectivityManager.java | 58 +- .../sdnip/PeerConnectivityManagerTest.java | 5 + .../org/onosproject/segmentrouting/ArpHandler.java | 5 +- .../segmentrouting/DefaultRoutingHandler.java | 24 +- .../segmentrouting/DeviceConfiguration.java | 164 ++- .../onosproject/segmentrouting/IcmpHandler.java | 4 +- .../segmentrouting/RoutingRulePopulator.java | 104 +- .../segmentrouting/SegmentRoutingManager.java | 190 ++- .../segmentrouting/SubnetAssignedVidStoreKey.java | 66 + .../grouphandler/DefaultEdgeGroupHandler.java | 9 +- .../grouphandler/DefaultGroupHandler.java | 81 +- .../grouphandler/DefaultTransitGroupHandler.java | 9 +- .../grouphandler/DeviceProperties.java | 18 + .../grouphandler/PolicyGroupHandler.java | 10 +- .../grouphandler/SubnetNextObjectiveStoreKey.java | 78 ++ .../cli/SetTestAddCommand.java | 12 +- .../cli/SetTestGetCommand.java | 12 +- .../cli/SetTestRemoveCommand.java | 23 +- .../virtualbng/ConnectPointConfiguration.java | 55 + .../onosproject/virtualbng/VbngConfiguration.java | 27 +- .../virtualbng/VbngConfigurationManager.java | 28 +- .../virtualbng/VbngConfigurationService.java | 12 +- .../org/onosproject/virtualbng/VbngManager.java | 49 +- framework/src/onos/apps/vtn/pom.xml | 17 + .../main/java/org/onosproject/sfc/SfcService.java | 52 + .../java/org/onosproject/sfc/impl/SfcManager.java | 69 + .../org/onosproject/sfc/impl/package-info.java | 20 + .../java/org/onosproject/sfc/package-info.java | 20 + .../onosproject/vtnrsc/DefaultFlowClassifier.java | 413 ++++++ .../org/onosproject/vtnrsc/DefaultPortChain.java | 201 +++ .../org/onosproject/vtnrsc/DefaultPortPair.java | 198 +++ .../onosproject/vtnrsc/DefaultPortPairGroup.java | 183 +++ .../org/onosproject/vtnrsc/FlowClassifier.java | 259 ++++ .../org/onosproject/vtnrsc/FlowClassifierId.java | 91 ++ .../java/org/onosproject/vtnrsc/PortChain.java | 148 +++ .../java/org/onosproject/vtnrsc/PortChainId.java | 95 ++ .../main/java/org/onosproject/vtnrsc/PortPair.java | 139 ++ .../java/org/onosproject/vtnrsc/PortPairGroup.java | 126 ++ .../org/onosproject/vtnrsc/PortPairGroupId.java | 95 ++ .../java/org/onosproject/vtnrsc/PortPairId.java | 95 ++ .../flowClassifier/FlowClassifierService.java | 72 + .../flowClassifier/impl/FlowClassifierManager.java | 108 ++ .../vtnrsc/flowClassifier/impl/package-info.java | 20 + .../vtnrsc/flowClassifier/package-info.java | 20 + .../vtnrsc/portchain/PortChainService.java | 80 ++ .../onosproject/vtnrsc/portchain/package-info.java | 20 + .../vtnrsc/portpairgroup/PortPairGroupService.java | 80 ++ .../vtnrsc/portpairgroup/package-info.java | 20 + .../vtnrsc/tunnel/TunnelConfigService.java | 72 - .../onosproject/vtnrsc/tunnel/package-info.java | 20 - .../virtualport/impl/VirtualPortManager.java | 40 +- .../vtnrsc/web/AllocationPoolsCodec.java | 40 - .../vtnrsc/web/AllowedAddressPairCodec.java | 40 - .../org/onosproject/vtnrsc/web/FixedIpCodec.java | 40 - .../vtnrsc/web/FlowClassifierCodec.java | 134 ++ .../onosproject/vtnrsc/web/HostRoutesCodec.java | 40 - .../onosproject/vtnrsc/web/SecurityGroupCodec.java | 39 - .../org/onosproject/vtnrsc/web/SubnetCodec.java | 53 - .../onosproject/vtnrsc/web/TenantNetworkCodec.java | 47 - .../onosproject/vtnrsc/web/VirtualPortCodec.java | 57 - .../flowclassifier/FlowClassifierIdTest.java | 68 + .../vtnrsc/subnet/DefaultAllocationPoolTest.java | 68 + .../vtnrsc/subnet/DefaultHostRouteTest.java | 68 + .../onosproject/vtnrsc/subnet/SubnetIdTest.java | 64 + .../tenantnetwork/DefaultNeutronNetworkTest.java | 83 ++ .../vtnrsc/tenantnetwork/PhysicalNetworkTest.java | 65 + .../vtnrsc/tenantnetwork/SegmentationIdTest.java | 64 + .../vtnrsc/tenantnetwork/TenantIdTest.java | 64 + .../vtnrsc/tenantnetwork/TenantNetworkIdTest.java | 64 + .../vtnrsc/virtualport/AllowedAddressPairTest.java | 76 ++ .../vtnrsc/virtualport/DefaultVirtualPortTest.java | 142 ++ .../vtnrsc/virtualport/FixedIpTest.java | 72 + .../vtnrsc/virtualport/SecurityGroupTest.java | 66 + .../vtnrsc/virtualport/VirtualPortIdTest.java | 66 + .../resources/FlowClassifierWebResource.java | 192 +++ .../vtnweb/resources/SubnetWebResource.java | 2 +- .../vtnweb/resources/TenantNetworkWebResource.java | 2 +- .../vtnweb/resources/VirtualPortWebResource.java | 2 +- .../vtnweb/web/AllocationPoolsCodec.java | 40 + .../vtnweb/web/AllowedAddressPairCodec.java | 40 + .../org/onosproject/vtnweb/web/FixedIpCodec.java | 40 + .../onosproject/vtnweb/web/HostRoutesCodec.java | 40 + .../org/onosproject/vtnweb/web/PortChainCodec.java | 105 ++ .../onosproject/vtnweb/web/SecurityGroupCodec.java | 39 + .../org/onosproject/vtnweb/web/SubnetCodec.java | 53 + .../onosproject/vtnweb/web/TenantNetworkCodec.java | 47 + .../onosproject/vtnweb/web/VirtualPortCodec.java | 57 + .../org/onosproject/vtnweb/web/package-info.java | 20 + .../onosproject/bgp/controller/BgpPeerManager.java | 54 + .../onosproject/bgpio/protocol/BGPFactories.java | 82 ++ .../org/onosproject/bgpio/protocol/BGPFactory.java | 60 + .../bgpio/protocol/BGPNotificationMsg.java | 34 +- .../bgpio/protocol/ver4/BGPFactoryVer4.java | 58 + .../bgpio/protocol/ver4/BGPMessageVer4.java | 109 ++ .../protocol/ver4/BGPNotificationMsgVer4.java | 17 +- .../bgpio/protocol/ver4/BgpPathAttributes.java | 190 +++ .../java/org/onosproject/bgpio/types/As4Path.java | 170 +++ .../java/org/onosproject/bgpio/types/AsPath.java | 209 +++ .../org/onosproject/bgpio/types/LocalPref.java | 120 ++ .../main/java/org/onosproject/bgpio/types/Med.java | 119 ++ .../java/org/onosproject/bgpio/types/NextHop.java | 138 ++ .../java/org/onosproject/bgpio/types/Origin.java | 166 +++ .../bgpio/types/attr/BgpAttrNodeFlagBitTlv.java | 78 +- .../bgpio/types/attr/BgpAttrRouterIdV4.java | 40 +- .../bgpio/types/attr/BgpAttrRouterIdV6.java | 29 +- .../bgpio/types/attr/BgpLinkAttrIgpMetric.java | 172 +++ .../types/attr/BgpLinkAttrMplsProtocolMask.java | 152 +++ .../types/attr/BgpLinkAttrProtectionType.java | 240 ++++ .../bgpio/types/attr/BgpPrefixAttrMetric.java | 131 ++ .../bgpio/types/attr/BgpPrefixAttrOspfFwdAddr.java | 187 +++ .../org/onosproject/bgpio/util/Validation.java | 36 +- .../onosproject/bgp/BgpAttrNodeFlagBitTlvTest.java | 51 + .../org/onosproject/bgp/BgpAttrRouterIdV6Test.java | 50 + .../onosproject/bgp/BgpLinkAttrIgpMetricTest.java | 44 + .../bgp/BgpLinkAttrProtectionTypeTest.java | 57 + .../bgp/BgpPrefixAttrOspfFwdAddrTest.java | 52 + .../test/java/org/onosproject/bgp/NextHopTest.java | 41 + .../main/java/org/onosproject/cli/Comparators.java | 5 +- .../cli/net/AddOpticalIntentCommand.java | 8 +- .../org/onosproject/cli/net/FlowsListCommand.java | 10 +- .../org/onosproject/cli/net/GroupsListCommand.java | 4 +- .../resources/OSGI-INF/blueprint/shell-config.xml | 1 - .../onosproject/cluster/ClusterAdminService.java | 3 +- .../cluster/ClusterDefinitionService.java | 47 - .../org/onosproject/cluster/ClusterMetadata.java | 185 +++ .../onosproject/cluster/ClusterMetadataEvent.java | 56 + .../cluster/ClusterMetadataEventListener.java | 24 + .../cluster/ClusterMetadataService.java | 40 + .../onosproject/cluster/ClusterMetadataStore.java | 77 ++ .../cluster/ClusterMetadataStoreDelegate.java | 24 + .../main/java/org/onosproject/cluster/NodeId.java | 7 +- .../java/org/onosproject/cluster/Partition.java | 91 ++ .../onosproject/net/behaviour/BridgeConfig.java | 11 + .../net/behaviour/ExtensionResolver.java | 40 + .../onosproject/net/behaviour/TunnelConfig.java | 9 + .../net/flow/DefaultTrafficSelector.java | 19 +- .../net/flow/DefaultTrafficTreatment.java | 25 +- .../org/onosproject/net/flow/TrafficTreatment.java | 15 +- .../java/org/onosproject/net/flow/Treatment.java | 36 - .../instructions/AbstractExtensionInstruction.java | 71 + .../flow/instructions/ExtensionInstruction.java | 78 ++ .../instructions/ExtensionPropertyException.java | 32 + .../net/flow/instructions/ExtensionType.java | 92 ++ .../net/flow/instructions/Instruction.java | 7 +- .../net/flow/instructions/Instructions.java | 68 + .../flowobjective/DefaultFilteringObjective.java | 16 + .../net/flowobjective/FilteringObjective.java | 66 +- .../onosproject/net/group/DefaultGroupBucket.java | 14 + .../onosproject/net/intent/HostToHostIntent.java | 17 +- .../main/java/org/onosproject/net/intent/Key.java | 15 +- .../net/intent/constraint/BandwidthConstraint.java | 15 +- .../net/newresource/ResourceService.java | 8 + .../onosproject/net/newresource/ResourceStore.java | 8 + .../net/resource/link/BandwidthResource.java | 13 +- .../resource/link/DefaultLinkResourceRequest.java | 104 +- .../net/resource/link/LambdaResourceRequest.java | 36 + .../net/resource/link/LinkResourceRequest.java | 54 +- .../net/resource/link/LinkResourceService.java | 19 + .../resource/link/MplsLabelResourceRequest.java | 36 + .../persistence/PersistenceService.java | 40 + .../persistence/PersistentMapBuilder.java | 49 + .../persistence/PersistentSetBuilder.java | 48 + .../org/onosproject/persistence/package-info.java | 20 + .../store/service/TransactionContext.java | 4 +- .../java/org/onosproject/ui/UiTopoOverlay.java | 8 +- .../onosproject/ui/table/cell/AppIdFormatter.java | 1 + .../java/org/onosproject/ui/topo/NodeBadge.java | 2 +- .../net/intent/HostToHostIntentTest.java | 54 +- .../net/packet/DefaultPacketRequestTest.java | 93 ++ .../onosproject/net/packet/PacketEventTest.java | 51 + .../net/packet/PacketProcessorTest.java | 59 + .../codec/impl/DecodeCriterionCodecHelper.java | 42 +- .../codec/impl/DecodeInstructionCodecHelper.java | 35 +- .../codec/impl/EncodeCriterionCodecHelper.java | 14 +- .../codec/impl/EncodeInstructionCodecHelper.java | 37 + .../onosproject/codec/impl/InstructionCodec.java | 3 + .../onosproject/codec/impl/CriterionCodecTest.java | 33 + .../codec/impl/CriterionJsonMatcher.java | 56 +- .../onosproject/codec/impl/FlowRuleCodecTest.java | 48 +- .../codec/impl/InstructionCodecTest.java | 25 +- .../codec/impl/InstructionJsonMatcher.java | 58 +- .../org/onosproject/codec/impl/criteria-flow.json | 5 +- .../onosproject/cluster/impl/ClusterManager.java | 48 +- .../cluster/impl/ClusterMetadataManager.java | 116 ++ .../net/device/impl/OpticalPortOperator.java | 2 +- .../composition/FlowObjectiveCompositionUtil.java | 24 +- .../impl/compiler/MplsPathIntentCompiler.java | 110 +- .../compiler/OpticalCircuitIntentCompiler.java | 3 +- .../OpticalConnectivityIntentCompiler.java | 108 +- .../net/newresource/impl/ResourceManager.java | 13 +- .../net/resource/impl/LinkResourceManager.java | 98 +- .../intent/impl/compiler/MockResourceService.java | 100 ++ .../impl/compiler/MplsPathIntentCompilerTest.java | 15 +- .../net/proxyarp/impl/ProxyArpManagerTest.java | 395 +++++- framework/src/onos/core/store/dist/pom.xml | 2 +- .../store/cluster/impl/ClusterDefinition.java | 58 - .../cluster/impl/ClusterDefinitionManager.java | 194 --- .../store/cluster/impl/ClusterDefinitionStore.java | 63 - .../cluster/impl/DistributedClusterStore.java | 11 +- .../cluster/impl/StaticClusterMetadataStore.java | 221 ++++ .../messaging/impl/IOLoopMessagingManager.java | 6 +- .../messaging/impl/NettyMessagingManager.java | 7 +- .../store/consistent/impl/DatabaseDefinition.java | 108 -- .../consistent/impl/DatabaseDefinitionStore.java | 74 -- .../store/consistent/impl/DatabaseManager.java | 52 +- .../consistent/impl/DefaultTransactionContext.java | 9 +- .../store/device/impl/GossipDeviceStore.java | 20 +- .../store/ecmap/MapDbPersistentStore.java | 2 +- .../newresource/impl/ConsistentResourceStore.java | 14 +- .../store/intent/impl/PartitionManagerTest.java | 6 + framework/src/onos/core/store/persistence/pom.xml | 66 + .../impl/DefaultPersistentMapBuilder.java | 63 + .../impl/DefaultPersistentSetBuilder.java | 59 + .../persistence/impl/PersistenceException.java | 30 + .../persistence/impl/PersistenceManager.java | 138 ++ .../persistence/impl/PersistentMap.java | 192 +++ .../persistence/impl/PersistentSet.java | 194 +++ .../onosproject/persistence/impl/package-info.java | 20 + .../src/main/test/test/PersistentMapTest.java | 245 ++++ .../src/main/test/test/PersistentSetTest.java | 274 ++++ framework/src/onos/core/store/pom.xml | 3 +- .../ExtensionInstructionSerializer.java | 73 ++ .../store/serializers/KryoNamespaces.java | 13 + framework/src/onos/docs/internal-bgpls | 2 + framework/src/onos/docs/internal-stores | 1 + framework/src/onos/docs/internal.xml | 4 + .../extensions/NiciraExtensionInterpreter.java | 84 ++ .../driver/extensions/NiciraSetTunnelDst.java | 106 ++ .../driver/extensions/package-info.java | 19 + .../driver/ovsdb/OvsdbBridgeConfig.java | 31 +- .../driver/ovsdb/OvsdbTunnelConfig.java | 37 +- .../driver/pipeline/CpqdOFDPA1Pipeline.java | 201 --- .../driver/pipeline/CpqdOFDPA2Pipeline.java | 203 +++ .../driver/pipeline/OFDPA1Pipeline.java | 887 ------------- .../driver/pipeline/OFDPA2Pipeline.java | 1369 ++++++++++++++++++++ .../onosproject/driver/pipeline/SpringOpenTTP.java | 75 +- .../drivers/src/main/resources/onos-drivers.xml | 11 +- framework/src/onos/features/features.xml | 1 + .../incubator/net/intf/package-info.java | 20 + .../java/org/onosproject/netconf/package-info.java | 20 + .../org/onosproject/netconf/ctl/package-info.java | 20 + .../org/onosproject/netconf/rfc/package-info.java | 20 + .../openflow/controller/ExtensionInterpreter.java | 58 + .../onosproject/ovsdb/controller/EventSubject.java | 3 +- .../onosproject/ovsdb/controller/OvsdbBridge.java | 11 +- .../ovsdb/controller/OvsdbBridgeName.java | 7 +- .../ovsdb/controller/OvsdbClientService.java | 16 +- .../ovsdb/controller/OvsdbController.java | 4 +- .../ovsdb/controller/OvsdbDatapathId.java | 9 +- .../ovsdb/controller/OvsdbEventSubject.java | 2 +- .../onosproject/ovsdb/controller/OvsdbIfaceId.java | 9 +- .../onosproject/ovsdb/controller/OvsdbNodeId.java | 2 +- .../onosproject/ovsdb/controller/OvsdbPort.java | 10 +- .../ovsdb/controller/OvsdbPortName.java | 9 +- .../ovsdb/controller/OvsdbPortNumber.java | 9 +- .../ovsdb/controller/OvsdbTableStore.java | 14 +- .../onosproject/ovsdb/controller/OvsdbTunnel.java | 21 +- .../ovsdb/controller/OvsdbTunnelName.java | 9 +- framework/src/onos/pom.xml | 3 +- .../provider/lldp/impl/LLDPLinkProvider.java | 196 +-- .../provider/lldp/impl/LinkDiscovery.java | 12 +- .../provider/lldp/impl/LLDPLinkProviderTest.java | 144 +- .../provider/of/flow/impl/FlowEntryBuilder.java | 65 +- .../provider/of/flow/impl/FlowModBuilder.java | 22 +- .../provider/of/flow/impl/FlowModBuilderVer10.java | 6 +- .../provider/of/flow/impl/FlowModBuilderVer13.java | 36 +- .../flow/impl/NewAdaptiveFlowStatsCollector.java | 26 +- .../of/flow/impl/OpenFlowRuleProvider.java | 22 +- .../of/group/impl/GroupBucketEntryBuilder.java | 4 + .../of/group/impl/OpenFlowGroupProvider.java | 2 +- .../ovsdb/provider/host/OvsdbHostProvider.java | 4 +- framework/src/onos/tools/build/conf/pom.xml | 2 +- .../conf/src/main/resources/onos/checkstyle.xml | 4 +- .../conf/src/main/resources/onos/suppressions.xml | 8 + .../src/onos/tools/dev/bin/onos-build-selective | 8 +- .../tools/dev/bin/onos-build-selective.exclude | 3 +- framework/src/onos/tools/dev/bin/onos-setup-karaf | 12 +- .../src/main/java/AppUiTopovMessageHandler.java | 20 +- .../src/main/java/AppUiTopovOverlay.java | 11 +- framework/src/onos/tools/test/bin/onos-config | 19 +- .../src/onos/tools/test/bin/onos-execute-expect | 27 + .../src/onos/tools/test/bin/onos-gen-partitions | 17 +- framework/src/onos/tools/test/bin/onos-secure-ssh | 3 +- framework/src/onos/tools/test/bin/stc | 4 +- .../onos/tools/test/scenarios/dist-test-seq.xml | 67 + .../src/onos/tools/test/scenarios/dist-test.xml | 70 + .../src/onos/tools/test/topos/opticalUtils.py | 10 +- .../src/main/java/org/onlab/packet/Ethernet.java | 131 +- .../src/main/java/org/onlab/util/Bandwidth.java | 11 + .../src/main/java/org/onlab/util/DataRateUnit.java | 64 + .../org/onlab/util/AbstractAccumulatorTest.java | 27 +- .../org/onlab/util/ManuallyAdvancingTimer.java | 26 +- .../org/onlab/util/ManuallyAdvancingTimerTest.java | 4 +- .../stc/src/main/java/org/onlab/stc/Main.java | 24 +- .../rest/resources/ClusterWebResource.java | 3 +- .../ui/impl/TopologyViewMessageHandler.java | 58 +- .../org/onosproject/ui/impl/TrafficOverlay.java | 3 +- .../web/gui/src/main/webapp/app/fw/layer/panel.css | 4 + .../web/gui/src/main/webapp/app/fw/layer/panel.js | 6 +- .../web/gui/src/main/webapp/app/fw/svg/icon.js | 2 + .../gui/src/main/webapp/app/fw/widget/table.css | 2 +- .../src/main/webapp/app/fw/widget/tableBuilder.js | 4 +- .../gui/src/main/webapp/app/view/intent/intent.css | 1 - .../src/main/webapp/app/view/intent/intent.html | 31 +- .../gui/src/main/webapp/app/view/intent/intent.js | 39 +- .../web/gui/src/main/webapp/app/view/topo/topo.css | 51 + .../web/gui/src/main/webapp/app/view/topo/topo.js | 20 +- .../gui/src/main/webapp/app/view/topo/topoD3.js | 60 +- .../src/main/webapp/app/view/topo/topoDialog.js | 183 +++ .../gui/src/main/webapp/app/view/topo/topoEvent.js | 2 + .../gui/src/main/webapp/app/view/topo/topoForce.js | 8 +- .../src/main/webapp/app/view/topo/topoOverlay.js | 7 +- .../src/main/webapp/app/view/topo/topoSelect.js | 30 +- .../src/main/webapp/app/view/topo/topoToolbar.js | 1 + .../src/main/webapp/app/view/topo/topoTraffic.js | 9 + .../src/onos/web/gui/src/main/webapp/index.html | 1 + .../ev/badges/ev_10_showHighlights_stuff.json | 63 + .../ev/badges/ev_11_showHighlights_clear.json | 8 + .../test/_karma/ev/badges/ev_4_addDevice_s3.json | 18 + .../test/_karma/ev/badges/ev_4_addLink_1_2.json | 16 - .../test/_karma/ev/badges/ev_5_addDevice_s4.json | 18 + .../ev/badges/ev_5_showHighlights_clear.json | 8 - .../test/_karma/ev/badges/ev_6_addDevice_s5.json | 18 + .../ev/badges/ev_6_showHighlights_stuff.json | 30 - .../test/_karma/ev/badges/ev_7_addDevice_s6.json | 18 + .../ev/badges/ev_7_showHighlights_clear.json | 8 - .../test/_karma/ev/badges/ev_8_addLink_1_2.json | 16 + .../ev/badges/ev_9_showHighlights_clear.json | 8 + .../gui/src/test/_karma/ev/badges/scenario.json | 2 +- 416 files changed, 21681 insertions(+), 6724 deletions(-) create mode 100644 framework/src/onos/apps/dhcp/api/pom.xml create mode 100644 framework/src/onos/apps/dhcp/api/src/main/java/org/onosproject/dhcp/DhcpService.java create mode 100644 framework/src/onos/apps/dhcp/api/src/main/java/org/onosproject/dhcp/DhcpStore.java create mode 100644 framework/src/onos/apps/dhcp/api/src/main/java/org/onosproject/dhcp/IpAssignment.java create mode 100644 framework/src/onos/apps/dhcp/api/src/main/java/org/onosproject/dhcp/package-info.java create mode 100644 framework/src/onos/apps/dhcp/api/src/test/java/org/onosproject/dhcp/IpAssignmentTest.java create mode 100644 framework/src/onos/apps/dhcp/app/app.xml create mode 100644 framework/src/onos/apps/dhcp/app/features.xml create mode 100644 framework/src/onos/apps/dhcp/app/pom.xml create mode 100644 framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/DhcpLeaseDetails.java create mode 100644 framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/DhcpListAllMappings.java create mode 100644 framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/DhcpRemoveStaticMapping.java create mode 100644 framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/DhcpSetStaticMapping.java create mode 100644 framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/FreeIpCompleter.java create mode 100644 framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/MacIdCompleter.java create mode 100644 framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/package-info.java create mode 100644 framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DhcpConfig.java create mode 100644 framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DhcpManager.java create mode 100644 framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DhcpUi.java create mode 100644 framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DhcpViewMessageHandler.java create mode 100644 framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DistributedDhcpStore.java create mode 100644 framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/package-info.java create mode 100644 framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/rest/DHCPWebResource.java create mode 100644 framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/rest/package-info.java create mode 100644 framework/src/onos/apps/dhcp/app/src/main/resources/OSGI-INF/blueprint/shell-config.xml create mode 100644 framework/src/onos/apps/dhcp/app/src/main/resources/app/view/dhcp/dhcp.css create mode 100644 framework/src/onos/apps/dhcp/app/src/main/resources/app/view/dhcp/dhcp.html create mode 100644 framework/src/onos/apps/dhcp/app/src/main/resources/app/view/dhcp/dhcp.js create mode 100644 framework/src/onos/apps/dhcp/app/src/main/resources/gui/css.html create mode 100644 framework/src/onos/apps/dhcp/app/src/main/resources/gui/js.html create mode 100644 framework/src/onos/apps/dhcp/app/src/main/webapp/WEB-INF/web.xml create mode 100644 framework/src/onos/apps/dhcp/app/src/test/java/org/onosproject/dhcp/impl/DhcpManagerTest.java create mode 100644 framework/src/onos/apps/dhcp/app/src/test/resources/dhcp-cfg.json delete mode 100644 framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/DhcpService.java delete mode 100644 framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/DhcpStore.java delete mode 100644 framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/IpAssignment.java delete mode 100644 framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpLeaseDetails.java delete mode 100644 framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpListAllMappings.java delete mode 100644 framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpRemoveStaticMapping.java delete mode 100644 framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpSetStaticMapping.java delete mode 100644 framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/FreeIpCompleter.java delete mode 100644 framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/MacIdCompleter.java delete mode 100644 framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/package-info.java delete mode 100644 framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpConfig.java delete mode 100644 framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpManager.java delete mode 100644 framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpUi.java delete mode 100644 framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpViewMessageHandler.java delete mode 100644 framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DistributedDhcpStore.java delete mode 100644 framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/package-info.java delete mode 100644 framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/package-info.java delete mode 100644 framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/rest/DHCPWebResource.java delete mode 100644 framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/rest/package-info.java delete mode 100644 framework/src/onos/apps/dhcp/src/main/resources/OSGI-INF/blueprint/shell-config.xml delete mode 100644 framework/src/onos/apps/dhcp/src/main/resources/app/view/dhcp/dhcp.css delete mode 100644 framework/src/onos/apps/dhcp/src/main/resources/app/view/dhcp/dhcp.html delete mode 100644 framework/src/onos/apps/dhcp/src/main/resources/app/view/dhcp/dhcp.js delete mode 100644 framework/src/onos/apps/dhcp/src/main/resources/gui/css.html delete mode 100644 framework/src/onos/apps/dhcp/src/main/resources/gui/js.html delete mode 100644 framework/src/onos/apps/dhcp/src/main/webapp/WEB-INF/web.xml delete mode 100644 framework/src/onos/apps/dhcp/src/test/java/org/onosproject/dhcp/IpAssignmentTest.java delete mode 100644 framework/src/onos/apps/dhcp/src/test/java/org/onosproject/dhcp/impl/DhcpManagerTest.java delete mode 100644 framework/src/onos/apps/dhcp/src/test/resources/dhcp-cfg.json create mode 100644 framework/src/onos/apps/igmp/src/main/java/org/onosproject/igmp/impl/package-info.java create mode 100644 framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/rest/package-info.java create mode 100644 framework/src/onos/apps/mlb/src/main/java/org/onosproject/mlb/package-info.java create mode 100644 framework/src/onos/apps/openstackswitching/pom.xml create mode 100644 framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackArpHandler.java create mode 100644 framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackDhcpHandler.java create mode 100644 framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackNetwork.java create mode 100644 framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackPort.java create mode 100644 framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingManager.java create mode 100644 framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingRulePopulator.java create mode 100644 framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingService.java create mode 100644 framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/package-info.java create mode 100644 framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackNetworkCodec.java create mode 100644 framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackNetworkWebResource.java create mode 100644 framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackPortCodec.java create mode 100644 framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackPortWebResource.java create mode 100644 framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/package-info.java create mode 100644 framework/src/onos/apps/openstackswitching/src/main/webapp/WEB-INF/web.xml create mode 100644 framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SubnetAssignedVidStoreKey.java create mode 100644 framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/SubnetNextObjectiveStoreKey.java create mode 100644 framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/ConnectPointConfiguration.java create mode 100644 framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/SfcService.java create mode 100644 framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/impl/SfcManager.java create mode 100644 framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/impl/package-info.java create mode 100644 framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/package-info.java create mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultFlowClassifier.java create mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultPortChain.java create mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultPortPair.java create mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultPortPairGroup.java create mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/FlowClassifier.java create mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/FlowClassifierId.java create mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortChain.java create mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortChainId.java create mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPair.java create mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPairGroup.java create mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPairGroupId.java create mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPairId.java create mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/FlowClassifierService.java create mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/impl/FlowClassifierManager.java create mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/impl/package-info.java create mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/package-info.java create mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portchain/PortChainService.java create mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portchain/package-info.java create mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portpairgroup/PortPairGroupService.java create mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portpairgroup/package-info.java delete mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/tunnel/TunnelConfigService.java delete mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/tunnel/package-info.java delete mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/AllocationPoolsCodec.java delete mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/AllowedAddressPairCodec.java delete mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/FixedIpCodec.java create mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/FlowClassifierCodec.java delete mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/HostRoutesCodec.java delete mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/SecurityGroupCodec.java delete mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/SubnetCodec.java delete mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/TenantNetworkCodec.java delete mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/VirtualPortCodec.java create mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/flowclassifier/FlowClassifierIdTest.java create mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/subnet/DefaultAllocationPoolTest.java create mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/subnet/DefaultHostRouteTest.java create mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/subnet/SubnetIdTest.java create mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/DefaultNeutronNetworkTest.java create mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/PhysicalNetworkTest.java create mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/SegmentationIdTest.java create mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/TenantIdTest.java create mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/TenantNetworkIdTest.java create mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/AllowedAddressPairTest.java create mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/DefaultVirtualPortTest.java create mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/FixedIpTest.java create mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/SecurityGroupTest.java create mode 100644 framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/VirtualPortIdTest.java create mode 100644 framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/FlowClassifierWebResource.java create mode 100644 framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/AllocationPoolsCodec.java create mode 100644 framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/AllowedAddressPairCodec.java create mode 100644 framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/FixedIpCodec.java create mode 100644 framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/HostRoutesCodec.java create mode 100644 framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/PortChainCodec.java create mode 100644 framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/SecurityGroupCodec.java create mode 100644 framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/SubnetCodec.java create mode 100644 framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/TenantNetworkCodec.java create mode 100644 framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/VirtualPortCodec.java create mode 100644 framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/package-info.java create mode 100755 framework/src/onos/bgp/api/src/main/java/org/onosproject/bgp/controller/BgpPeerManager.java create mode 100755 framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPFactories.java create mode 100755 framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPFactory.java create mode 100755 framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPFactoryVer4.java create mode 100755 framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPMessageVer4.java create mode 100644 framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BgpPathAttributes.java create mode 100644 framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/As4Path.java create mode 100644 framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/AsPath.java create mode 100644 framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/LocalPref.java create mode 100644 framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/Med.java create mode 100644 framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/NextHop.java create mode 100644 framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/Origin.java create mode 100755 framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpLinkAttrIgpMetric.java create mode 100755 framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpLinkAttrMplsProtocolMask.java create mode 100755 framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpLinkAttrProtectionType.java create mode 100755 framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpPrefixAttrMetric.java create mode 100755 framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpPrefixAttrOspfFwdAddr.java create mode 100644 framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpAttrNodeFlagBitTlvTest.java create mode 100644 framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpAttrRouterIdV6Test.java create mode 100644 framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpLinkAttrIgpMetricTest.java create mode 100644 framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpLinkAttrProtectionTypeTest.java create mode 100644 framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpPrefixAttrOspfFwdAddrTest.java create mode 100755 framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/NextHopTest.java delete mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterDefinitionService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadata.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataEvent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataEventListener.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataStore.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataStoreDelegate.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/cluster/Partition.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ExtensionResolver.java delete mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/Treatment.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/AbstractExtensionInstruction.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionInstruction.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionPropertyException.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionType.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/persistence/PersistenceService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/persistence/PersistentMapBuilder.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/persistence/PersistentSetBuilder.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/persistence/package-info.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/DefaultPacketRequestTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/PacketEventTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/PacketProcessorTest.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/cluster/impl/ClusterMetadataManager.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MockResourceService.java delete mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/ClusterDefinition.java delete mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/ClusterDefinitionManager.java delete mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/ClusterDefinitionStore.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/StaticClusterMetadataStore.java delete mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseDefinition.java delete mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseDefinitionStore.java create mode 100644 framework/src/onos/core/store/persistence/pom.xml create mode 100644 framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/DefaultPersistentMapBuilder.java create mode 100644 framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/DefaultPersistentSetBuilder.java create mode 100644 framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistenceException.java create mode 100644 framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistenceManager.java create mode 100644 framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistentMap.java create mode 100644 framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistentSet.java create mode 100644 framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/package-info.java create mode 100644 framework/src/onos/core/store/persistence/src/main/test/test/PersistentMapTest.java create mode 100644 framework/src/onos/core/store/persistence/src/main/test/test/PersistentSetTest.java create mode 100644 framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/ExtensionInstructionSerializer.java create mode 100644 framework/src/onos/docs/internal-bgpls create mode 100644 framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraExtensionInterpreter.java create mode 100644 framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraSetTunnelDst.java create mode 100644 framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/package-info.java delete mode 100644 framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA1Pipeline.java create mode 100644 framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA2Pipeline.java delete mode 100644 framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA1Pipeline.java create mode 100644 framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA2Pipeline.java create mode 100644 framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/intf/package-info.java create mode 100644 framework/src/onos/netconf/api/src/main/java/org/onosproject/netconf/package-info.java create mode 100644 framework/src/onos/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/package-info.java create mode 100644 framework/src/onos/netconf/rfc/src/main/java/org/onosproject/netconf/rfc/package-info.java create mode 100644 framework/src/onos/openflow/api/src/main/java/org/onosproject/openflow/controller/ExtensionInterpreter.java create mode 100755 framework/src/onos/tools/test/bin/onos-execute-expect create mode 100644 framework/src/onos/tools/test/scenarios/dist-test-seq.xml create mode 100644 framework/src/onos/tools/test/scenarios/dist-test.xml create mode 100644 framework/src/onos/utils/misc/src/main/java/org/onlab/util/DataRateUnit.java create mode 100644 framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoDialog.js create mode 100644 framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_10_showHighlights_stuff.json create mode 100644 framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_11_showHighlights_clear.json create mode 100644 framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_4_addDevice_s3.json delete mode 100644 framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_4_addLink_1_2.json create mode 100644 framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_5_addDevice_s4.json delete mode 100644 framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_5_showHighlights_clear.json create mode 100644 framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_6_addDevice_s5.json delete mode 100644 framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_6_showHighlights_stuff.json create mode 100644 framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_7_addDevice_s6.json delete mode 100644 framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_7_showHighlights_clear.json create mode 100644 framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_8_addLink_1_2.json create mode 100644 framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_9_showHighlights_clear.json (limited to 'framework') 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 72a5b122..567944a6 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 @@ -419,6 +419,7 @@ public class AAA { * Handles RADIUS packets. * * @param radiusPacket RADIUS packet coming from the RADIUS server. + * @throws StateMachineException if an illegal state transition is triggered */ protected void handleRadiusPacket(RADIUS radiusPacket) throws StateMachineException { StateMachine stateMachine = StateMachine.lookupStateMachineById(radiusPacket.getIdentifier()); 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 4b28a14b..e15bc763 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 @@ -23,17 +23,27 @@ import org.apache.felix.scr.annotations.Deactivate; import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.ReferenceCardinality; import org.apache.felix.scr.annotations.Service; +import org.onlab.util.ItemNotFoundException; import org.onlab.util.KryoNamespace; import org.onosproject.cluster.ClusterService; import org.onosproject.core.ApplicationId; import org.onosproject.core.CoreService; +import org.onosproject.net.DefaultAnnotations; import org.onosproject.net.Device; import org.onosproject.net.DeviceId; import org.onosproject.net.Host; +import org.onosproject.net.behaviour.BridgeConfig; +import org.onosproject.net.behaviour.BridgeName; import org.onosproject.net.behaviour.ControllerInfo; +import org.onosproject.net.behaviour.DefaultTunnelDescription; +import org.onosproject.net.behaviour.TunnelConfig; +import org.onosproject.net.behaviour.TunnelDescription; +import org.onosproject.net.behaviour.TunnelName; import org.onosproject.net.device.DeviceEvent; import org.onosproject.net.device.DeviceListener; import org.onosproject.net.device.DeviceService; +import org.onosproject.net.driver.DriverHandler; +import org.onosproject.net.driver.DriverService; import org.onosproject.net.host.HostEvent; import org.onosproject.net.host.HostListener; import org.onosproject.net.host.HostService; @@ -58,6 +68,7 @@ import java.util.concurrent.Executors; import static com.google.common.base.Preconditions.checkNotNull; import static org.onlab.util.Tools.groupedThreads; import static org.onosproject.net.Device.Type.SWITCH; +import static org.onosproject.net.behaviour.TunnelDescription.Type.VXLAN; import static org.slf4j.LoggerFactory.getLogger; /** @@ -79,7 +90,6 @@ public class CordVtn implements CordVtnService { private static final Map DEFAULT_TUNNEL_OPTIONS = new HashMap() { { put("key", "flow"); - put("local_ip", "flow"); put("remote_ip", "flow"); } }; @@ -98,6 +108,9 @@ public class CordVtn implements CordVtnService { @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected HostService hostService; + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected DriverService driverService; + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected OvsdbController controller; @@ -213,8 +226,8 @@ public class CordVtn implements CordVtnService { if (deviceService.getDevice(ovsdb.intBrId()) == null || !deviceService.isAvailable(ovsdb.intBrId())) { createIntegrationBridge(ovsdb); - } else if (!checkVxlanPort(ovsdb)) { - createVxlanPort(ovsdb); + } else if (!checkVxlanInterface(ovsdb)) { + createVxlanInterface(ovsdb); } } @@ -272,26 +285,41 @@ public class CordVtn implements CordVtnService { }); String dpid = ovsdb.intBrId().toString().substring(DPID_BEGIN); - // TODO change to use bridge config - OvsdbClientService ovsdbClient = getOvsdbClient(ovsdb); - ovsdbClient.createBridge(DEFAULT_BRIDGE_NAME, dpid, controllers); + try { + DriverHandler handler = driverService.createHandler(ovsdb.deviceId()); + BridgeConfig bridgeConfig = handler.behaviour(BridgeConfig.class); + bridgeConfig.addBridge(BridgeName.bridgeName(DEFAULT_BRIDGE_NAME), dpid, controllers); + } catch (ItemNotFoundException e) { + log.warn("Failed to create integration bridge on {}", ovsdb.deviceId()); + } } - private void createVxlanPort(OvsdbNode ovsdb) { - // TODO change to use tunnel config and tunnel description - OvsdbClientService ovsdbClient = getOvsdbClient(ovsdb); - ovsdbClient.createTunnel(DEFAULT_BRIDGE_NAME, DEFAULT_TUNNEL, - DEFAULT_TUNNEL, DEFAULT_TUNNEL_OPTIONS); + private void createVxlanInterface(OvsdbNode ovsdb) { + DefaultAnnotations.Builder optionBuilder = DefaultAnnotations.builder(); + for (String key : DEFAULT_TUNNEL_OPTIONS.keySet()) { + optionBuilder.set(key, DEFAULT_TUNNEL_OPTIONS.get(key)); + } + TunnelDescription description = + new DefaultTunnelDescription(null, null, VXLAN, + TunnelName.tunnelName(DEFAULT_TUNNEL), + optionBuilder.build()); + try { + DriverHandler handler = driverService.createHandler(ovsdb.deviceId()); + TunnelConfig tunnelConfig = handler.behaviour(TunnelConfig.class); + tunnelConfig.createTunnelInterface(BridgeName.bridgeName(DEFAULT_BRIDGE_NAME), description); + } catch (ItemNotFoundException e) { + log.warn("Failed to create VXLAN interface on {}", ovsdb.deviceId()); + } } - private boolean checkVxlanPort(OvsdbNode ovsdb) { - // TODO change to use tunnel config - OvsdbClientService ovsdbClient = getOvsdbClient(ovsdb); + private boolean checkVxlanInterface(OvsdbNode ovsdb) { try { - ovsdbClient.getPorts().stream() - .filter(p -> p.portName().value().equals(DEFAULT_TUNNEL)) - .findFirst().get(); - } catch (NoSuchElementException e) { + DriverHandler handler = driverService.createHandler(ovsdb.deviceId()); + BridgeConfig bridgeConfig = handler.behaviour(BridgeConfig.class); + bridgeConfig.getPorts().stream() + .filter(p -> p.annotations().value("portName").equals(DEFAULT_TUNNEL)) + .findAny().get(); + } catch (ItemNotFoundException | NoSuchElementException e) { return false; } return true; @@ -374,8 +402,8 @@ public class CordVtn implements CordVtnService { return; } - if (!checkVxlanPort(ovsdb)) { - createVxlanPort(ovsdb); + if (!checkVxlanInterface(ovsdb)) { + createVxlanInterface(ovsdb); } } 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 index 287f2a34..274ca9b4 100644 --- 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 @@ -72,8 +72,6 @@ public class CordVtnConfigManager { configService.addListener(configListener); configRegistry.registerConfigFactory(configFactory); - - readConfiguration(); } @Deactivate @@ -101,7 +99,22 @@ public class CordVtnConfigManager { @Override public void event(NetworkConfigEvent event) { - // TODO handle update event + if (!event.configClass().equals(CordVtnConfig.class)) { + return; + } + + switch (event.type()) { + case CONFIG_ADDED: + log.info("Network configuration added"); + readConfiguration(); + break; + case CONFIG_UPDATED: + log.info("Network configuration updated"); + readConfiguration(); + break; + default: + break; + } } } } 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 eba52108..46f6e29c 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 @@ -61,7 +61,7 @@ public class DefaultOvsdbNode implements OvsdbNode { @Override public DeviceId deviceId() { - return DeviceId.deviceId("ovsdb:" + this.ip.toString() + ":" + this.port.toString()); + return DeviceId.deviceId("ovsdb:" + this.ip.toString()); } @Override diff --git a/framework/src/onos/apps/dhcp/api/pom.xml b/framework/src/onos/apps/dhcp/api/pom.xml new file mode 100644 index 00000000..fb5246f7 --- /dev/null +++ b/framework/src/onos/apps/dhcp/api/pom.xml @@ -0,0 +1,64 @@ + + + + 4.0.0 + + + onos-dhcp + org.onosproject + 1.4.0-SNAPSHOT + ../pom.xml + + + onos-app-dhcp-api + bundle + + http://onosproject.org + + DHCP Server application API + + + + org.onosproject + onlab-junit + test + + + org.onosproject + onos-core-serializers + ${project.version} + + + + org.onosproject + onos-incubator-api + ${project.version} + + + org.onosproject + onos-api + ${project.version} + tests + test + + + + + + diff --git a/framework/src/onos/apps/dhcp/api/src/main/java/org/onosproject/dhcp/DhcpService.java b/framework/src/onos/apps/dhcp/api/src/main/java/org/onosproject/dhcp/DhcpService.java new file mode 100644 index 00000000..7c2127f9 --- /dev/null +++ b/framework/src/onos/apps/dhcp/api/src/main/java/org/onosproject/dhcp/DhcpService.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.dhcp; + +import org.onlab.packet.Ip4Address; +import org.onlab.packet.MacAddress; +import org.onosproject.net.HostId; + +import java.util.Map; + +/** + * DHCP Service Interface. + */ +public interface DhcpService { + + /** + * Returns a collection of all the MacAddress to IPAddress mapping. + * + * @return collection of mappings. + */ + Map listMapping(); + + /** + * Returns the default lease time granted by the DHCP Server. + * + * @return lease time + */ + int getLeaseTime(); + + /** + * Returns the default renewal time granted by the DHCP Server. + * + * @return renewal time + */ + int getRenewalTime(); + + /** + * Returns the default rebinding time granted by the DHCP Server. + * + * @return rebinding time + */ + int getRebindingTime(); + + /** + * Registers a static IP mapping with the DHCP Server. + * + * @param macID macID of the client + * @param ipAddress IP Address requested for the client + * @return true if the mapping was successfully registered, false otherwise + */ + boolean setStaticMapping(MacAddress macID, Ip4Address ipAddress); + + /** + * Removes a static IP mapping with the DHCP Server. + * + * @param macID macID of the client + * @return true if the mapping was successfully removed, false otherwise + */ + boolean removeStaticMapping(MacAddress macID); + + /** + * Returns the list of all the available IPs with the server. + * + * @return list of available IPs + */ + Iterable getAvailableIPs(); + +} diff --git a/framework/src/onos/apps/dhcp/api/src/main/java/org/onosproject/dhcp/DhcpStore.java b/framework/src/onos/apps/dhcp/api/src/main/java/org/onosproject/dhcp/DhcpStore.java new file mode 100644 index 00000000..e263b3a2 --- /dev/null +++ b/framework/src/onos/apps/dhcp/api/src/main/java/org/onosproject/dhcp/DhcpStore.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.dhcp; + +import org.onlab.packet.Ip4Address; +import org.onlab.packet.MacAddress; +import org.onosproject.net.HostId; + +import java.util.Map; + +/** + * DHCPStore Interface. + */ +public interface DhcpStore { + + /** + * Appends all the IPs in a given range to the free pool of IPs. + * + * @param startIP Start IP for the range + * @param endIP End IP for the range + */ + void populateIPPoolfromRange(Ip4Address startIP, Ip4Address endIP); + + /** + * Returns an IP Address for a Mac ID, in response to a DHCP DISCOVER message. + * + * @param hostId Host ID of the client requesting an IP + * @param requestedIP requested IP address + * @return IP address assigned to the Mac ID + */ + Ip4Address suggestIP(HostId hostId, Ip4Address requestedIP); + + /** + * Assigns the requested IP to the Mac ID, in response to a DHCP REQUEST message. + * + * @param hostId Host Id of the client requesting an IP + * @param ipAddr IP Address being requested + * @param leaseTime Lease time offered by the server for this mapping + * @return returns true if the assignment was successful, false otherwise + */ + boolean assignIP(HostId hostId, Ip4Address ipAddr, int leaseTime); + + /** + * Sets the default time for which suggested IP mappings are valid. + * + * @param timeInSeconds default time for IP mappings to be valid + */ + void setDefaultTimeoutForPurge(int timeInSeconds); + + /** + * Releases the IP assigned to a Mac ID into the free pool. + * + * @param hostId the host ID for which the mapping needs to be changed + * @return released ip + */ + Ip4Address releaseIP(HostId hostId); + + /** + * Returns a collection of all the MacAddress to IPAddress mapping assigned to the hosts. + * + * @return the collection of the mappings + */ + Map listAssignedMapping(); + + /** + * Returns a collection of all the MacAddress to IPAddress mapping. + * + * @return the collection of the mappings + */ + Map listAllMapping(); + + /** + * Assigns the requested IP to the MAC ID (if available) for an indefinite period of time. + * + * @param macID macID of the client + * @param ipAddr IP Address requested for the client + * @return true if the mapping was successfully registered, false otherwise + */ + boolean assignStaticIP(MacAddress macID, Ip4Address ipAddr); + + /** + * Removes a static IP mapping associated with the given MAC ID from the DHCP Server. + * + * @param macID macID of the client + * @return true if the mapping was successfully registered, false otherwise + */ + boolean removeStaticIP(MacAddress macID); + + /** + * Returns the list of all the available IPs with the server. + * + * @return list of available IPs + */ + Iterable getAvailableIPs(); + +} diff --git a/framework/src/onos/apps/dhcp/api/src/main/java/org/onosproject/dhcp/IpAssignment.java b/framework/src/onos/apps/dhcp/api/src/main/java/org/onosproject/dhcp/IpAssignment.java new file mode 100644 index 00000000..9b3aa686 --- /dev/null +++ b/framework/src/onos/apps/dhcp/api/src/main/java/org/onosproject/dhcp/IpAssignment.java @@ -0,0 +1,215 @@ +/* + * 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.dhcp; + +import com.google.common.base.MoreObjects; +import org.onlab.packet.Ip4Address; + +import java.util.Date; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Stores the MAC ID to IP Address mapping details. + */ +public final class IpAssignment { + + private final Ip4Address ipAddress; + + private final Date timestamp; + + private final long leasePeriod; + + private final AssignmentStatus assignmentStatus; + + public enum AssignmentStatus { + /** + * IP has been requested by a host, but not assigned to it yet. + */ + Option_Requested, + + /** + * IP has been assigned to a host. + */ + Option_Assigned, + + /** + * IP mapping is no longer active. + */ + Option_Expired + } + + /** + * Constructor for IPAssignment, where the ipAddress, the lease period, the timestamp + * and assignment status is supplied. + * + * @param ipAddress + * @param leasePeriod + * @param assignmentStatus + */ + private IpAssignment(Ip4Address ipAddress, + long leasePeriod, + Date timestamp, + AssignmentStatus assignmentStatus) { + this.ipAddress = ipAddress; + this.leasePeriod = leasePeriod; + this.timestamp = timestamp; + this.assignmentStatus = assignmentStatus; + } + + /** + * Returns the IP Address of the IP assignment. + * + * @return the IP address + */ + public Ip4Address ipAddress() { + return this.ipAddress; + } + + /** + * Returns the timestamp of the IP assignment. + * + * @return the timestamp + */ + public Date timestamp() { + return this.timestamp; + } + + /** + * Returns the assignment status of the IP assignment. + * + * @return the assignment status + */ + public AssignmentStatus assignmentStatus() { + return this.assignmentStatus; + } + + /** + * Returns the lease period of the IP assignment. + * + * @return the lease period in seconds + */ + public int leasePeriod() { + return (int) this.leasePeriod; + } + + /** + * Returns the lease period of the IP assignment. + * + * @return the lease period in milliseconds + */ + public int leasePeriodMs() { + return (int) this.leasePeriod * 1000; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("ip", ipAddress) + .add("timestamp", timestamp) + .add("lease", leasePeriod) + .add("assignmentStatus", assignmentStatus) + .toString(); + } + + /** + * Creates and returns a new builder instance. + * + * @return new builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Creates and returns a new builder instance that clones an existing IPAssignment. + * + * @param assignment ip address assignment + * @return new builder + */ + public static Builder builder(IpAssignment assignment) { + return new Builder(assignment); + } + + /** + * IPAssignment Builder. + */ + public static final class Builder { + + private Ip4Address ipAddress; + + private Date timeStamp; + + private long leasePeriod; + + private AssignmentStatus assignmentStatus; + + private Builder() { + + } + + private Builder(IpAssignment ipAssignment) { + ipAddress = ipAssignment.ipAddress(); + timeStamp = ipAssignment.timestamp(); + leasePeriod = ipAssignment.leasePeriod(); + assignmentStatus = ipAssignment.assignmentStatus(); + } + + public IpAssignment build() { + validateInputs(); + return new IpAssignment(ipAddress, + leasePeriod, + timeStamp, + assignmentStatus); + } + + public Builder ipAddress(Ip4Address addr) { + ipAddress = addr; + return this; + } + + public Builder timestamp(Date timestamp) { + timeStamp = timestamp; + return this; + } + + public Builder leasePeriod(int leasePeriodinSeconds) { + leasePeriod = leasePeriodinSeconds; + return this; + } + + public Builder assignmentStatus(AssignmentStatus status) { + assignmentStatus = status; + return this; + } + + private void validateInputs() { + checkNotNull(ipAddress, "IP Address must be specified"); + checkNotNull(assignmentStatus, "Assignment Status must be specified"); + checkNotNull(leasePeriod, "Lease Period must be specified"); + checkNotNull(timeStamp, "Timestamp must be specified"); + + switch (assignmentStatus) { + case Option_Requested: + case Option_Assigned: + case Option_Expired: + break; + default: + throw new IllegalStateException("Unknown assignment status"); + } + } + } +} diff --git a/framework/src/onos/apps/dhcp/api/src/main/java/org/onosproject/dhcp/package-info.java b/framework/src/onos/apps/dhcp/api/src/main/java/org/onosproject/dhcp/package-info.java new file mode 100644 index 00000000..56778a35 --- /dev/null +++ b/framework/src/onos/apps/dhcp/api/src/main/java/org/onosproject/dhcp/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. + */ + +/** + * Sample application that assigns and manages DHCP leases. + */ +package org.onosproject.dhcp; \ No newline at end of file diff --git a/framework/src/onos/apps/dhcp/api/src/test/java/org/onosproject/dhcp/IpAssignmentTest.java b/framework/src/onos/apps/dhcp/api/src/test/java/org/onosproject/dhcp/IpAssignmentTest.java new file mode 100644 index 00000000..3ecc5cfa --- /dev/null +++ b/framework/src/onos/apps/dhcp/api/src/test/java/org/onosproject/dhcp/IpAssignmentTest.java @@ -0,0 +1,100 @@ +/* + * 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.dhcp; + +import com.google.common.testing.EqualsTester; +import org.junit.Assert; +import org.junit.Test; +import org.onlab.packet.Ip4Address; + +import java.util.Date; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.fail; + +/** + * Unit Tests for IPAssignment class. + */ +public class IpAssignmentTest { + + private final Date dateNow = new Date(); + + private final IpAssignment stats1 = IpAssignment.builder() + .ipAddress(Ip4Address.valueOf("10.10.10.10")) + .leasePeriod(300) + .assignmentStatus(IpAssignment.AssignmentStatus.Option_Expired) + .timestamp(dateNow) + .build(); + + private final IpAssignment stats2 = IpAssignment.builder() + .ipAddress(Ip4Address.valueOf("10.10.10.10")) + .leasePeriod(300) + .assignmentStatus(IpAssignment.AssignmentStatus.Option_Assigned) + .timestamp(dateNow) + .build(); + + private final IpAssignment stats3 = IpAssignment.builder(stats1) + .build(); + + /** + * Tests the constructor for the class. + */ + @Test + public void testConstruction() { + assertThat(stats3.ipAddress(), is(Ip4Address.valueOf("10.10.10.10"))); + assertThat(stats3.timestamp(), is(dateNow)); + assertThat(stats3.leasePeriod(), is(300)); + assertThat(stats3.assignmentStatus(), is(IpAssignment.AssignmentStatus.Option_Expired)); + } + + /** + * Tests the equality and inequality of objects using Guava EqualsTester. + */ + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup(stats1, stats1) + .addEqualityGroup(stats2) + .testEquals(); + } + + /** + * Tests if the toString method returns a consistent value for hashing. + */ + @Test + public void testToString() { + assertThat(stats1.toString(), is(stats1.toString())); + } + + /** + * Tests if the validateInputs method returns an exception for malformed object. + */ + @Test + public void testValidateInputs() { + try { + IpAssignment stats4 = IpAssignment.builder() + .ipAddress(Ip4Address.valueOf("10.10.10.10")) + .leasePeriod(300) + .build(); + + fail("Construction of a malformed IPAssignment did not throw an exception"); + } catch (NullPointerException e) { + Assert.assertThat(e.getMessage(), containsString("must be specified")); + } + } +} diff --git a/framework/src/onos/apps/dhcp/app/app.xml b/framework/src/onos/apps/dhcp/app/app.xml new file mode 100644 index 00000000..bf324b19 --- /dev/null +++ b/framework/src/onos/apps/dhcp/app/app.xml @@ -0,0 +1,23 @@ + + + + ${project.description} + mvn:${project.groupId}/${project.artifactId}/${project.version} + mvn:${project.groupId}/onos-app-dhcp-api/${project.version} + diff --git a/framework/src/onos/apps/dhcp/app/features.xml b/framework/src/onos/apps/dhcp/app/features.xml new file mode 100644 index 00000000..0b277dea --- /dev/null +++ b/framework/src/onos/apps/dhcp/app/features.xml @@ -0,0 +1,25 @@ + + + + mvn:${project.groupId}/${project.artifactId}/${project.version}/xml/features + + onos-api + mvn:${project.groupId}/onos-app-dhcp-api/${project.version} + mvn:${project.groupId}/onos-app-dhcp/${project.version} + + diff --git a/framework/src/onos/apps/dhcp/app/pom.xml b/framework/src/onos/apps/dhcp/app/pom.xml new file mode 100644 index 00000000..6589402a --- /dev/null +++ b/framework/src/onos/apps/dhcp/app/pom.xml @@ -0,0 +1,166 @@ + + + 4.0.0 + + + onos-dhcp + org.onosproject + 1.4.0-SNAPSHOT + ../pom.xml + + + onos-app-dhcp + bundle + + http://onosproject.org + + DHCP Server application + + + org.onosproject.dhcp + /onos/dhcp + 1.0.0 + DHCP Server REST API + + APIs for interacting with the DHCP Server application. + + org.onosproject.dhcp.rest + + + + + org.onosproject + onos-app-dhcp-api + ${project.version} + + + org.osgi + org.osgi.compendium + + + + org.onosproject + onos-cli + ${project.version} + + + + org.apache.karaf.shell + org.apache.karaf.shell.console + compile + + + + org.onosproject + onlab-junit + test + + + org.onosproject + onos-core-serializers + ${project.version} + + + + org.onosproject + onos-incubator-api + ${project.version} + + + org.onosproject + onos-api + ${project.version} + tests + test + + + + org.onosproject + onos-rest + ${project.version} + + + org.onosproject + onlab-rest + ${project.version} + + + javax.ws.rs + jsr311-api + 1.1.1 + + + com.sun.jersey + jersey-servlet + + + com.fasterxml.jackson.core + jackson-databind + + + + com.fasterxml.jackson.core + jackson-annotations + + + + + + + org.apache.felix + maven-bundle-plugin + true + + + <_wab>src/main/webapp/ + + WEB-INF/classes/apidoc/swagger.json=target/swagger.json, + {maven-resources} + + + ${project.groupId}.${project.artifactId} + + + org.slf4j, + org.osgi.framework, + javax.ws.rs, + javax.ws.rs.core, + com.sun.jersey.api.core, + com.sun.jersey.spi.container.servlet, + com.sun.jersey.server.impl.container.servlet, + com.fasterxml.jackson.databind, + com.fasterxml.jackson.databind.node, + com.fasterxml.jackson.core, + org.apache.karaf.shell.commands, + org.apache.karaf.shell.console, + com.google.common.*, + org.onlab.packet.*, + org.onlab.rest.*, + org.onosproject.*, + org.onlab.util.*, + org.jboss.netty.util.* + + ${web.context} + + + + + + + diff --git a/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/DhcpLeaseDetails.java b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/DhcpLeaseDetails.java new file mode 100644 index 00000000..95f49e69 --- /dev/null +++ b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/DhcpLeaseDetails.java @@ -0,0 +1,41 @@ +/* + * 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.dhcp.cli; + +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.dhcp.DhcpService; + +/** + * Lists all the default lease parameters offered by the DHCP Server. + */ +@Command(scope = "onos", name = "dhcp-lease", + description = "Lists all the default lease parameters offered by the DHCP Server") +public class DhcpLeaseDetails extends AbstractShellCommand { + + private static final String DHCP_LEASE_FORMAT = "Lease Time: %ds\nRenewal Time: %ds\nRebinding Time: %ds"; + + @Override + protected void execute() { + + DhcpService dhcpService = AbstractShellCommand.get(DhcpService.class); + int leaseTime = dhcpService.getLeaseTime(); + int renewTime = dhcpService.getRenewalTime(); + int rebindTime = dhcpService.getRebindingTime(); + + print(DHCP_LEASE_FORMAT, leaseTime, renewTime, rebindTime); + } +} diff --git a/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/DhcpListAllMappings.java b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/DhcpListAllMappings.java new file mode 100644 index 00000000..209ba683 --- /dev/null +++ b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/DhcpListAllMappings.java @@ -0,0 +1,44 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.dhcp.cli; + +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.dhcp.DhcpService; +import org.onosproject.dhcp.IpAssignment; +import org.onosproject.net.HostId; + +import java.util.Map; + +/** + * Lists all the MacAddress to IP Address mappings held by the DHCP Server. + */ +@Command(scope = "onos", name = "dhcp-list", + description = "Lists all the MAC to IP mappings held by the DHCP Server") +public class DhcpListAllMappings extends AbstractShellCommand { + + private static final String DHCP_MAPPING_FORMAT = "MAC ID: %s -> IP ASSIGNED %s"; + @Override + protected void execute() { + + DhcpService dhcpService = AbstractShellCommand.get(DhcpService.class); + Map allocationMap = dhcpService.listMapping(); + + for (Map.Entry entry : allocationMap.entrySet()) { + print(DHCP_MAPPING_FORMAT, entry.getKey().toString(), entry.getValue().ipAddress().toString()); + } + } +} diff --git a/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/DhcpRemoveStaticMapping.java b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/DhcpRemoveStaticMapping.java new file mode 100644 index 00000000..a92cd250 --- /dev/null +++ b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/DhcpRemoveStaticMapping.java @@ -0,0 +1,56 @@ +/* + * 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.dhcp.cli; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onlab.packet.MacAddress; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.dhcp.DhcpService; + +/** + * Removes a static MAC Address to IP Mapping from the DHCP Server. + */ +@Command(scope = "onos", name = "dhcp-remove-static-mapping", + description = "Removes a static MAC Address to IP Mapping from the DHCP Server") +public class DhcpRemoveStaticMapping extends AbstractShellCommand { + + @Argument(index = 0, name = "macAddr", + description = "MAC Address of the client", + required = true, multiValued = false) + String macAddr = null; + + private static final String DHCP_SUCCESS = "Static Mapping Successfully Removed."; + private static final String DHCP_FAILURE = "Static Mapping Removal Failed. " + + "Either the mapping does not exist or it is not static."; + + @Override + protected void execute() { + DhcpService dhcpService = AbstractShellCommand.get(DhcpService.class); + + try { + MacAddress macID = MacAddress.valueOf(macAddr); + if (dhcpService.removeStaticMapping(macID)) { + print(DHCP_SUCCESS); + } else { + print(DHCP_FAILURE); + } + + } catch (IllegalArgumentException e) { + print(e.getMessage()); + } + } +} diff --git a/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/DhcpSetStaticMapping.java b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/DhcpSetStaticMapping.java new file mode 100644 index 00000000..9f4f6580 --- /dev/null +++ b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/DhcpSetStaticMapping.java @@ -0,0 +1,61 @@ +/* + * 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.dhcp.cli; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onlab.packet.Ip4Address; +import org.onlab.packet.MacAddress; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.dhcp.DhcpService; + +/** + * Registers a static MAC Address to IP Mapping with the DHCP Server. + */ +@Command(scope = "onos", name = "dhcp-set-static-mapping", + description = "Registers a static MAC Address to IP Mapping with the DHCP Server") +public class DhcpSetStaticMapping extends AbstractShellCommand { + + @Argument(index = 0, name = "macAddr", + description = "MAC Address of the client", + required = true, multiValued = false) + String macAddr = null; + + @Argument(index = 1, name = "ipAddr", + description = "IP Address requested for static mapping", + required = true, multiValued = false) + String ipAddr = null; + + private static final String DHCP_SUCCESS = "Static Mapping Successfully Added."; + private static final String DHCP_FAILURE = "Static Mapping Failed. The IP maybe unavailable."; + @Override + protected void execute() { + DhcpService dhcpService = AbstractShellCommand.get(DhcpService.class); + + try { + MacAddress macID = MacAddress.valueOf(macAddr); + Ip4Address ipAddress = Ip4Address.valueOf(ipAddr); + if (dhcpService.setStaticMapping(macID, ipAddress)) { + print(DHCP_SUCCESS); + } else { + print(DHCP_FAILURE); + } + + } catch (IllegalArgumentException e) { + print(e.getMessage()); + } + } +} diff --git a/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/FreeIpCompleter.java b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/FreeIpCompleter.java new file mode 100644 index 00000000..228d70fd --- /dev/null +++ b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/FreeIpCompleter.java @@ -0,0 +1,48 @@ +/* + * 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.dhcp.cli; + +import org.apache.karaf.shell.console.Completer; +import org.apache.karaf.shell.console.completer.StringsCompleter; +import org.onlab.packet.Ip4Address; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.dhcp.DhcpService; + +import java.util.Iterator; +import java.util.List; +import java.util.SortedSet; + +/** + * Free IP Completer. + */ +public class FreeIpCompleter implements Completer { + + @Override + public int complete(String buffer, int cursor, List candidates) { + // Delegate string completer + StringsCompleter delegate = new StringsCompleter(); + DhcpService dhcpService = AbstractShellCommand.get(DhcpService.class); + Iterator it = dhcpService.getAvailableIPs().iterator(); + SortedSet strings = delegate.getStrings(); + + while (it.hasNext()) { + strings.add(it.next().toString()); + } + + // Now let the completer do the work for figuring out what to offer. + return delegate.complete(buffer, cursor, candidates); + } +} diff --git a/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/MacIdCompleter.java b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/MacIdCompleter.java new file mode 100644 index 00000000..d6cd73a7 --- /dev/null +++ b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/MacIdCompleter.java @@ -0,0 +1,48 @@ +/* + * 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.dhcp.cli; + +import org.apache.karaf.shell.console.Completer; +import org.apache.karaf.shell.console.completer.StringsCompleter; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.net.Host; +import org.onosproject.net.host.HostService; + +import java.util.Iterator; +import java.util.List; +import java.util.SortedSet; + +/** + * MAC ID Completer. + */ +public class MacIdCompleter implements Completer { + + @Override + public int complete(String buffer, int cursor, List candidates) { + // Delegate string completer + StringsCompleter delegate = new StringsCompleter(); + HostService service = AbstractShellCommand.get(HostService.class); + Iterator it = service.getHosts().iterator(); + SortedSet strings = delegate.getStrings(); + + while (it.hasNext()) { + strings.add(it.next().mac().toString()); + } + + // Now let the completer do the work for figuring out what to offer. + return delegate.complete(buffer, cursor, candidates); + } +} diff --git a/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/package-info.java b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/package-info.java new file mode 100644 index 00000000..f8780195 --- /dev/null +++ b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/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. + */ + +/** + * CLI implementation for sample application that assigns and manages DHCP leases. + */ +package org.onosproject.dhcp.cli; \ No newline at end of file diff --git a/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DhcpConfig.java b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DhcpConfig.java new file mode 100644 index 00000000..4353d623 --- /dev/null +++ b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DhcpConfig.java @@ -0,0 +1,319 @@ +/* + * 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.dhcp.impl; + +import org.onlab.packet.Ip4Address; +import org.onlab.packet.MacAddress; +import org.onosproject.core.ApplicationId; +import org.onosproject.net.config.Config; +import org.onosproject.net.config.basics.BasicElementConfig; + +/** + * DHCP Config class. + */ +public class DhcpConfig extends Config { + + public static final String MY_IP = "ip"; + public static final String MY_MAC = "mac"; + public static final String SUBNET_MASK = "subnet"; + public static final String BROADCAST_ADDRESS = "broadcast"; + public static final String ROUTER_ADDRESS = "router"; + public static final String DOMAIN_SERVER = "domain"; + public static final String TTL = "ttl"; + public static final String LEASE_TIME = "lease"; + public static final String RENEW_TIME = "renew"; + public static final String REBIND_TIME = "rebind"; + public static final String TIMER_DELAY = "delay"; + public static final String DEFAULT_TIMEOUT = "timeout"; + public static final String START_IP = "startip"; + public static final String END_IP = "endip"; + + public static final int DEFAULT = -1; + + /** + * Returns the dhcp server ip. + * + * @return ip address or null if not set + */ + public Ip4Address ip() { + String ip = get(MY_IP, null); + return ip != null ? Ip4Address.valueOf(ip) : null; + } + + /** + * Sets the dhcp server ip. + * + * @param ip new ip address; null to clear + * @return self + */ + public BasicElementConfig ip(String ip) { + return (BasicElementConfig) setOrClear(MY_IP, ip); + } + + /** + * Returns the dhcp server mac. + * + * @return server mac or null if not set + */ + public MacAddress mac() { + String mac = get(MY_MAC, null); + return mac != null ? MacAddress.valueOf(mac) : null; + } + + /** + * Sets the dhcp server mac. + * + * @param mac new mac address; null to clear + * @return self + */ + public BasicElementConfig mac(String mac) { + return (BasicElementConfig) setOrClear(MY_MAC, mac); + } + + /** + * Returns the subnet mask. + * + * @return subnet mask or null if not set + */ + public Ip4Address subnetMask() { + String ip = get(SUBNET_MASK, null); + return ip != null ? Ip4Address.valueOf(ip) : null; + } + + /** + * Sets the subnet mask. + * + * @param subnet new subnet mask; null to clear + * @return self + */ + public BasicElementConfig subnetMask(String subnet) { + return (BasicElementConfig) setOrClear(SUBNET_MASK, subnet); + } + + /** + * Returns the broadcast address. + * + * @return broadcast address or null if not set + */ + public Ip4Address broadcastAddress() { + String ip = get(BROADCAST_ADDRESS, null); + return ip != null ? Ip4Address.valueOf(ip) : null; + } + + /** + * Sets the broadcast address. + * + * @param broadcast new broadcast address; null to clear + * @return self + */ + public BasicElementConfig broadcastAddress(String broadcast) { + return (BasicElementConfig) setOrClear(BROADCAST_ADDRESS, broadcast); + } + + /** + * Returns the Time To Live for the reply packets. + * + * @return ttl or -1 if not set + */ + public int ttl() { + return get(TTL, DEFAULT); + } + + /** + * Sets the Time To Live for the reply packets. + * + * @param ttl new ttl; null to clear + * @return self + */ + public BasicElementConfig ttl(int ttl) { + return (BasicElementConfig) setOrClear(TTL, ttl); + } + + /** + * Returns the Lease Time offered by the DHCP Server. + * + * @return lease time or -1 if not set + */ + public int leaseTime() { + return get(LEASE_TIME, DEFAULT); + } + + /** + * Sets the Lease Time offered by the DHCP Server. + * + * @param lease new lease time; null to clear + * @return self + */ + public BasicElementConfig leaseTime(int lease) { + return (BasicElementConfig) setOrClear(LEASE_TIME, lease); + } + + /** + * Returns the Renew Time offered by the DHCP Server. + * + * @return renew time or -1 if not set + */ + public int renewTime() { + return get(RENEW_TIME, DEFAULT); + } + + /** + * Sets the Renew Time offered by the DHCP Server. + * + * @param renew new renew time; null to clear + * @return self + */ + public BasicElementConfig renewTime(int renew) { + return (BasicElementConfig) setOrClear(RENEW_TIME, renew); + } + + /** + * Returns the Rebind Time offered by the DHCP Server. + * + * @return rebind time or -1 if not set + */ + public int rebindTime() { + return get(REBIND_TIME, DEFAULT); + } + + /** + * Sets the Rebind Time offered by the DHCP Server. + * + * @param rebind new rebind time; null to clear + * @return self + */ + public BasicElementConfig rebindTime(int rebind) { + return (BasicElementConfig) setOrClear(REBIND_TIME, rebind); + } + + /** + * Returns the Router Address. + * + * @return router address or null if not set + */ + public Ip4Address routerAddress() { + String ip = get(ROUTER_ADDRESS, null); + return ip != null ? Ip4Address.valueOf(ip) : null; + } + + /** + * Sets the Router Address. + * + * @param router new router address; null to clear + * @return self + */ + public BasicElementConfig routerAddress(String router) { + return (BasicElementConfig) setOrClear(ROUTER_ADDRESS, router); + } + + /** + * Returns the Domain Server Address. + * + * @return domain server address or null if not set + */ + public Ip4Address domainServer() { + String ip = get(DOMAIN_SERVER, null); + return ip != null ? Ip4Address.valueOf(ip) : null; + } + + /** + * Sets the Domain Server Address. + * + * @param domain new domain server address; null to clear + * @return self + */ + public BasicElementConfig domainServer(String domain) { + return (BasicElementConfig) setOrClear(DOMAIN_SERVER, domain); + } + + /** + * Returns the delay in minutes after which the dhcp server will purge expired entries. + * + * @return time delay or -1 if not set + */ + public int timerDelay() { + return get(TIMER_DELAY, DEFAULT); + } + + /** + * Sets the delay after which the dhcp server will purge expired entries. + * + * @param delay new time delay; null to clear + * @return self + */ + public BasicElementConfig timerDelay(int delay) { + return (BasicElementConfig) setOrClear(TIMER_DELAY, delay); + } + + /** + * Returns the default timeout for pending assignments. + * + * @return default timeout or -1 if not set + */ + public int defaultTimeout() { + return get(DEFAULT_TIMEOUT, DEFAULT); + } + + /** + * Sets the default timeout for pending assignments. + * + * @param defaultTimeout new default timeout; null to clear + * @return self + */ + public BasicElementConfig defaultTimeout(int defaultTimeout) { + return (BasicElementConfig) setOrClear(DEFAULT_TIMEOUT, defaultTimeout); + } + + /** + * Returns the start IP for the available IP Range. + * + * @return start IP or null if not set + */ + public Ip4Address startIp() { + String ip = get(START_IP, null); + return ip != null ? Ip4Address.valueOf(ip) : null; + } + + /** + * Sets the start IP for the available IP Range. + * + * @param startIp new start IP; null to clear + * @return self + */ + public BasicElementConfig startIp(String startIp) { + return (BasicElementConfig) setOrClear(START_IP, startIp); + } + + /** + * Returns the end IP for the available IP Range. + * + * @return end IP or null if not set + */ + public Ip4Address endIp() { + String ip = get(END_IP, null); + return ip != null ? Ip4Address.valueOf(ip) : null; + } + + /** + * Sets the end IP for the available IP Range. + * + * @param endIp new end IP; null to clear + * @return self + */ + public BasicElementConfig endIp(String endIp) { + return (BasicElementConfig) setOrClear(END_IP, endIp); + } +} diff --git a/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DhcpManager.java b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DhcpManager.java new file mode 100644 index 00000000..96d94a2b --- /dev/null +++ b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DhcpManager.java @@ -0,0 +1,699 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.dhcp.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; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.ReferenceCardinality; +import org.apache.felix.scr.annotations.Service; +import org.jboss.netty.util.Timeout; +import org.jboss.netty.util.TimerTask; +import org.onlab.packet.ARP; +import org.onlab.packet.DHCP; +import org.onlab.packet.DHCPOption; +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.TpPort; +import org.onlab.packet.UDP; +import org.onlab.packet.VlanId; +import org.onlab.util.Timer; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.CoreService; +import org.onosproject.dhcp.DhcpService; +import org.onosproject.dhcp.DhcpStore; +import org.onosproject.dhcp.IpAssignment; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.Host; +import org.onosproject.net.HostId; +import org.onosproject.net.HostLocation; +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; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.host.DefaultHostDescription; +import org.onosproject.net.host.HostProvider; +import org.onosproject.net.host.HostProviderRegistry; +import org.onosproject.net.host.HostProviderService; +import org.onosproject.net.packet.DefaultOutboundPacket; +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.onosproject.net.provider.AbstractProvider; +import org.onosproject.net.provider.ProviderId; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import static org.onlab.packet.MacAddress.valueOf; +import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY; + +/** + * Skeletal ONOS DHCP Server application. + */ +@Component(immediate = true) +@Service +public class DhcpManager implements DhcpService { + + private static final ProviderId PID = new ProviderId("of", "org.onosproject.dhcp", true); + private final Logger log = LoggerFactory.getLogger(getClass()); + + private final InternalConfigListener cfgListener = new InternalConfigListener(); + + private final Set factories = ImmutableSet.of( + new ConfigFactory(APP_SUBJECT_FACTORY, + DhcpConfig.class, + "dhcp") { + @Override + public DhcpConfig createConfig() { + return new DhcpConfig(); + } + } + ); + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected NetworkConfigRegistry cfgService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected PacketService packetService; + + private DHCPPacketProcessor processor = new DHCPPacketProcessor(); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected CoreService coreService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected DhcpStore dhcpStore; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected HostProviderRegistry hostProviderRegistry; + + protected HostProviderService hostProviderService; + + private final HostProvider hostProvider = new InternalHostProvider(); + + private ApplicationId appId; + + // Hardcoded values are default values. + + private static Ip4Address myIP = Ip4Address.valueOf("10.0.0.2"); + + private static MacAddress myMAC = valueOf("4f:4f:4f:4f:4f:4f"); + + /** + * leaseTime - 10 mins or 600s. + * renewalTime - 5 mins or 300s. + * rebindingTime - 6 mins or 360s. + */ + + private static int leaseTime = 600; + + private static int renewalTime = 300; + + private static int rebindingTime = 360; + + private static byte packetTTL = (byte) 127; + + private static Ip4Address subnetMask = Ip4Address.valueOf("255.0.0.0"); + + private static Ip4Address broadcastAddress = Ip4Address.valueOf("10.255.255.255"); + + private static Ip4Address routerAddress = Ip4Address.valueOf("10.0.0.2"); + + 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; + + @Activate + protected void activate() { + // start the dhcp server + appId = coreService.registerApplication("org.onosproject.dhcp"); + + cfgService.addListener(cfgListener); + factories.forEach(cfgService::registerConfigFactory); + cfgListener.reconfigureNetwork(cfgService.getConfig(appId, DhcpConfig.class)); + + hostProviderService = hostProviderRegistry.register(hostProvider); + packetService.addProcessor(processor, PacketProcessor.director(0)); + requestPackets(); + timeout = Timer.getTimer().newTimeout(new PurgeListTask(), timerDelay, TimeUnit.MINUTES); + log.info("Started"); + } + + @Deactivate + protected void deactivate() { + cfgService.removeListener(cfgListener); + factories.forEach(cfgService::unregisterConfigFactory); + packetService.removeProcessor(processor); + hostProviderRegistry.unregister(hostProvider); + hostProviderService = null; + cancelPackets(); + timeout.cancel(); + log.info("Stopped"); + } + + /** + * Request packet in via PacketService. + */ + private void requestPackets() { + + TrafficSelector.Builder selectorServer = DefaultTrafficSelector.builder() + .matchEthType(Ethernet.TYPE_IPV4) + .matchIPProtocol(IPv4.PROTOCOL_UDP) + .matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT)) + .matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT)); + packetService.requestPackets(selectorServer.build(), PacketPriority.CONTROL, appId); + + selectorServer = DefaultTrafficSelector.builder() + .matchEthType(Ethernet.TYPE_ARP); + packetService.requestPackets(selectorServer.build(), PacketPriority.CONTROL, appId); + } + + /** + * Cancel requested packets in via packet service. + */ + private void cancelPackets() { + TrafficSelector.Builder selectorServer = DefaultTrafficSelector.builder() + .matchEthType(Ethernet.TYPE_IPV4) + .matchIPProtocol(IPv4.PROTOCOL_UDP) + .matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT)) + .matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT)); + packetService.cancelPackets(selectorServer.build(), PacketPriority.CONTROL, appId); + + selectorServer = DefaultTrafficSelector.builder() + .matchEthType(Ethernet.TYPE_ARP); + packetService.cancelPackets(selectorServer.build(), PacketPriority.CONTROL, appId); + } + + @Override + public Map listMapping() { + return dhcpStore.listAssignedMapping(); + } + + @Override + public int getLeaseTime() { + return leaseTime; + } + + @Override + public int getRenewalTime() { + return renewalTime; + } + + @Override + public int getRebindingTime() { + return rebindingTime; + } + + @Override + public boolean setStaticMapping(MacAddress macID, Ip4Address ipAddress) { + return dhcpStore.assignStaticIP(macID, ipAddress); + } + + @Override + public boolean removeStaticMapping(MacAddress macID) { + return dhcpStore.removeStaticIP(macID); + } + + @Override + public Iterable getAvailableIPs() { + return dhcpStore.getAvailableIPs(); + } + + private class DHCPPacketProcessor implements PacketProcessor { + + /** + * Builds the DHCP Reply packet. + * + * @param packet the incoming Ethernet frame + * @param ipOffered the IP offered by the DHCP Server + * @param outgoingMessageType the message type of the outgoing packet + * @return the Ethernet reply frame + */ + private Ethernet buildReply(Ethernet packet, Ip4Address ipOffered, byte outgoingMessageType) { + + // Ethernet Frame. + Ethernet ethReply = new Ethernet(); + ethReply.setSourceMACAddress(myMAC); + ethReply.setDestinationMACAddress(packet.getSourceMAC()); + ethReply.setEtherType(Ethernet.TYPE_IPV4); + ethReply.setVlanID(packet.getVlanID()); + + // IP Packet + IPv4 ipv4Packet = (IPv4) packet.getPayload(); + IPv4 ipv4Reply = new IPv4(); + ipv4Reply.setSourceAddress(myIP.toInt()); + ipv4Reply.setDestinationAddress(ipOffered.toInt()); + ipv4Reply.setTtl(packetTTL); + + // UDP Datagram. + UDP udpPacket = (UDP) ipv4Packet.getPayload(); + UDP udpReply = new UDP(); + udpReply.setSourcePort((byte) UDP.DHCP_SERVER_PORT); + udpReply.setDestinationPort((byte) UDP.DHCP_CLIENT_PORT); + + // DHCP Payload. + DHCP dhcpPacket = (DHCP) udpPacket.getPayload(); + DHCP dhcpReply = new DHCP(); + dhcpReply.setOpCode(DHCP.OPCODE_REPLY); + 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); + + // DHCP Options. + DHCPOption option = new DHCPOption(); + List optionList = new ArrayList<>(); + + // DHCP Message Type. + option.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue()); + option.setLength((byte) 1); + byte[] optionData = {outgoingMessageType}; + option.setData(optionData); + optionList.add(option); + + // DHCP Server Identifier. + option = new DHCPOption(); + option.setCode(DHCP.DHCPOptionCode.OptionCode_DHCPServerIp.getValue()); + option.setLength((byte) 4); + option.setData(myIP.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(); + option.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue()); + option.setLength((byte) 1); + optionList.add(option); + + dhcpReply.setOptions(optionList); + + udpReply.setPayload(dhcpReply); + ipv4Reply.setPayload(udpReply); + ethReply.setPayload(ipv4Reply); + + return ethReply; + } + + /** + * Sends the Ethernet reply frame via the Packet Service. + * + * @param context the context of the incoming frame + * @param reply the Ethernet reply frame + */ + private void sendReply(PacketContext context, Ethernet reply) { + if (reply != null) { + TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder(); + ConnectPoint sourcePoint = context.inPacket().receivedFrom(); + builder.setOutput(sourcePoint.port()); + context.block(); + packetService.emit(new DefaultOutboundPacket(sourcePoint.deviceId(), + builder.build(), ByteBuffer.wrap(reply.serialize()))); + } + } + + /** + * Processes the DHCP Payload and initiates a reply to the client. + * + * @param context context of the incoming message + * @param dhcpPayload the extracted DHCP payload + */ + private void processDHCPPacket(PacketContext context, DHCP dhcpPayload) { + Ethernet packet = context.inPacket().parsed(); + boolean flagIfRequestedIP = false; + boolean flagIfServerIP = false; + Ip4Address requestedIP = Ip4Address.valueOf("0.0.0.0"); + Ip4Address serverIP = Ip4Address.valueOf("0.0.0.0"); + + if (dhcpPayload != null) { + + DHCPPacketType incomingPacketType = DHCPPacketType.getType(0); + for (DHCPOption option : dhcpPayload.getOptions()) { + if (option.getCode() == DHCP.DHCPOptionCode.OptionCode_MessageType.getValue()) { + byte[] data = option.getData(); + incomingPacketType = DHCPPacketType.getType(data[0]); + } + if (option.getCode() == DHCP.DHCPOptionCode.OptionCode_RequestedIP.getValue()) { + byte[] data = option.getData(); + requestedIP = Ip4Address.valueOf(data); + flagIfRequestedIP = true; + } + if (option.getCode() == DHCP.DHCPOptionCode.OptionCode_DHCPServerIp.getValue()) { + byte[] data = option.getData(); + serverIP = Ip4Address.valueOf(data); + flagIfServerIP = true; + } + } + DHCPPacketType outgoingPacketType; + MacAddress clientMAC = new MacAddress(dhcpPayload.getClientHardwareAddress()); + VlanId vlanId = VlanId.vlanId(packet.getVlanID()); + HostId hostId = HostId.hostId(clientMAC, vlanId); + + if (incomingPacketType.getValue() == DHCPPacketType.DHCPDISCOVER.getValue()) { + + outgoingPacketType = DHCPPacketType.DHCPOFFER; + Ip4Address ipOffered = dhcpStore.suggestIP(hostId, requestedIP); + if (ipOffered != null) { + Ethernet ethReply = buildReply(packet, ipOffered, + (byte) outgoingPacketType.getValue()); + sendReply(context, ethReply); + } + + } else if (incomingPacketType.getValue() == DHCPPacketType.DHCPREQUEST.getValue()) { + + if (flagIfServerIP && flagIfRequestedIP) { + // SELECTING state + if (myIP.equals(serverIP)) { + + 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); + } + } else if (flagIfRequestedIP) { + // INIT-REBOOT state + if (dhcpStore.assignIP(hostId, requestedIP, leaseTime)) { + 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)) { + 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()) { + Ip4Address ip4Address = dhcpStore.releaseIP(hostId); + if (ip4Address != null) { + hostProviderService.removeIpFromHost(hostId, ip4Address); + } + } + } + } + + /** + * Processes the ARP Payload and initiates a reply to the client. + * + * @param context context of the incoming message + * @param packet the ethernet payload + */ + private void processARPPacket(PacketContext context, Ethernet packet) { + + ARP arpPacket = (ARP) packet.getPayload(); + + ARP arpReply = (ARP) arpPacket.clone(); + arpReply.setOpCode(ARP.OP_REPLY); + + arpReply.setTargetProtocolAddress(arpPacket.getSenderProtocolAddress()); + arpReply.setTargetHardwareAddress(arpPacket.getSenderHardwareAddress()); + arpReply.setSenderProtocolAddress(arpPacket.getTargetProtocolAddress()); + arpReply.setSenderHardwareAddress(myMAC.toBytes()); + + // Ethernet Frame. + Ethernet ethReply = new Ethernet(); + ethReply.setSourceMACAddress(myMAC); + ethReply.setDestinationMACAddress(packet.getSourceMAC()); + ethReply.setEtherType(Ethernet.TYPE_ARP); + ethReply.setVlanID(packet.getVlanID()); + + ethReply.setPayload(arpReply); + sendReply(context, ethReply); + } + + /** + * Integrates hosts learned through DHCP into topology. + * @param context context of the incoming message + * @param ipAssigned IP Address assigned to the host by DHCP Manager + */ + private void discoverHost(PacketContext context, Ip4Address ipAssigned) { + Ethernet packet = context.inPacket().parsed(); + MacAddress mac = packet.getSourceMAC(); + VlanId vlanId = VlanId.vlanId(packet.getVlanID()); + HostLocation hostLocation = new HostLocation(context.inPacket().receivedFrom(), 0); + + Set ips = new HashSet<>(); + ips.add(ipAssigned); + + HostId hostId = HostId.hostId(mac, vlanId); + DefaultHostDescription desc = new DefaultHostDescription(mac, vlanId, hostLocation, ips); + hostProviderService.hostDetected(hostId, desc); + } + + + @Override + public void process(PacketContext context) { + Ethernet packet = context.inPacket().parsed(); + if (packet == null) { + return; + } + + if (packet.getEtherType() == Ethernet.TYPE_IPV4) { + IPv4 ipv4Packet = (IPv4) packet.getPayload(); + + if (ipv4Packet.getProtocol() == IPv4.PROTOCOL_UDP) { + UDP udpPacket = (UDP) ipv4Packet.getPayload(); + + if (udpPacket.getDestinationPort() == UDP.DHCP_SERVER_PORT && + udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT) { + // This is meant for the dhcp server so process the packet here. + + DHCP dhcpPayload = (DHCP) udpPacket.getPayload(); + processDHCPPacket(context, dhcpPayload); + } + } + } else if (packet.getEtherType() == Ethernet.TYPE_ARP) { + ARP arpPacket = (ARP) packet.getPayload(); + + if ((arpPacket.getOpCode() == ARP.OP_REQUEST) && + Objects.equals(myIP, Ip4Address.valueOf(arpPacket.getTargetProtocolAddress()))) { + + processARPPacket(context, packet); + + } + } + } + } + + private class InternalConfigListener implements NetworkConfigListener { + + /** + * Reconfigures the DHCP Server according to the configuration parameters passed. + * + * @param cfg configuration object + */ + private void reconfigureNetwork(DhcpConfig cfg) { + if (cfg == null) { + return; + } + if (cfg.ip() != null) { + myIP = cfg.ip(); + } + if (cfg.mac() != null) { + myMAC = cfg.mac(); + } + if (cfg.subnetMask() != null) { + subnetMask = cfg.subnetMask(); + } + if (cfg.broadcastAddress() != null) { + broadcastAddress = cfg.broadcastAddress(); + } + if (cfg.routerAddress() != null) { + routerAddress = cfg.routerAddress(); + } + if (cfg.domainServer() != null) { + domainServer = cfg.domainServer(); + } + if (cfg.ttl() != -1) { + packetTTL = (byte) cfg.ttl(); + } + if (cfg.leaseTime() != -1) { + leaseTime = cfg.leaseTime(); + } + if (cfg.renewTime() != -1) { + renewalTime = cfg.renewTime(); + } + if (cfg.rebindTime() != -1) { + rebindingTime = cfg.rebindTime(); + } + if (cfg.defaultTimeout() != -1) { + dhcpStore.setDefaultTimeoutForPurge(cfg.defaultTimeout()); + } + if (cfg.timerDelay() != -1) { + timerDelay = cfg.timerDelay(); + } + if ((cfg.startIp() != null) && (cfg.endIp() != null)) { + dhcpStore.populateIPPoolfromRange(cfg.startIp(), cfg.endIp()); + } + } + + + @Override + public void event(NetworkConfigEvent event) { + + if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED || + event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) && + event.configClass().equals(DhcpConfig.class)) { + + DhcpConfig cfg = cfgService.getConfig(appId, DhcpConfig.class); + reconfigureNetwork(cfg); + log.info("Reconfigured"); + } + } + } + + private class InternalHostProvider extends AbstractProvider implements HostProvider { + + /** + * Creates a provider with the supplier identifier. + */ + protected InternalHostProvider() { + super(PID); + } + + @Override + public void triggerProbe(Host host) { + // nothing to do + } + } + + private class PurgeListTask implements TimerTask { + + @Override + public void run(Timeout to) { + IpAssignment ipAssignment; + Date dateNow = new Date(); + + Map ipAssignmentMap = dhcpStore.listAllMapping(); + for (Map.Entry entry: ipAssignmentMap.entrySet()) { + ipAssignment = entry.getValue(); + + long timeLapsed = dateNow.getTime() - ipAssignment.timestamp().getTime(); + if ((ipAssignment.assignmentStatus() != IpAssignment.AssignmentStatus.Option_Expired) && + (ipAssignment.leasePeriod() > 0) && (timeLapsed > (ipAssignment.leasePeriodMs()))) { + + Ip4Address ip4Address = dhcpStore.releaseIP(entry.getKey()); + if (ip4Address != null) { + hostProviderService.removeIpFromHost(entry.getKey(), ipAssignment.ipAddress()); + } + } + } + timeout = Timer.getTimer().newTimeout(new PurgeListTask(), timerDelay, TimeUnit.MINUTES); + } + } +} \ No newline at end of file diff --git a/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DhcpUi.java b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DhcpUi.java new file mode 100644 index 00000000..bb2bd2c2 --- /dev/null +++ b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DhcpUi.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.dhcp.impl; + +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.apache.felix.scr.annotations.Service; +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; + +import static org.onosproject.ui.UiView.Category.NETWORK; + +/** + * Mechanism to stream data to the GUI. + */ +@Component(immediate = true, enabled = true) +@Service(value = DhcpUi.class) +public class DhcpUi { + + private final Logger log = LoggerFactory.getLogger(getClass()); + private static final ClassLoader CL = DhcpUi.class.getClassLoader(); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected UiExtensionService uiExtensionService; + + private final UiMessageHandlerFactory messageHandlerFactory = + () -> ImmutableList.of(new DhcpViewMessageHandler()); + + private final List views = ImmutableList.of( + new UiView(NETWORK, "dhcp", "DHCP Server") + ); + + private final UiExtension uiExtension = + new UiExtension.Builder(CL, views) + .messageHandlerFactory(messageHandlerFactory) + .resourcePath("gui") + .build(); + + @Activate + protected void activate() { + uiExtensionService.register(uiExtension); + log.info("Started"); + } + + @Deactivate + protected void deactivate() { + uiExtensionService.unregister(uiExtension); + log.info("Stopped"); + } + +} \ No newline at end of file diff --git a/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DhcpViewMessageHandler.java b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DhcpViewMessageHandler.java new file mode 100644 index 00000000..9ce65d5e --- /dev/null +++ b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DhcpViewMessageHandler.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.dhcp.impl; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.collect.ImmutableSet; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.dhcp.DhcpService; +import org.onosproject.dhcp.IpAssignment; +import org.onosproject.net.HostId; +import org.onosproject.ui.RequestHandler; +import org.onosproject.ui.UiMessageHandler; +import org.onosproject.ui.table.TableModel; +import org.onosproject.ui.table.TableRequestHandler; + +import java.util.Collection; +import java.util.Date; +import java.util.Map; + +/** + * DHCPViewMessageHandler class implementation. + */ +public class DhcpViewMessageHandler extends UiMessageHandler { + + private static final String DHCP_DATA_REQ = "dhcpDataRequest"; + private static final String DHCP_DATA_RESP = "dhcpDataResponse"; + private static final String DHCP = "dhcps"; + + private static final String HOST = "host"; + private static final String IP = "ip"; + private static final String LEASE = "lease"; + + private static final String[] COL_IDS = { + HOST, IP, LEASE + }; + + @Override + protected Collection createRequestHandlers() { + return ImmutableSet.of( + new DataRequestHandler() + ); + } + + // handler for dhcp table requests + private final class DataRequestHandler extends TableRequestHandler { + + private DataRequestHandler() { + super(DHCP_DATA_REQ, DHCP_DATA_RESP, DHCP); + } + + @Override + protected String defaultColumnId() { + return HOST; + } + + @Override + protected String[] getColumnIds() { + return COL_IDS; + } + + @Override + protected void populateTable(TableModel tm, ObjectNode payload) { + DhcpService dhcpService = AbstractShellCommand.get(DhcpService.class); + Map allocationMap = dhcpService.listMapping(); + + for (Map.Entry entry : allocationMap.entrySet()) { + populateRow(tm.addRow(), entry); + } + } + + private void populateRow(TableModel.Row row, Map.Entry entry) { + if (entry.getValue().leasePeriod() > 0) { + Date now = new Date(entry.getValue().timestamp().getTime() + entry.getValue().leasePeriod()); + row.cell(HOST, entry.getKey()) + .cell(IP, entry.getValue().ipAddress()) + .cell(LEASE, now.toString()); + } else { + row.cell(HOST, entry.getKey()) + .cell(IP, entry.getValue().ipAddress()) + .cell(LEASE, "Infinite Static Lease"); + } + } + } +} diff --git a/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DistributedDhcpStore.java b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DistributedDhcpStore.java new file mode 100644 index 00000000..63f69d40 --- /dev/null +++ b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DistributedDhcpStore.java @@ -0,0 +1,328 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.dhcp.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; +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.Ip4Address; +import org.onlab.packet.MacAddress; +import org.onlab.util.KryoNamespace; +import org.onosproject.dhcp.DhcpStore; +import org.onosproject.dhcp.IpAssignment; +import org.onosproject.net.HostId; +import org.onosproject.store.serializers.KryoNamespaces; +import org.onosproject.store.service.ConsistentMap; +import org.onosproject.store.service.DistributedSet; +import org.onosproject.store.service.Serializer; +import org.onosproject.store.service.StorageService; +import org.onosproject.store.service.Versioned; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +/** + * Manages the pool of available IP Addresses in the network and + * Remembers the mapping between MAC ID and IP Addresses assigned. + */ + +@Component(immediate = true) +@Service +public class DistributedDhcpStore implements DhcpStore { + + private final Logger log = LoggerFactory.getLogger(getClass()); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected StorageService storageService; + + private ConsistentMap allocationMap; + + private DistributedSet freeIPPool; + + private static Ip4Address startIPRange; + + private static Ip4Address endIPRange; + + // Hardcoded values are default values. + + private static int timeoutForPendingAssignments = 60; + + @Activate + protected void activate() { + allocationMap = storageService.consistentMapBuilder() + .withName("onos-dhcp-assignedIP") + .withSerializer(Serializer.using( + new KryoNamespace.Builder() + .register(KryoNamespaces.API) + .register(IpAssignment.class, + IpAssignment.AssignmentStatus.class, + Date.class, + long.class, + Ip4Address.class) + .build())) + .build(); + + freeIPPool = storageService.setBuilder() + .withName("onos-dhcp-freeIP") + .withSerializer(Serializer.using(KryoNamespaces.API)) + .build(); + + log.info("Started"); + } + + @Deactivate + protected void deactivate() { + log.info("Stopped"); + } + + @Override + public Ip4Address suggestIP(HostId hostId, Ip4Address requestedIP) { + + IpAssignment assignmentInfo; + if (allocationMap.containsKey(hostId)) { + assignmentInfo = allocationMap.get(hostId).value(); + IpAssignment.AssignmentStatus status = assignmentInfo.assignmentStatus(); + Ip4Address ipAddr = assignmentInfo.ipAddress(); + + if (status == IpAssignment.AssignmentStatus.Option_Assigned || + status == IpAssignment.AssignmentStatus.Option_Requested) { + // Client has a currently Active Binding. + if (ipWithinRange(ipAddr)) { + return ipAddr; + } + + } else if (status == IpAssignment.AssignmentStatus.Option_Expired) { + // Client has a Released or Expired Binding. + if (freeIPPool.contains(ipAddr)) { + assignmentInfo = IpAssignment.builder() + .ipAddress(ipAddr) + .timestamp(new Date()) + .leasePeriod(timeoutForPendingAssignments) + .assignmentStatus(IpAssignment.AssignmentStatus.Option_Requested) + .build(); + if (freeIPPool.remove(ipAddr)) { + allocationMap.put(hostId, assignmentInfo); + return ipAddr; + } + } + } + } else if (requestedIP.toInt() != 0) { + // Client has requested an IP. + if (freeIPPool.contains(requestedIP)) { + assignmentInfo = IpAssignment.builder() + .ipAddress(requestedIP) + .timestamp(new Date()) + .leasePeriod(timeoutForPendingAssignments) + .assignmentStatus(IpAssignment.AssignmentStatus.Option_Requested) + .build(); + if (freeIPPool.remove(requestedIP)) { + allocationMap.put(hostId, assignmentInfo); + return requestedIP; + } + } + } + + // Allocate a new IP from the server's pool of available IP. + Ip4Address nextIPAddr = fetchNextIP(); + if (nextIPAddr != null) { + assignmentInfo = IpAssignment.builder() + .ipAddress(nextIPAddr) + .timestamp(new Date()) + .leasePeriod(timeoutForPendingAssignments) + .assignmentStatus(IpAssignment.AssignmentStatus.Option_Requested) + .build(); + + allocationMap.put(hostId, assignmentInfo); + } + return nextIPAddr; + + } + + @Override + public boolean assignIP(HostId hostId, Ip4Address ipAddr, int leaseTime) { + + IpAssignment assignmentInfo; + if (allocationMap.containsKey(hostId)) { + assignmentInfo = allocationMap.get(hostId).value(); + IpAssignment.AssignmentStatus status = assignmentInfo.assignmentStatus(); + + if (Objects.equals(assignmentInfo.ipAddress(), ipAddr) && ipWithinRange(ipAddr)) { + + if (status == IpAssignment.AssignmentStatus.Option_Assigned || + status == IpAssignment.AssignmentStatus.Option_Requested) { + // Client has a currently active binding with the server. + assignmentInfo = IpAssignment.builder() + .ipAddress(ipAddr) + .timestamp(new Date()) + .leasePeriod(leaseTime) + .assignmentStatus(IpAssignment.AssignmentStatus.Option_Assigned) + .build(); + allocationMap.put(hostId, assignmentInfo); + return true; + } else if (status == IpAssignment.AssignmentStatus.Option_Expired) { + // Client has an expired binding with the server. + if (freeIPPool.contains(ipAddr)) { + assignmentInfo = IpAssignment.builder() + .ipAddress(ipAddr) + .timestamp(new Date()) + .leasePeriod(leaseTime) + .assignmentStatus(IpAssignment.AssignmentStatus.Option_Assigned) + .build(); + if (freeIPPool.remove(ipAddr)) { + allocationMap.put(hostId, assignmentInfo); + return true; + } + } + } + } + } else if (freeIPPool.contains(ipAddr)) { + assignmentInfo = IpAssignment.builder() + .ipAddress(ipAddr) + .timestamp(new Date()) + .leasePeriod(leaseTime) + .assignmentStatus(IpAssignment.AssignmentStatus.Option_Assigned) + .build(); + if (freeIPPool.remove(ipAddr)) { + allocationMap.put(hostId, assignmentInfo); + return true; + } + } + return false; + } + + @Override + public Ip4Address releaseIP(HostId hostId) { + if (allocationMap.containsKey(hostId)) { + IpAssignment newAssignment = IpAssignment.builder(allocationMap.get(hostId).value()) + .assignmentStatus(IpAssignment.AssignmentStatus.Option_Expired) + .build(); + Ip4Address freeIP = newAssignment.ipAddress(); + allocationMap.put(hostId, newAssignment); + if (ipWithinRange(freeIP)) { + freeIPPool.add(freeIP); + } + return freeIP; + } + return null; + } + + @Override + public void setDefaultTimeoutForPurge(int timeInSeconds) { + timeoutForPendingAssignments = timeInSeconds; + } + + @Override + public Map listAssignedMapping() { + + Map validMapping = new HashMap<>(); + IpAssignment assignment; + for (Map.Entry> entry: allocationMap.entrySet()) { + assignment = entry.getValue().value(); + if (assignment.assignmentStatus() == IpAssignment.AssignmentStatus.Option_Assigned) { + validMapping.put(entry.getKey(), assignment); + } + } + return validMapping; + } + + @Override + public Map listAllMapping() { + Map validMapping = new HashMap<>(); + for (Map.Entry> entry: allocationMap.entrySet()) { + validMapping.put(entry.getKey(), entry.getValue().value()); + } + return validMapping; + } + + @Override + public boolean assignStaticIP(MacAddress macID, Ip4Address ipAddr) { + HostId host = HostId.hostId(macID); + return assignIP(host, ipAddr, -1); + } + + @Override + public boolean removeStaticIP(MacAddress macID) { + HostId host = HostId.hostId(macID); + if (allocationMap.containsKey(host)) { + IpAssignment assignment = allocationMap.get(host).value(); + Ip4Address freeIP = assignment.ipAddress(); + if (assignment.leasePeriod() < 0) { + allocationMap.remove(host); + if (ipWithinRange(freeIP)) { + freeIPPool.add(freeIP); + } + return true; + } + } + return false; + } + + @Override + public Iterable getAvailableIPs() { + return ImmutableSet.copyOf(freeIPPool); + } + + @Override + public void populateIPPoolfromRange(Ip4Address startIP, Ip4Address endIP) { + // Clear all entries from previous range. + allocationMap.clear(); + freeIPPool.clear(); + startIPRange = startIP; + endIPRange = endIP; + + int lastIP = endIP.toInt(); + Ip4Address nextIP; + for (int loopCounter = startIP.toInt(); loopCounter <= lastIP; loopCounter++) { + nextIP = Ip4Address.valueOf(loopCounter); + freeIPPool.add(nextIP); + } + } + + /** + * Fetches the next available IP from the free pool pf IPs. + * + * @return the next available IP address + */ + private Ip4Address fetchNextIP() { + for (Ip4Address freeIP : freeIPPool) { + if (freeIPPool.remove(freeIP)) { + return freeIP; + } + } + return null; + } + + /** + * Returns true if the given ip is within the range of available IPs. + * + * @param ip given ip address + * @return true if within range, false otherwise + */ + private boolean ipWithinRange(Ip4Address ip) { + if ((ip.toInt() >= startIPRange.toInt()) && (ip.toInt() <= endIPRange.toInt())) { + return true; + } + return false; + } +} diff --git a/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/package-info.java b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/package-info.java new file mode 100644 index 00000000..12e14e48 --- /dev/null +++ b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/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 classes for sample application that assigns and manages DHCP leases. + */ +package org.onosproject.dhcp.impl; \ No newline at end of file diff --git a/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/rest/DHCPWebResource.java b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/rest/DHCPWebResource.java new file mode 100644 index 00000000..646ab7ea --- /dev/null +++ b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/rest/DHCPWebResource.java @@ -0,0 +1,164 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.dhcp.rest; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.onlab.packet.Ip4Address; +import org.onlab.packet.MacAddress; +import org.onosproject.dhcp.DhcpService; +import org.onosproject.dhcp.IpAssignment; +import org.onosproject.net.HostId; +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.util.Map; + +/** + * Manage DHCP address assignments. + */ +@Path("dhcp") +public class DHCPWebResource extends AbstractWebResource { + + final DhcpService service = get(DhcpService.class); + + /** + * Get DHCP server configuration data. + * Shows lease, renewal and rebinding times in seconds. + * + * @return 200 OK + */ + @GET + @Path("config") + public Response getConfigs() { + DhcpService service = get(DhcpService.class); + ObjectNode node = mapper().createObjectNode() + .put("leaseTime", service.getLeaseTime()) + .put("renewalTime", service.getRenewalTime()) + .put("rebindingTime", service.getRebindingTime()); + return ok(node.toString()).build(); + } + + /** + * Get all MAC/IP mappings. + * Shows all MAC/IP mappings held by the DHCP server. + * + * @return 200 OK + */ + @GET + @Path("mappings") + public Response listMappings() { + ObjectNode root = mapper().createObjectNode(); + + final Map intents = service.listMapping(); + ArrayNode arrayNode = root.putArray("mappings"); + intents.entrySet().forEach(i -> arrayNode.add(mapper().createObjectNode() + .put("host", i.getKey().toString()) + .put("ip", i.getValue().ipAddress().toString()))); + + return ok(root.toString()).build(); + } + + + + /** + * Get all available IPs. + * Shows all the IPs in the free pool of the DHCP Server. + * + * @return 200 OK + */ + @GET + @Path("available") + public Response listAvailableIPs() { + final Iterable availableIPList = service.getAvailableIPs(); + + final ObjectNode root = mapper().createObjectNode(); + ArrayNode arrayNode = root.putArray("availableIP"); + availableIPList.forEach(i -> arrayNode.add(i.toString())); + return ok(root.toString()).build(); + } + + /** + * Post a new static MAC/IP binding. + * Registers a static binding to the DHCP server, and displays the current set of bindings. + * + * @param stream JSON stream + * @return 200 OK + */ + @POST + @Path("mappings") + @Consumes(MediaType.APPLICATION_JSON) + public Response setMapping(InputStream stream) { + ObjectNode root = mapper().createObjectNode(); + + try { + ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream); + JsonNode macID = jsonTree.get("mac"); + JsonNode ip = jsonTree.get("ip"); + if (macID != null && ip != null) { + + if (!service.setStaticMapping(MacAddress.valueOf(macID.asText()), + Ip4Address.valueOf(ip.asText()))) { + throw new IllegalArgumentException("Static Mapping Failed. The IP maybe unavailable."); + } + } + + final Map intents = service.listMapping(); + ArrayNode arrayNode = root.putArray("mappings"); + intents.entrySet().forEach(i -> arrayNode.add(mapper().createObjectNode() + .put("host", i.getKey().toString()) + .put("ip", i.getValue().ipAddress().toString()))); + } catch (IOException e) { + throw new IllegalArgumentException(e.getMessage()); + } + return ok(root.toString()).build(); + } + + /** + * Delete a static MAC/IP binding. + * Removes a static binding from the DHCP Server, and displays the current set of bindings. + * + * @param macID mac address identifier + * @return 200 OK + */ + @DELETE + @Path("mappings/{macID}") + public Response deleteMapping(@PathParam("macID") String macID) { + + ObjectNode root = mapper().createObjectNode(); + + if (!service.removeStaticMapping(MacAddress.valueOf(macID))) { + throw new IllegalArgumentException("Static Mapping Removal Failed."); + } + final Map intents = service.listMapping(); + ArrayNode arrayNode = root.putArray("mappings"); + intents.entrySet().forEach(i -> arrayNode.add(mapper().createObjectNode() + .put("host", i.getKey().toString()) + .put("ip", i.getValue().ipAddress().toString()))); + + return ok(root.toString()).build(); + } +} diff --git a/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/rest/package-info.java b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/rest/package-info.java new file mode 100644 index 00000000..73173c55 --- /dev/null +++ b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/rest/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. + */ + +/** + * REST APIs for sample application that assigns and manages DHCP leases. + */ +package org.onosproject.dhcp.rest; \ No newline at end of file diff --git a/framework/src/onos/apps/dhcp/app/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/framework/src/onos/apps/dhcp/app/src/main/resources/OSGI-INF/blueprint/shell-config.xml new file mode 100644 index 00000000..ce716315 --- /dev/null +++ b/framework/src/onos/apps/dhcp/app/src/main/resources/OSGI-INF/blueprint/shell-config.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/framework/src/onos/apps/dhcp/app/src/main/resources/app/view/dhcp/dhcp.css b/framework/src/onos/apps/dhcp/app/src/main/resources/app/view/dhcp/dhcp.css new file mode 100644 index 00000000..e0a29314 --- /dev/null +++ b/framework/src/onos/apps/dhcp/app/src/main/resources/app/view/dhcp/dhcp.css @@ -0,0 +1,27 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 -- DHCP Server -- CSS file + */ + +#ov-dhcp h2 { + display: inline-block; +} + +#ov-dhcp div.ctrl-btns { + width: 45px; +} diff --git a/framework/src/onos/apps/dhcp/app/src/main/resources/app/view/dhcp/dhcp.html b/framework/src/onos/apps/dhcp/app/src/main/resources/app/view/dhcp/dhcp.html new file mode 100644 index 00000000..5782badf --- /dev/null +++ b/framework/src/onos/apps/dhcp/app/src/main/resources/app/view/dhcp/dhcp.html @@ -0,0 +1,47 @@ + +
+
+

DHCP Mappings ({{tableData.length}} total)

+
+
+
+
+ +
+
+ +
+ + + + + + +
Host IDIP AddressLease Expiry
+
+ +
+ + + + + + + + + + +
+ No mappings found +
{{dhcp.host}}{{dhcp.ip}}{{dhcp.lease}}
+
+ +
+ +
diff --git a/framework/src/onos/apps/dhcp/app/src/main/resources/app/view/dhcp/dhcp.js b/framework/src/onos/apps/dhcp/app/src/main/resources/app/view/dhcp/dhcp.js new file mode 100644 index 00000000..061d0de6 --- /dev/null +++ b/framework/src/onos/apps/dhcp/app/src/main/resources/app/view/dhcp/dhcp.js @@ -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. + */ + +/* + ONOS GUI -- DHCP Server View Module + */ + +(function () { + 'use strict'; + + // injected refs + var $log, $scope; + + angular.module('ovDhcp', []) + .controller('OvDhcpCtrl', + ['$log', '$scope', 'TableBuilderService', + + function (_$log_, _$scope_, tbs) { + $log = _$log_; + $scope = _$scope_; + + function selCb($event, row) { + $log.debug('Got a click on:', row); + } + + tbs.buildTable({ + scope: $scope, + tag: 'dhcp', + selCb: selCb + }); + + $scope.$on('$destroy', function () { + $log.debug('OvDhcpCtrl has been destroyed'); + }); + + $log.log('OvDhcpCtrl has been created'); + }]); +}()); \ No newline at end of file diff --git a/framework/src/onos/apps/dhcp/app/src/main/resources/gui/css.html b/framework/src/onos/apps/dhcp/app/src/main/resources/gui/css.html new file mode 100644 index 00000000..d02ad44a --- /dev/null +++ b/framework/src/onos/apps/dhcp/app/src/main/resources/gui/css.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/framework/src/onos/apps/dhcp/app/src/main/resources/gui/js.html b/framework/src/onos/apps/dhcp/app/src/main/resources/gui/js.html new file mode 100644 index 00000000..d37b5768 --- /dev/null +++ b/framework/src/onos/apps/dhcp/app/src/main/resources/gui/js.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/framework/src/onos/apps/dhcp/app/src/main/webapp/WEB-INF/web.xml b/framework/src/onos/apps/dhcp/app/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000..27504548 --- /dev/null +++ b/framework/src/onos/apps/dhcp/app/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,43 @@ + + + + DHCP Server REST API v1.0 + + + JAX-RS Service + com.sun.jersey.spi.container.servlet.ServletContainer + + com.sun.jersey.config.property.resourceConfigClass + com.sun.jersey.api.core.ClassNamesResourceConfig + + + com.sun.jersey.config.property.classnames + + org.onosproject.dhcp.rest.DHCPWebResource + + + 1 + + + + JAX-RS Service + /* + + diff --git a/framework/src/onos/apps/dhcp/app/src/test/java/org/onosproject/dhcp/impl/DhcpManagerTest.java b/framework/src/onos/apps/dhcp/app/src/test/java/org/onosproject/dhcp/impl/DhcpManagerTest.java new file mode 100644 index 00000000..fd4701c6 --- /dev/null +++ b/framework/src/onos/apps/dhcp/app/src/test/java/org/onosproject/dhcp/impl/DhcpManagerTest.java @@ -0,0 +1,392 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.dhcp.impl; + +import com.google.common.collect.ImmutableSet; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.onlab.packet.DHCP; +import org.onlab.packet.DHCPOption; +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; +import org.onosproject.dhcp.DhcpStore; +import org.onosproject.dhcp.IpAssignment; +import org.onosproject.net.Host; +import org.onosproject.net.HostId; +import org.onosproject.net.config.NetworkConfigRegistryAdapter; +import org.onosproject.net.host.HostDescription; +import org.onosproject.net.host.HostProvider; +import org.onosproject.net.host.HostProviderRegistry; +import org.onosproject.net.host.HostProviderService; +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.AbstractProvider; +import org.onosproject.net.provider.AbstractProviderService; +import org.onosproject.net.provider.ProviderId; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.onosproject.net.NetTestTools.connectPoint; + +/** + * Set of tests of the ONOS application component. + */ + +public class DhcpManagerTest { + + private DhcpManager dhcpXManager; + + protected PacketProcessor packetProcessor; + + protected HostProviderService hostProviderService; + + private static final HostId CLIENT1_HOST = HostId.hostId(MacAddress.valueOf("1a:1a:1a:1a:1a:1a")); + + private static final String EXPECTED_IP = "10.2.0.2"; + + private static final Ip4Address BROADCAST = Ip4Address.valueOf("255.255.255.255"); + + private static final int TRANSACTION_ID = 1000; + + private static final ProviderId PID = new ProviderId("of", "foo"); + + @Before + public void setUp() { + dhcpXManager = new DhcpManager(); + dhcpXManager.cfgService = new TestNetworkConfigRegistry(); + dhcpXManager.packetService = new TestPacketService(); + dhcpXManager.coreService = new TestCoreService(); + dhcpXManager.dhcpStore = new TestDhcpStore(); + hostProviderService = new TestHostProviderService(new TestHostProvider()); + dhcpXManager.hostProviderService = hostProviderService; + dhcpXManager.hostProviderRegistry = new TestHostRegistry(); + dhcpXManager.activate(); + } + + @After + public void tearDown() { + dhcpXManager.deactivate(); + } + + /** + * Tests the response to a DHCP Discover Packet. + */ + @Test + public void testDiscover() { + Ethernet reply = constructDHCPPacket(DHCPPacketType.DHCPDISCOVER); + sendPacket(reply); + } + + /** + * Tests the response to a DHCP Request Packet. + */ + @Test + public void testRequest() { + Ethernet reply = constructDHCPPacket(DHCPPacketType.DHCPREQUEST); + sendPacket(reply); + } + + /** + * 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 DHCP Payload. + * @param packetType DHCP Message Type + * @return Ethernet packet + */ + private Ethernet constructDHCPPacket(DHCPPacketType packetType) { + + // Ethernet Frame. + Ethernet ethReply = new Ethernet(); + ethReply.setSourceMACAddress(CLIENT1_HOST.mac()); + ethReply.setDestinationMACAddress(MacAddress.BROADCAST); + ethReply.setEtherType(Ethernet.TYPE_IPV4); + ethReply.setVlanID((short) 2); + + // IP Packet + IPv4 ipv4Reply = new IPv4(); + ipv4Reply.setSourceAddress(0); + ipv4Reply.setDestinationAddress(BROADCAST.toInt()); + ipv4Reply.setTtl((byte) 127); + + // UDP Datagram. + UDP udpReply = new UDP(); + udpReply.setSourcePort((byte) UDP.DHCP_CLIENT_PORT); + udpReply.setDestinationPort((byte) UDP.DHCP_SERVER_PORT); + + // DHCP Payload. + DHCP dhcpReply = new DHCP(); + dhcpReply.setOpCode(DHCP.OPCODE_REQUEST); + + dhcpReply.setYourIPAddress(0); + dhcpReply.setServerIPAddress(0); + + dhcpReply.setTransactionId(TRANSACTION_ID); + dhcpReply.setClientHardwareAddress(CLIENT1_HOST.mac().toBytes()); + dhcpReply.setHardwareType(DHCP.HWTYPE_ETHERNET); + dhcpReply.setHardwareAddressLength((byte) 6); + + // DHCP Options. + DHCPOption option = new DHCPOption(); + List optionList = new ArrayList<>(); + + // DHCP Message Type. + option.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue()); + option.setLength((byte) 1); + byte[] optionData = {(byte) packetType.getValue()}; + option.setData(optionData); + optionList.add(option); + + // DHCP Requested IP. + option = new DHCPOption(); + option.setCode(DHCP.DHCPOptionCode.OptionCode_RequestedIP.getValue()); + option.setLength((byte) 4); + optionData = Ip4Address.valueOf(EXPECTED_IP).toOctets(); + option.setData(optionData); + optionList.add(option); + + // End Option. + option = new DHCPOption(); + option.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue()); + option.setLength((byte) 1); + optionList.add(option); + + dhcpReply.setOptions(optionList); + + udpReply.setPayload(dhcpReply); + ipv4Reply.setPayload(udpReply); + ethReply.setPayload(ipv4Reply); + + return ethReply; + } + + /** + * Validates the contents of the packet sent by the DHCP Manager. + * @param packet Ethernet packet received + */ + private void validatePacket(Ethernet packet) { + DHCP dhcpPacket = (DHCP) packet.getPayload().getPayload().getPayload(); + assertEquals(MacAddress.valueOf(dhcpPacket.getClientHardwareAddress()), CLIENT1_HOST.mac()); + assertEquals(Ip4Address.valueOf(dhcpPacket.getYourIPAddress()), Ip4Address.valueOf(EXPECTED_IP)); + assertEquals(dhcpPacket.getTransactionId(), TRANSACTION_ID); + } + + /** + * Mocks the DHCPStore. + */ + private final class TestDhcpStore implements DhcpStore { + + + public void populateIPPoolfromRange(Ip4Address startIP, Ip4Address endIP) { + } + + public Ip4Address suggestIP(HostId hostId, Ip4Address requestedIP) { + return Ip4Address.valueOf(EXPECTED_IP); + } + + public boolean assignIP(HostId hostId, Ip4Address ipAddr, int leaseTime) { + return true; + } + + public void setDefaultTimeoutForPurge(int timeInSeconds) { + } + + public Ip4Address releaseIP(HostId hostId) { + return null; + } + + public Map listAssignedMapping() { + return listAllMapping(); + } + + public Map listAllMapping() { + Map map = new HashMap<>(); + IpAssignment assignment = IpAssignment.builder() + .ipAddress(Ip4Address.valueOf(EXPECTED_IP)) + .assignmentStatus(IpAssignment.AssignmentStatus.Option_Assigned) + .leasePeriod(300) + .timestamp(new Date()) + .build(); + map.put(CLIENT1_HOST, assignment); + return map; + } + + public boolean assignStaticIP(MacAddress macID, Ip4Address ipAddr) { + return true; + } + + public boolean removeStaticIP(MacAddress macID) { + return true; + } + + public Iterable getAvailableIPs() { + List ipList = new ArrayList<>(); + ipList.add(Ip4Address.valueOf(EXPECTED_IP)); + return ImmutableSet.copyOf(ipList); + } + } + + /** + * Mocks the DefaultPacket context. + */ + 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. + } + } + + /** + * Keeps a reference to the PacketProcessor and verifies the OutboundPackets. + */ + private class TestPacketService 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); + validatePacket(eth); + } catch (Exception e) { + fail(e.getMessage()); + } + } + } + + /** + * Mocks the CoreService. + */ + private class TestCoreService extends CoreServiceAdapter { + + } + + /** + * Mocks the NetworkConfigRegistry. + */ + private class TestNetworkConfigRegistry extends NetworkConfigRegistryAdapter { + + } + + /** + * Mocks the HostProviderService. + */ + private class TestHostProviderService extends AbstractProviderService + implements HostProviderService { + + protected TestHostProviderService(HostProvider provider) { + super(provider); + } + + @Override + public void hostDetected(HostId hostId, HostDescription hostDescription, boolean replaceIps) { + + } + + @Override + public void hostVanished(HostId hostId) { + } + + @Override + public void removeIpFromHost(HostId hostId, IpAddress ipAddress) { + + } + + } + + /** + * Mocks the HostProvider. + */ + private static class TestHostProvider extends AbstractProvider + implements HostProvider { + + protected TestHostProvider() { + super(PID); + } + + @Override + public ProviderId id() { + return PID; + } + + @Override + public void triggerProbe(Host host) { + } + + } + + /** + * Mocks the HostProviderRegistry. + */ + private class TestHostRegistry implements HostProviderRegistry { + + @Override + public HostProviderService register(HostProvider provider) { + return hostProviderService; + } + + @Override + public void unregister(HostProvider provider) { + } + + @Override + public Set getProviders() { + return null; + } + + } + +} diff --git a/framework/src/onos/apps/dhcp/app/src/test/resources/dhcp-cfg.json b/framework/src/onos/apps/dhcp/app/src/test/resources/dhcp-cfg.json new file mode 100644 index 00000000..abc48a83 --- /dev/null +++ b/framework/src/onos/apps/dhcp/app/src/test/resources/dhcp-cfg.json @@ -0,0 +1,22 @@ +{ + "apps": { + "org.onosproject.dhcp" : { + "dhcp" : { + "ip": "10.0.0.1", + "mac": "1a:2b:3c:4e:5e:6f", + "subnet": "255.0.0.0", + "broadcast": "10.255.255.255", + "router": "10.0.0.1", + "domain": "10.0.0.1", + "ttl": "63", + "lease": "300", + "renew": "150", + "rebind": "200", + "delay": "3", + "timeout": "150", + "startip": "10.0.0.110", + "endip": "10.0.0.130" + } + } + } +} \ No newline at end of file diff --git a/framework/src/onos/apps/dhcp/pom.xml b/framework/src/onos/apps/dhcp/pom.xml index 0daa4f7b..7a10776e 100644 --- a/framework/src/onos/apps/dhcp/pom.xml +++ b/framework/src/onos/apps/dhcp/pom.xml @@ -13,149 +13,30 @@ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ~ See the License for the specific language governing permissions and ~ limitations under the License. - --> + --> + 4.0.0 - onos-apps org.onosproject + onos-apps 1.4.0-SNAPSHOT ../pom.xml - onos-app-dhcp - bundle - - http://onosproject.org + onos-dhcp + pom - DHCP Server application + ONOS sample applications - - org.onosproject.dhcp - /onos/dhcp - 1.0.0 - DHCP Server REST API - - APIs for interacting with the DHCP Server application. - - org.onosproject.dhcp.rest - + + api + app + - - org.osgi - org.osgi.compendium - - - - org.onosproject - onos-cli - ${project.version} - - - - org.apache.karaf.shell - org.apache.karaf.shell.console - compile - - - - org.onosproject - onlab-junit - test - - - org.onosproject - onos-core-serializers - ${project.version} - - - - org.onosproject - onos-incubator-api - ${project.version} - - - org.onosproject - onos-api - ${project.version} - tests - test - - - - org.onosproject - onos-rest - ${project.version} - - - org.onosproject - onlab-rest - ${project.version} - - - javax.ws.rs - jsr311-api - 1.1.1 - - - com.sun.jersey - jersey-servlet - - - com.fasterxml.jackson.core - jackson-databind - - - - com.fasterxml.jackson.core - jackson-annotations - - - - - org.apache.felix - maven-bundle-plugin - true - - - <_wab>src/main/webapp/ - - WEB-INF/classes/apidoc/swagger.json=target/swagger.json, - {maven-resources} - - - ${project.groupId}.${project.artifactId} - - - org.slf4j, - org.osgi.framework, - javax.ws.rs, - javax.ws.rs.core, - com.sun.jersey.api.core, - com.sun.jersey.spi.container.servlet, - com.sun.jersey.server.impl.container.servlet, - com.fasterxml.jackson.databind, - com.fasterxml.jackson.databind.node, - com.fasterxml.jackson.core, - org.apache.karaf.shell.commands, - org.apache.karaf.shell.console, - com.google.common.*, - org.onlab.packet.*, - org.onlab.rest.*, - org.onosproject.*, - org.onlab.util.*, - org.jboss.netty.util.* - - ${web.context} - - - - - - diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/DhcpService.java b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/DhcpService.java deleted file mode 100644 index 7c2127f9..00000000 --- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/DhcpService.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.onosproject.dhcp; - -import org.onlab.packet.Ip4Address; -import org.onlab.packet.MacAddress; -import org.onosproject.net.HostId; - -import java.util.Map; - -/** - * DHCP Service Interface. - */ -public interface DhcpService { - - /** - * Returns a collection of all the MacAddress to IPAddress mapping. - * - * @return collection of mappings. - */ - Map listMapping(); - - /** - * Returns the default lease time granted by the DHCP Server. - * - * @return lease time - */ - int getLeaseTime(); - - /** - * Returns the default renewal time granted by the DHCP Server. - * - * @return renewal time - */ - int getRenewalTime(); - - /** - * Returns the default rebinding time granted by the DHCP Server. - * - * @return rebinding time - */ - int getRebindingTime(); - - /** - * Registers a static IP mapping with the DHCP Server. - * - * @param macID macID of the client - * @param ipAddress IP Address requested for the client - * @return true if the mapping was successfully registered, false otherwise - */ - boolean setStaticMapping(MacAddress macID, Ip4Address ipAddress); - - /** - * Removes a static IP mapping with the DHCP Server. - * - * @param macID macID of the client - * @return true if the mapping was successfully removed, false otherwise - */ - boolean removeStaticMapping(MacAddress macID); - - /** - * Returns the list of all the available IPs with the server. - * - * @return list of available IPs - */ - Iterable getAvailableIPs(); - -} 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 deleted file mode 100644 index e263b3a2..00000000 --- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/DhcpStore.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.onosproject.dhcp; - -import org.onlab.packet.Ip4Address; -import org.onlab.packet.MacAddress; -import org.onosproject.net.HostId; - -import java.util.Map; - -/** - * DHCPStore Interface. - */ -public interface DhcpStore { - - /** - * Appends all the IPs in a given range to the free pool of IPs. - * - * @param startIP Start IP for the range - * @param endIP End IP for the range - */ - void populateIPPoolfromRange(Ip4Address startIP, Ip4Address endIP); - - /** - * Returns an IP Address for a Mac ID, in response to a DHCP DISCOVER message. - * - * @param hostId Host ID of the client requesting an IP - * @param requestedIP requested IP address - * @return IP address assigned to the Mac ID - */ - Ip4Address suggestIP(HostId hostId, Ip4Address requestedIP); - - /** - * Assigns the requested IP to the Mac ID, in response to a DHCP REQUEST message. - * - * @param hostId Host Id of the client requesting an IP - * @param ipAddr IP Address being requested - * @param leaseTime Lease time offered by the server for this mapping - * @return returns true if the assignment was successful, false otherwise - */ - boolean assignIP(HostId hostId, Ip4Address ipAddr, int leaseTime); - - /** - * Sets the default time for which suggested IP mappings are valid. - * - * @param timeInSeconds default time for IP mappings to be valid - */ - void setDefaultTimeoutForPurge(int timeInSeconds); - - /** - * Releases the IP assigned to a Mac ID into the free pool. - * - * @param hostId the host ID for which the mapping needs to be changed - * @return released ip - */ - Ip4Address releaseIP(HostId hostId); - - /** - * Returns a collection of all the MacAddress to IPAddress mapping assigned to the hosts. - * - * @return the collection of the mappings - */ - Map listAssignedMapping(); - - /** - * Returns a collection of all the MacAddress to IPAddress mapping. - * - * @return the collection of the mappings - */ - Map listAllMapping(); - - /** - * Assigns the requested IP to the MAC ID (if available) for an indefinite period of time. - * - * @param macID macID of the client - * @param ipAddr IP Address requested for the client - * @return true if the mapping was successfully registered, false otherwise - */ - boolean assignStaticIP(MacAddress macID, Ip4Address ipAddr); - - /** - * Removes a static IP mapping associated with the given MAC ID from the DHCP Server. - * - * @param macID macID of the client - * @return true if the mapping was successfully registered, false otherwise - */ - boolean removeStaticIP(MacAddress macID); - - /** - * Returns the list of all the available IPs with the server. - * - * @return list of available IPs - */ - Iterable getAvailableIPs(); - -} diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/IpAssignment.java b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/IpAssignment.java deleted file mode 100644 index 9b3aa686..00000000 --- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/IpAssignment.java +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.onosproject.dhcp; - -import com.google.common.base.MoreObjects; -import org.onlab.packet.Ip4Address; - -import java.util.Date; - -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * Stores the MAC ID to IP Address mapping details. - */ -public final class IpAssignment { - - private final Ip4Address ipAddress; - - private final Date timestamp; - - private final long leasePeriod; - - private final AssignmentStatus assignmentStatus; - - public enum AssignmentStatus { - /** - * IP has been requested by a host, but not assigned to it yet. - */ - Option_Requested, - - /** - * IP has been assigned to a host. - */ - Option_Assigned, - - /** - * IP mapping is no longer active. - */ - Option_Expired - } - - /** - * Constructor for IPAssignment, where the ipAddress, the lease period, the timestamp - * and assignment status is supplied. - * - * @param ipAddress - * @param leasePeriod - * @param assignmentStatus - */ - private IpAssignment(Ip4Address ipAddress, - long leasePeriod, - Date timestamp, - AssignmentStatus assignmentStatus) { - this.ipAddress = ipAddress; - this.leasePeriod = leasePeriod; - this.timestamp = timestamp; - this.assignmentStatus = assignmentStatus; - } - - /** - * Returns the IP Address of the IP assignment. - * - * @return the IP address - */ - public Ip4Address ipAddress() { - return this.ipAddress; - } - - /** - * Returns the timestamp of the IP assignment. - * - * @return the timestamp - */ - public Date timestamp() { - return this.timestamp; - } - - /** - * Returns the assignment status of the IP assignment. - * - * @return the assignment status - */ - public AssignmentStatus assignmentStatus() { - return this.assignmentStatus; - } - - /** - * Returns the lease period of the IP assignment. - * - * @return the lease period in seconds - */ - public int leasePeriod() { - return (int) this.leasePeriod; - } - - /** - * Returns the lease period of the IP assignment. - * - * @return the lease period in milliseconds - */ - public int leasePeriodMs() { - return (int) this.leasePeriod * 1000; - } - - @Override - public String toString() { - return MoreObjects.toStringHelper(getClass()) - .add("ip", ipAddress) - .add("timestamp", timestamp) - .add("lease", leasePeriod) - .add("assignmentStatus", assignmentStatus) - .toString(); - } - - /** - * Creates and returns a new builder instance. - * - * @return new builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Creates and returns a new builder instance that clones an existing IPAssignment. - * - * @param assignment ip address assignment - * @return new builder - */ - public static Builder builder(IpAssignment assignment) { - return new Builder(assignment); - } - - /** - * IPAssignment Builder. - */ - public static final class Builder { - - private Ip4Address ipAddress; - - private Date timeStamp; - - private long leasePeriod; - - private AssignmentStatus assignmentStatus; - - private Builder() { - - } - - private Builder(IpAssignment ipAssignment) { - ipAddress = ipAssignment.ipAddress(); - timeStamp = ipAssignment.timestamp(); - leasePeriod = ipAssignment.leasePeriod(); - assignmentStatus = ipAssignment.assignmentStatus(); - } - - public IpAssignment build() { - validateInputs(); - return new IpAssignment(ipAddress, - leasePeriod, - timeStamp, - assignmentStatus); - } - - public Builder ipAddress(Ip4Address addr) { - ipAddress = addr; - return this; - } - - public Builder timestamp(Date timestamp) { - timeStamp = timestamp; - return this; - } - - public Builder leasePeriod(int leasePeriodinSeconds) { - leasePeriod = leasePeriodinSeconds; - return this; - } - - public Builder assignmentStatus(AssignmentStatus status) { - assignmentStatus = status; - return this; - } - - private void validateInputs() { - checkNotNull(ipAddress, "IP Address must be specified"); - checkNotNull(assignmentStatus, "Assignment Status must be specified"); - checkNotNull(leasePeriod, "Lease Period must be specified"); - checkNotNull(timeStamp, "Timestamp must be specified"); - - switch (assignmentStatus) { - case Option_Requested: - case Option_Assigned: - case Option_Expired: - break; - default: - throw new IllegalStateException("Unknown assignment status"); - } - } - } -} diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpLeaseDetails.java b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpLeaseDetails.java deleted file mode 100644 index 95f49e69..00000000 --- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpLeaseDetails.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.onosproject.dhcp.cli; - -import org.apache.karaf.shell.commands.Command; -import org.onosproject.cli.AbstractShellCommand; -import org.onosproject.dhcp.DhcpService; - -/** - * Lists all the default lease parameters offered by the DHCP Server. - */ -@Command(scope = "onos", name = "dhcp-lease", - description = "Lists all the default lease parameters offered by the DHCP Server") -public class DhcpLeaseDetails extends AbstractShellCommand { - - private static final String DHCP_LEASE_FORMAT = "Lease Time: %ds\nRenewal Time: %ds\nRebinding Time: %ds"; - - @Override - protected void execute() { - - DhcpService dhcpService = AbstractShellCommand.get(DhcpService.class); - int leaseTime = dhcpService.getLeaseTime(); - int renewTime = dhcpService.getRenewalTime(); - int rebindTime = dhcpService.getRebindingTime(); - - print(DHCP_LEASE_FORMAT, leaseTime, renewTime, rebindTime); - } -} diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpListAllMappings.java b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpListAllMappings.java deleted file mode 100644 index 209ba683..00000000 --- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpListAllMappings.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.onosproject.dhcp.cli; - -import org.apache.karaf.shell.commands.Command; -import org.onosproject.cli.AbstractShellCommand; -import org.onosproject.dhcp.DhcpService; -import org.onosproject.dhcp.IpAssignment; -import org.onosproject.net.HostId; - -import java.util.Map; - -/** - * Lists all the MacAddress to IP Address mappings held by the DHCP Server. - */ -@Command(scope = "onos", name = "dhcp-list", - description = "Lists all the MAC to IP mappings held by the DHCP Server") -public class DhcpListAllMappings extends AbstractShellCommand { - - private static final String DHCP_MAPPING_FORMAT = "MAC ID: %s -> IP ASSIGNED %s"; - @Override - protected void execute() { - - DhcpService dhcpService = AbstractShellCommand.get(DhcpService.class); - Map allocationMap = dhcpService.listMapping(); - - for (Map.Entry entry : allocationMap.entrySet()) { - print(DHCP_MAPPING_FORMAT, entry.getKey().toString(), entry.getValue().ipAddress().toString()); - } - } -} diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpRemoveStaticMapping.java b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpRemoveStaticMapping.java deleted file mode 100644 index a92cd250..00000000 --- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpRemoveStaticMapping.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.onosproject.dhcp.cli; - -import org.apache.karaf.shell.commands.Argument; -import org.apache.karaf.shell.commands.Command; -import org.onlab.packet.MacAddress; -import org.onosproject.cli.AbstractShellCommand; -import org.onosproject.dhcp.DhcpService; - -/** - * Removes a static MAC Address to IP Mapping from the DHCP Server. - */ -@Command(scope = "onos", name = "dhcp-remove-static-mapping", - description = "Removes a static MAC Address to IP Mapping from the DHCP Server") -public class DhcpRemoveStaticMapping extends AbstractShellCommand { - - @Argument(index = 0, name = "macAddr", - description = "MAC Address of the client", - required = true, multiValued = false) - String macAddr = null; - - private static final String DHCP_SUCCESS = "Static Mapping Successfully Removed."; - private static final String DHCP_FAILURE = "Static Mapping Removal Failed. " + - "Either the mapping does not exist or it is not static."; - - @Override - protected void execute() { - DhcpService dhcpService = AbstractShellCommand.get(DhcpService.class); - - try { - MacAddress macID = MacAddress.valueOf(macAddr); - if (dhcpService.removeStaticMapping(macID)) { - print(DHCP_SUCCESS); - } else { - print(DHCP_FAILURE); - } - - } catch (IllegalArgumentException e) { - print(e.getMessage()); - } - } -} diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpSetStaticMapping.java b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpSetStaticMapping.java deleted file mode 100644 index 9f4f6580..00000000 --- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpSetStaticMapping.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.onosproject.dhcp.cli; - -import org.apache.karaf.shell.commands.Argument; -import org.apache.karaf.shell.commands.Command; -import org.onlab.packet.Ip4Address; -import org.onlab.packet.MacAddress; -import org.onosproject.cli.AbstractShellCommand; -import org.onosproject.dhcp.DhcpService; - -/** - * Registers a static MAC Address to IP Mapping with the DHCP Server. - */ -@Command(scope = "onos", name = "dhcp-set-static-mapping", - description = "Registers a static MAC Address to IP Mapping with the DHCP Server") -public class DhcpSetStaticMapping extends AbstractShellCommand { - - @Argument(index = 0, name = "macAddr", - description = "MAC Address of the client", - required = true, multiValued = false) - String macAddr = null; - - @Argument(index = 1, name = "ipAddr", - description = "IP Address requested for static mapping", - required = true, multiValued = false) - String ipAddr = null; - - private static final String DHCP_SUCCESS = "Static Mapping Successfully Added."; - private static final String DHCP_FAILURE = "Static Mapping Failed. The IP maybe unavailable."; - @Override - protected void execute() { - DhcpService dhcpService = AbstractShellCommand.get(DhcpService.class); - - try { - MacAddress macID = MacAddress.valueOf(macAddr); - Ip4Address ipAddress = Ip4Address.valueOf(ipAddr); - if (dhcpService.setStaticMapping(macID, ipAddress)) { - print(DHCP_SUCCESS); - } else { - print(DHCP_FAILURE); - } - - } catch (IllegalArgumentException e) { - print(e.getMessage()); - } - } -} diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/FreeIpCompleter.java b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/FreeIpCompleter.java deleted file mode 100644 index 228d70fd..00000000 --- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/FreeIpCompleter.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.onosproject.dhcp.cli; - -import org.apache.karaf.shell.console.Completer; -import org.apache.karaf.shell.console.completer.StringsCompleter; -import org.onlab.packet.Ip4Address; -import org.onosproject.cli.AbstractShellCommand; -import org.onosproject.dhcp.DhcpService; - -import java.util.Iterator; -import java.util.List; -import java.util.SortedSet; - -/** - * Free IP Completer. - */ -public class FreeIpCompleter implements Completer { - - @Override - public int complete(String buffer, int cursor, List candidates) { - // Delegate string completer - StringsCompleter delegate = new StringsCompleter(); - DhcpService dhcpService = AbstractShellCommand.get(DhcpService.class); - Iterator it = dhcpService.getAvailableIPs().iterator(); - SortedSet strings = delegate.getStrings(); - - while (it.hasNext()) { - strings.add(it.next().toString()); - } - - // Now let the completer do the work for figuring out what to offer. - return delegate.complete(buffer, cursor, candidates); - } -} diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/MacIdCompleter.java b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/MacIdCompleter.java deleted file mode 100644 index d6cd73a7..00000000 --- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/MacIdCompleter.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.onosproject.dhcp.cli; - -import org.apache.karaf.shell.console.Completer; -import org.apache.karaf.shell.console.completer.StringsCompleter; -import org.onosproject.cli.AbstractShellCommand; -import org.onosproject.net.Host; -import org.onosproject.net.host.HostService; - -import java.util.Iterator; -import java.util.List; -import java.util.SortedSet; - -/** - * MAC ID Completer. - */ -public class MacIdCompleter implements Completer { - - @Override - public int complete(String buffer, int cursor, List candidates) { - // Delegate string completer - StringsCompleter delegate = new StringsCompleter(); - HostService service = AbstractShellCommand.get(HostService.class); - Iterator it = service.getHosts().iterator(); - SortedSet strings = delegate.getStrings(); - - while (it.hasNext()) { - strings.add(it.next().mac().toString()); - } - - // Now let the completer do the work for figuring out what to offer. - return delegate.complete(buffer, cursor, candidates); - } -} diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/package-info.java b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/package-info.java deleted file mode 100644 index f8780195..00000000 --- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * CLI implementation for sample application that assigns and manages DHCP leases. - */ -package org.onosproject.dhcp.cli; \ No newline at end of file diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpConfig.java b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpConfig.java deleted file mode 100644 index 4353d623..00000000 --- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpConfig.java +++ /dev/null @@ -1,319 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.onosproject.dhcp.impl; - -import org.onlab.packet.Ip4Address; -import org.onlab.packet.MacAddress; -import org.onosproject.core.ApplicationId; -import org.onosproject.net.config.Config; -import org.onosproject.net.config.basics.BasicElementConfig; - -/** - * DHCP Config class. - */ -public class DhcpConfig extends Config { - - public static final String MY_IP = "ip"; - public static final String MY_MAC = "mac"; - public static final String SUBNET_MASK = "subnet"; - public static final String BROADCAST_ADDRESS = "broadcast"; - public static final String ROUTER_ADDRESS = "router"; - public static final String DOMAIN_SERVER = "domain"; - public static final String TTL = "ttl"; - public static final String LEASE_TIME = "lease"; - public static final String RENEW_TIME = "renew"; - public static final String REBIND_TIME = "rebind"; - public static final String TIMER_DELAY = "delay"; - public static final String DEFAULT_TIMEOUT = "timeout"; - public static final String START_IP = "startip"; - public static final String END_IP = "endip"; - - public static final int DEFAULT = -1; - - /** - * Returns the dhcp server ip. - * - * @return ip address or null if not set - */ - public Ip4Address ip() { - String ip = get(MY_IP, null); - return ip != null ? Ip4Address.valueOf(ip) : null; - } - - /** - * Sets the dhcp server ip. - * - * @param ip new ip address; null to clear - * @return self - */ - public BasicElementConfig ip(String ip) { - return (BasicElementConfig) setOrClear(MY_IP, ip); - } - - /** - * Returns the dhcp server mac. - * - * @return server mac or null if not set - */ - public MacAddress mac() { - String mac = get(MY_MAC, null); - return mac != null ? MacAddress.valueOf(mac) : null; - } - - /** - * Sets the dhcp server mac. - * - * @param mac new mac address; null to clear - * @return self - */ - public BasicElementConfig mac(String mac) { - return (BasicElementConfig) setOrClear(MY_MAC, mac); - } - - /** - * Returns the subnet mask. - * - * @return subnet mask or null if not set - */ - public Ip4Address subnetMask() { - String ip = get(SUBNET_MASK, null); - return ip != null ? Ip4Address.valueOf(ip) : null; - } - - /** - * Sets the subnet mask. - * - * @param subnet new subnet mask; null to clear - * @return self - */ - public BasicElementConfig subnetMask(String subnet) { - return (BasicElementConfig) setOrClear(SUBNET_MASK, subnet); - } - - /** - * Returns the broadcast address. - * - * @return broadcast address or null if not set - */ - public Ip4Address broadcastAddress() { - String ip = get(BROADCAST_ADDRESS, null); - return ip != null ? Ip4Address.valueOf(ip) : null; - } - - /** - * Sets the broadcast address. - * - * @param broadcast new broadcast address; null to clear - * @return self - */ - public BasicElementConfig broadcastAddress(String broadcast) { - return (BasicElementConfig) setOrClear(BROADCAST_ADDRESS, broadcast); - } - - /** - * Returns the Time To Live for the reply packets. - * - * @return ttl or -1 if not set - */ - public int ttl() { - return get(TTL, DEFAULT); - } - - /** - * Sets the Time To Live for the reply packets. - * - * @param ttl new ttl; null to clear - * @return self - */ - public BasicElementConfig ttl(int ttl) { - return (BasicElementConfig) setOrClear(TTL, ttl); - } - - /** - * Returns the Lease Time offered by the DHCP Server. - * - * @return lease time or -1 if not set - */ - public int leaseTime() { - return get(LEASE_TIME, DEFAULT); - } - - /** - * Sets the Lease Time offered by the DHCP Server. - * - * @param lease new lease time; null to clear - * @return self - */ - public BasicElementConfig leaseTime(int lease) { - return (BasicElementConfig) setOrClear(LEASE_TIME, lease); - } - - /** - * Returns the Renew Time offered by the DHCP Server. - * - * @return renew time or -1 if not set - */ - public int renewTime() { - return get(RENEW_TIME, DEFAULT); - } - - /** - * Sets the Renew Time offered by the DHCP Server. - * - * @param renew new renew time; null to clear - * @return self - */ - public BasicElementConfig renewTime(int renew) { - return (BasicElementConfig) setOrClear(RENEW_TIME, renew); - } - - /** - * Returns the Rebind Time offered by the DHCP Server. - * - * @return rebind time or -1 if not set - */ - public int rebindTime() { - return get(REBIND_TIME, DEFAULT); - } - - /** - * Sets the Rebind Time offered by the DHCP Server. - * - * @param rebind new rebind time; null to clear - * @return self - */ - public BasicElementConfig rebindTime(int rebind) { - return (BasicElementConfig) setOrClear(REBIND_TIME, rebind); - } - - /** - * Returns the Router Address. - * - * @return router address or null if not set - */ - public Ip4Address routerAddress() { - String ip = get(ROUTER_ADDRESS, null); - return ip != null ? Ip4Address.valueOf(ip) : null; - } - - /** - * Sets the Router Address. - * - * @param router new router address; null to clear - * @return self - */ - public BasicElementConfig routerAddress(String router) { - return (BasicElementConfig) setOrClear(ROUTER_ADDRESS, router); - } - - /** - * Returns the Domain Server Address. - * - * @return domain server address or null if not set - */ - public Ip4Address domainServer() { - String ip = get(DOMAIN_SERVER, null); - return ip != null ? Ip4Address.valueOf(ip) : null; - } - - /** - * Sets the Domain Server Address. - * - * @param domain new domain server address; null to clear - * @return self - */ - public BasicElementConfig domainServer(String domain) { - return (BasicElementConfig) setOrClear(DOMAIN_SERVER, domain); - } - - /** - * Returns the delay in minutes after which the dhcp server will purge expired entries. - * - * @return time delay or -1 if not set - */ - public int timerDelay() { - return get(TIMER_DELAY, DEFAULT); - } - - /** - * Sets the delay after which the dhcp server will purge expired entries. - * - * @param delay new time delay; null to clear - * @return self - */ - public BasicElementConfig timerDelay(int delay) { - return (BasicElementConfig) setOrClear(TIMER_DELAY, delay); - } - - /** - * Returns the default timeout for pending assignments. - * - * @return default timeout or -1 if not set - */ - public int defaultTimeout() { - return get(DEFAULT_TIMEOUT, DEFAULT); - } - - /** - * Sets the default timeout for pending assignments. - * - * @param defaultTimeout new default timeout; null to clear - * @return self - */ - public BasicElementConfig defaultTimeout(int defaultTimeout) { - return (BasicElementConfig) setOrClear(DEFAULT_TIMEOUT, defaultTimeout); - } - - /** - * Returns the start IP for the available IP Range. - * - * @return start IP or null if not set - */ - public Ip4Address startIp() { - String ip = get(START_IP, null); - return ip != null ? Ip4Address.valueOf(ip) : null; - } - - /** - * Sets the start IP for the available IP Range. - * - * @param startIp new start IP; null to clear - * @return self - */ - public BasicElementConfig startIp(String startIp) { - return (BasicElementConfig) setOrClear(START_IP, startIp); - } - - /** - * Returns the end IP for the available IP Range. - * - * @return end IP or null if not set - */ - public Ip4Address endIp() { - String ip = get(END_IP, null); - return ip != null ? Ip4Address.valueOf(ip) : null; - } - - /** - * Sets the end IP for the available IP Range. - * - * @param endIp new end IP; null to clear - * @return self - */ - public BasicElementConfig endIp(String endIp) { - return (BasicElementConfig) setOrClear(END_IP, endIp); - } -} 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 deleted file mode 100644 index 96d94a2b..00000000 --- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpManager.java +++ /dev/null @@ -1,699 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.onosproject.dhcp.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; -import org.apache.felix.scr.annotations.Reference; -import org.apache.felix.scr.annotations.ReferenceCardinality; -import org.apache.felix.scr.annotations.Service; -import org.jboss.netty.util.Timeout; -import org.jboss.netty.util.TimerTask; -import org.onlab.packet.ARP; -import org.onlab.packet.DHCP; -import org.onlab.packet.DHCPOption; -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.TpPort; -import org.onlab.packet.UDP; -import org.onlab.packet.VlanId; -import org.onlab.util.Timer; -import org.onosproject.core.ApplicationId; -import org.onosproject.core.CoreService; -import org.onosproject.dhcp.DhcpService; -import org.onosproject.dhcp.DhcpStore; -import org.onosproject.dhcp.IpAssignment; -import org.onosproject.net.ConnectPoint; -import org.onosproject.net.Host; -import org.onosproject.net.HostId; -import org.onosproject.net.HostLocation; -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; -import org.onosproject.net.flow.TrafficTreatment; -import org.onosproject.net.host.DefaultHostDescription; -import org.onosproject.net.host.HostProvider; -import org.onosproject.net.host.HostProviderRegistry; -import org.onosproject.net.host.HostProviderService; -import org.onosproject.net.packet.DefaultOutboundPacket; -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.onosproject.net.provider.AbstractProvider; -import org.onosproject.net.provider.ProviderId; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.TimeUnit; - -import static org.onlab.packet.MacAddress.valueOf; -import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY; - -/** - * Skeletal ONOS DHCP Server application. - */ -@Component(immediate = true) -@Service -public class DhcpManager implements DhcpService { - - private static final ProviderId PID = new ProviderId("of", "org.onosproject.dhcp", true); - private final Logger log = LoggerFactory.getLogger(getClass()); - - private final InternalConfigListener cfgListener = new InternalConfigListener(); - - private final Set factories = ImmutableSet.of( - new ConfigFactory(APP_SUBJECT_FACTORY, - DhcpConfig.class, - "dhcp") { - @Override - public DhcpConfig createConfig() { - return new DhcpConfig(); - } - } - ); - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected NetworkConfigRegistry cfgService; - - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected PacketService packetService; - - private DHCPPacketProcessor processor = new DHCPPacketProcessor(); - - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected CoreService coreService; - - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected DhcpStore dhcpStore; - - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected HostProviderRegistry hostProviderRegistry; - - protected HostProviderService hostProviderService; - - private final HostProvider hostProvider = new InternalHostProvider(); - - private ApplicationId appId; - - // Hardcoded values are default values. - - private static Ip4Address myIP = Ip4Address.valueOf("10.0.0.2"); - - private static MacAddress myMAC = valueOf("4f:4f:4f:4f:4f:4f"); - - /** - * leaseTime - 10 mins or 600s. - * renewalTime - 5 mins or 300s. - * rebindingTime - 6 mins or 360s. - */ - - private static int leaseTime = 600; - - private static int renewalTime = 300; - - private static int rebindingTime = 360; - - private static byte packetTTL = (byte) 127; - - private static Ip4Address subnetMask = Ip4Address.valueOf("255.0.0.0"); - - private static Ip4Address broadcastAddress = Ip4Address.valueOf("10.255.255.255"); - - private static Ip4Address routerAddress = Ip4Address.valueOf("10.0.0.2"); - - 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; - - @Activate - protected void activate() { - // start the dhcp server - appId = coreService.registerApplication("org.onosproject.dhcp"); - - cfgService.addListener(cfgListener); - factories.forEach(cfgService::registerConfigFactory); - cfgListener.reconfigureNetwork(cfgService.getConfig(appId, DhcpConfig.class)); - - hostProviderService = hostProviderRegistry.register(hostProvider); - packetService.addProcessor(processor, PacketProcessor.director(0)); - requestPackets(); - timeout = Timer.getTimer().newTimeout(new PurgeListTask(), timerDelay, TimeUnit.MINUTES); - log.info("Started"); - } - - @Deactivate - protected void deactivate() { - cfgService.removeListener(cfgListener); - factories.forEach(cfgService::unregisterConfigFactory); - packetService.removeProcessor(processor); - hostProviderRegistry.unregister(hostProvider); - hostProviderService = null; - cancelPackets(); - timeout.cancel(); - log.info("Stopped"); - } - - /** - * Request packet in via PacketService. - */ - private void requestPackets() { - - TrafficSelector.Builder selectorServer = DefaultTrafficSelector.builder() - .matchEthType(Ethernet.TYPE_IPV4) - .matchIPProtocol(IPv4.PROTOCOL_UDP) - .matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT)) - .matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT)); - packetService.requestPackets(selectorServer.build(), PacketPriority.CONTROL, appId); - - selectorServer = DefaultTrafficSelector.builder() - .matchEthType(Ethernet.TYPE_ARP); - packetService.requestPackets(selectorServer.build(), PacketPriority.CONTROL, appId); - } - - /** - * Cancel requested packets in via packet service. - */ - private void cancelPackets() { - TrafficSelector.Builder selectorServer = DefaultTrafficSelector.builder() - .matchEthType(Ethernet.TYPE_IPV4) - .matchIPProtocol(IPv4.PROTOCOL_UDP) - .matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT)) - .matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT)); - packetService.cancelPackets(selectorServer.build(), PacketPriority.CONTROL, appId); - - selectorServer = DefaultTrafficSelector.builder() - .matchEthType(Ethernet.TYPE_ARP); - packetService.cancelPackets(selectorServer.build(), PacketPriority.CONTROL, appId); - } - - @Override - public Map listMapping() { - return dhcpStore.listAssignedMapping(); - } - - @Override - public int getLeaseTime() { - return leaseTime; - } - - @Override - public int getRenewalTime() { - return renewalTime; - } - - @Override - public int getRebindingTime() { - return rebindingTime; - } - - @Override - public boolean setStaticMapping(MacAddress macID, Ip4Address ipAddress) { - return dhcpStore.assignStaticIP(macID, ipAddress); - } - - @Override - public boolean removeStaticMapping(MacAddress macID) { - return dhcpStore.removeStaticIP(macID); - } - - @Override - public Iterable getAvailableIPs() { - return dhcpStore.getAvailableIPs(); - } - - private class DHCPPacketProcessor implements PacketProcessor { - - /** - * Builds the DHCP Reply packet. - * - * @param packet the incoming Ethernet frame - * @param ipOffered the IP offered by the DHCP Server - * @param outgoingMessageType the message type of the outgoing packet - * @return the Ethernet reply frame - */ - private Ethernet buildReply(Ethernet packet, Ip4Address ipOffered, byte outgoingMessageType) { - - // Ethernet Frame. - Ethernet ethReply = new Ethernet(); - ethReply.setSourceMACAddress(myMAC); - ethReply.setDestinationMACAddress(packet.getSourceMAC()); - ethReply.setEtherType(Ethernet.TYPE_IPV4); - ethReply.setVlanID(packet.getVlanID()); - - // IP Packet - IPv4 ipv4Packet = (IPv4) packet.getPayload(); - IPv4 ipv4Reply = new IPv4(); - ipv4Reply.setSourceAddress(myIP.toInt()); - ipv4Reply.setDestinationAddress(ipOffered.toInt()); - ipv4Reply.setTtl(packetTTL); - - // UDP Datagram. - UDP udpPacket = (UDP) ipv4Packet.getPayload(); - UDP udpReply = new UDP(); - udpReply.setSourcePort((byte) UDP.DHCP_SERVER_PORT); - udpReply.setDestinationPort((byte) UDP.DHCP_CLIENT_PORT); - - // DHCP Payload. - DHCP dhcpPacket = (DHCP) udpPacket.getPayload(); - DHCP dhcpReply = new DHCP(); - dhcpReply.setOpCode(DHCP.OPCODE_REPLY); - 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); - - // DHCP Options. - DHCPOption option = new DHCPOption(); - List optionList = new ArrayList<>(); - - // DHCP Message Type. - option.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue()); - option.setLength((byte) 1); - byte[] optionData = {outgoingMessageType}; - option.setData(optionData); - optionList.add(option); - - // DHCP Server Identifier. - option = new DHCPOption(); - option.setCode(DHCP.DHCPOptionCode.OptionCode_DHCPServerIp.getValue()); - option.setLength((byte) 4); - option.setData(myIP.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(); - option.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue()); - option.setLength((byte) 1); - optionList.add(option); - - dhcpReply.setOptions(optionList); - - udpReply.setPayload(dhcpReply); - ipv4Reply.setPayload(udpReply); - ethReply.setPayload(ipv4Reply); - - return ethReply; - } - - /** - * Sends the Ethernet reply frame via the Packet Service. - * - * @param context the context of the incoming frame - * @param reply the Ethernet reply frame - */ - private void sendReply(PacketContext context, Ethernet reply) { - if (reply != null) { - TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder(); - ConnectPoint sourcePoint = context.inPacket().receivedFrom(); - builder.setOutput(sourcePoint.port()); - context.block(); - packetService.emit(new DefaultOutboundPacket(sourcePoint.deviceId(), - builder.build(), ByteBuffer.wrap(reply.serialize()))); - } - } - - /** - * Processes the DHCP Payload and initiates a reply to the client. - * - * @param context context of the incoming message - * @param dhcpPayload the extracted DHCP payload - */ - private void processDHCPPacket(PacketContext context, DHCP dhcpPayload) { - Ethernet packet = context.inPacket().parsed(); - boolean flagIfRequestedIP = false; - boolean flagIfServerIP = false; - Ip4Address requestedIP = Ip4Address.valueOf("0.0.0.0"); - Ip4Address serverIP = Ip4Address.valueOf("0.0.0.0"); - - if (dhcpPayload != null) { - - DHCPPacketType incomingPacketType = DHCPPacketType.getType(0); - for (DHCPOption option : dhcpPayload.getOptions()) { - if (option.getCode() == DHCP.DHCPOptionCode.OptionCode_MessageType.getValue()) { - byte[] data = option.getData(); - incomingPacketType = DHCPPacketType.getType(data[0]); - } - if (option.getCode() == DHCP.DHCPOptionCode.OptionCode_RequestedIP.getValue()) { - byte[] data = option.getData(); - requestedIP = Ip4Address.valueOf(data); - flagIfRequestedIP = true; - } - if (option.getCode() == DHCP.DHCPOptionCode.OptionCode_DHCPServerIp.getValue()) { - byte[] data = option.getData(); - serverIP = Ip4Address.valueOf(data); - flagIfServerIP = true; - } - } - DHCPPacketType outgoingPacketType; - MacAddress clientMAC = new MacAddress(dhcpPayload.getClientHardwareAddress()); - VlanId vlanId = VlanId.vlanId(packet.getVlanID()); - HostId hostId = HostId.hostId(clientMAC, vlanId); - - if (incomingPacketType.getValue() == DHCPPacketType.DHCPDISCOVER.getValue()) { - - outgoingPacketType = DHCPPacketType.DHCPOFFER; - Ip4Address ipOffered = dhcpStore.suggestIP(hostId, requestedIP); - if (ipOffered != null) { - Ethernet ethReply = buildReply(packet, ipOffered, - (byte) outgoingPacketType.getValue()); - sendReply(context, ethReply); - } - - } else if (incomingPacketType.getValue() == DHCPPacketType.DHCPREQUEST.getValue()) { - - if (flagIfServerIP && flagIfRequestedIP) { - // SELECTING state - if (myIP.equals(serverIP)) { - - 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); - } - } else if (flagIfRequestedIP) { - // INIT-REBOOT state - if (dhcpStore.assignIP(hostId, requestedIP, leaseTime)) { - 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)) { - 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()) { - Ip4Address ip4Address = dhcpStore.releaseIP(hostId); - if (ip4Address != null) { - hostProviderService.removeIpFromHost(hostId, ip4Address); - } - } - } - } - - /** - * Processes the ARP Payload and initiates a reply to the client. - * - * @param context context of the incoming message - * @param packet the ethernet payload - */ - private void processARPPacket(PacketContext context, Ethernet packet) { - - ARP arpPacket = (ARP) packet.getPayload(); - - ARP arpReply = (ARP) arpPacket.clone(); - arpReply.setOpCode(ARP.OP_REPLY); - - arpReply.setTargetProtocolAddress(arpPacket.getSenderProtocolAddress()); - arpReply.setTargetHardwareAddress(arpPacket.getSenderHardwareAddress()); - arpReply.setSenderProtocolAddress(arpPacket.getTargetProtocolAddress()); - arpReply.setSenderHardwareAddress(myMAC.toBytes()); - - // Ethernet Frame. - Ethernet ethReply = new Ethernet(); - ethReply.setSourceMACAddress(myMAC); - ethReply.setDestinationMACAddress(packet.getSourceMAC()); - ethReply.setEtherType(Ethernet.TYPE_ARP); - ethReply.setVlanID(packet.getVlanID()); - - ethReply.setPayload(arpReply); - sendReply(context, ethReply); - } - - /** - * Integrates hosts learned through DHCP into topology. - * @param context context of the incoming message - * @param ipAssigned IP Address assigned to the host by DHCP Manager - */ - private void discoverHost(PacketContext context, Ip4Address ipAssigned) { - Ethernet packet = context.inPacket().parsed(); - MacAddress mac = packet.getSourceMAC(); - VlanId vlanId = VlanId.vlanId(packet.getVlanID()); - HostLocation hostLocation = new HostLocation(context.inPacket().receivedFrom(), 0); - - Set ips = new HashSet<>(); - ips.add(ipAssigned); - - HostId hostId = HostId.hostId(mac, vlanId); - DefaultHostDescription desc = new DefaultHostDescription(mac, vlanId, hostLocation, ips); - hostProviderService.hostDetected(hostId, desc); - } - - - @Override - public void process(PacketContext context) { - Ethernet packet = context.inPacket().parsed(); - if (packet == null) { - return; - } - - if (packet.getEtherType() == Ethernet.TYPE_IPV4) { - IPv4 ipv4Packet = (IPv4) packet.getPayload(); - - if (ipv4Packet.getProtocol() == IPv4.PROTOCOL_UDP) { - UDP udpPacket = (UDP) ipv4Packet.getPayload(); - - if (udpPacket.getDestinationPort() == UDP.DHCP_SERVER_PORT && - udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT) { - // This is meant for the dhcp server so process the packet here. - - DHCP dhcpPayload = (DHCP) udpPacket.getPayload(); - processDHCPPacket(context, dhcpPayload); - } - } - } else if (packet.getEtherType() == Ethernet.TYPE_ARP) { - ARP arpPacket = (ARP) packet.getPayload(); - - if ((arpPacket.getOpCode() == ARP.OP_REQUEST) && - Objects.equals(myIP, Ip4Address.valueOf(arpPacket.getTargetProtocolAddress()))) { - - processARPPacket(context, packet); - - } - } - } - } - - private class InternalConfigListener implements NetworkConfigListener { - - /** - * Reconfigures the DHCP Server according to the configuration parameters passed. - * - * @param cfg configuration object - */ - private void reconfigureNetwork(DhcpConfig cfg) { - if (cfg == null) { - return; - } - if (cfg.ip() != null) { - myIP = cfg.ip(); - } - if (cfg.mac() != null) { - myMAC = cfg.mac(); - } - if (cfg.subnetMask() != null) { - subnetMask = cfg.subnetMask(); - } - if (cfg.broadcastAddress() != null) { - broadcastAddress = cfg.broadcastAddress(); - } - if (cfg.routerAddress() != null) { - routerAddress = cfg.routerAddress(); - } - if (cfg.domainServer() != null) { - domainServer = cfg.domainServer(); - } - if (cfg.ttl() != -1) { - packetTTL = (byte) cfg.ttl(); - } - if (cfg.leaseTime() != -1) { - leaseTime = cfg.leaseTime(); - } - if (cfg.renewTime() != -1) { - renewalTime = cfg.renewTime(); - } - if (cfg.rebindTime() != -1) { - rebindingTime = cfg.rebindTime(); - } - if (cfg.defaultTimeout() != -1) { - dhcpStore.setDefaultTimeoutForPurge(cfg.defaultTimeout()); - } - if (cfg.timerDelay() != -1) { - timerDelay = cfg.timerDelay(); - } - if ((cfg.startIp() != null) && (cfg.endIp() != null)) { - dhcpStore.populateIPPoolfromRange(cfg.startIp(), cfg.endIp()); - } - } - - - @Override - public void event(NetworkConfigEvent event) { - - if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED || - event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) && - event.configClass().equals(DhcpConfig.class)) { - - DhcpConfig cfg = cfgService.getConfig(appId, DhcpConfig.class); - reconfigureNetwork(cfg); - log.info("Reconfigured"); - } - } - } - - private class InternalHostProvider extends AbstractProvider implements HostProvider { - - /** - * Creates a provider with the supplier identifier. - */ - protected InternalHostProvider() { - super(PID); - } - - @Override - public void triggerProbe(Host host) { - // nothing to do - } - } - - private class PurgeListTask implements TimerTask { - - @Override - public void run(Timeout to) { - IpAssignment ipAssignment; - Date dateNow = new Date(); - - Map ipAssignmentMap = dhcpStore.listAllMapping(); - for (Map.Entry entry: ipAssignmentMap.entrySet()) { - ipAssignment = entry.getValue(); - - long timeLapsed = dateNow.getTime() - ipAssignment.timestamp().getTime(); - if ((ipAssignment.assignmentStatus() != IpAssignment.AssignmentStatus.Option_Expired) && - (ipAssignment.leasePeriod() > 0) && (timeLapsed > (ipAssignment.leasePeriodMs()))) { - - Ip4Address ip4Address = dhcpStore.releaseIP(entry.getKey()); - if (ip4Address != null) { - hostProviderService.removeIpFromHost(entry.getKey(), ipAssignment.ipAddress()); - } - } - } - timeout = Timer.getTimer().newTimeout(new PurgeListTask(), timerDelay, TimeUnit.MINUTES); - } - } -} \ No newline at end of file diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpUi.java b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpUi.java deleted file mode 100644 index bb2bd2c2..00000000 --- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpUi.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.onosproject.dhcp.impl; - -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.apache.felix.scr.annotations.Service; -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; - -import static org.onosproject.ui.UiView.Category.NETWORK; - -/** - * Mechanism to stream data to the GUI. - */ -@Component(immediate = true, enabled = true) -@Service(value = DhcpUi.class) -public class DhcpUi { - - private final Logger log = LoggerFactory.getLogger(getClass()); - private static final ClassLoader CL = DhcpUi.class.getClassLoader(); - - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected UiExtensionService uiExtensionService; - - private final UiMessageHandlerFactory messageHandlerFactory = - () -> ImmutableList.of(new DhcpViewMessageHandler()); - - private final List views = ImmutableList.of( - new UiView(NETWORK, "dhcp", "DHCP Server") - ); - - private final UiExtension uiExtension = - new UiExtension.Builder(CL, views) - .messageHandlerFactory(messageHandlerFactory) - .resourcePath("gui") - .build(); - - @Activate - protected void activate() { - uiExtensionService.register(uiExtension); - log.info("Started"); - } - - @Deactivate - protected void deactivate() { - uiExtensionService.unregister(uiExtension); - log.info("Stopped"); - } - -} \ No newline at end of file diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpViewMessageHandler.java b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpViewMessageHandler.java deleted file mode 100644 index 9ce65d5e..00000000 --- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpViewMessageHandler.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.onosproject.dhcp.impl; - -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.google.common.collect.ImmutableSet; -import org.onosproject.cli.AbstractShellCommand; -import org.onosproject.dhcp.DhcpService; -import org.onosproject.dhcp.IpAssignment; -import org.onosproject.net.HostId; -import org.onosproject.ui.RequestHandler; -import org.onosproject.ui.UiMessageHandler; -import org.onosproject.ui.table.TableModel; -import org.onosproject.ui.table.TableRequestHandler; - -import java.util.Collection; -import java.util.Date; -import java.util.Map; - -/** - * DHCPViewMessageHandler class implementation. - */ -public class DhcpViewMessageHandler extends UiMessageHandler { - - private static final String DHCP_DATA_REQ = "dhcpDataRequest"; - private static final String DHCP_DATA_RESP = "dhcpDataResponse"; - private static final String DHCP = "dhcps"; - - private static final String HOST = "host"; - private static final String IP = "ip"; - private static final String LEASE = "lease"; - - private static final String[] COL_IDS = { - HOST, IP, LEASE - }; - - @Override - protected Collection createRequestHandlers() { - return ImmutableSet.of( - new DataRequestHandler() - ); - } - - // handler for dhcp table requests - private final class DataRequestHandler extends TableRequestHandler { - - private DataRequestHandler() { - super(DHCP_DATA_REQ, DHCP_DATA_RESP, DHCP); - } - - @Override - protected String defaultColumnId() { - return HOST; - } - - @Override - protected String[] getColumnIds() { - return COL_IDS; - } - - @Override - protected void populateTable(TableModel tm, ObjectNode payload) { - DhcpService dhcpService = AbstractShellCommand.get(DhcpService.class); - Map allocationMap = dhcpService.listMapping(); - - for (Map.Entry entry : allocationMap.entrySet()) { - populateRow(tm.addRow(), entry); - } - } - - private void populateRow(TableModel.Row row, Map.Entry entry) { - if (entry.getValue().leasePeriod() > 0) { - Date now = new Date(entry.getValue().timestamp().getTime() + entry.getValue().leasePeriod()); - row.cell(HOST, entry.getKey()) - .cell(IP, entry.getValue().ipAddress()) - .cell(LEASE, now.toString()); - } else { - row.cell(HOST, entry.getKey()) - .cell(IP, entry.getValue().ipAddress()) - .cell(LEASE, "Infinite Static Lease"); - } - } - } -} 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 deleted file mode 100644 index 63f69d40..00000000 --- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DistributedDhcpStore.java +++ /dev/null @@ -1,328 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.onosproject.dhcp.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; -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.Ip4Address; -import org.onlab.packet.MacAddress; -import org.onlab.util.KryoNamespace; -import org.onosproject.dhcp.DhcpStore; -import org.onosproject.dhcp.IpAssignment; -import org.onosproject.net.HostId; -import org.onosproject.store.serializers.KryoNamespaces; -import org.onosproject.store.service.ConsistentMap; -import org.onosproject.store.service.DistributedSet; -import org.onosproject.store.service.Serializer; -import org.onosproject.store.service.StorageService; -import org.onosproject.store.service.Versioned; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Date; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; - -/** - * Manages the pool of available IP Addresses in the network and - * Remembers the mapping between MAC ID and IP Addresses assigned. - */ - -@Component(immediate = true) -@Service -public class DistributedDhcpStore implements DhcpStore { - - private final Logger log = LoggerFactory.getLogger(getClass()); - - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected StorageService storageService; - - private ConsistentMap allocationMap; - - private DistributedSet freeIPPool; - - private static Ip4Address startIPRange; - - private static Ip4Address endIPRange; - - // Hardcoded values are default values. - - private static int timeoutForPendingAssignments = 60; - - @Activate - protected void activate() { - allocationMap = storageService.consistentMapBuilder() - .withName("onos-dhcp-assignedIP") - .withSerializer(Serializer.using( - new KryoNamespace.Builder() - .register(KryoNamespaces.API) - .register(IpAssignment.class, - IpAssignment.AssignmentStatus.class, - Date.class, - long.class, - Ip4Address.class) - .build())) - .build(); - - freeIPPool = storageService.setBuilder() - .withName("onos-dhcp-freeIP") - .withSerializer(Serializer.using(KryoNamespaces.API)) - .build(); - - log.info("Started"); - } - - @Deactivate - protected void deactivate() { - log.info("Stopped"); - } - - @Override - public Ip4Address suggestIP(HostId hostId, Ip4Address requestedIP) { - - IpAssignment assignmentInfo; - if (allocationMap.containsKey(hostId)) { - assignmentInfo = allocationMap.get(hostId).value(); - IpAssignment.AssignmentStatus status = assignmentInfo.assignmentStatus(); - Ip4Address ipAddr = assignmentInfo.ipAddress(); - - if (status == IpAssignment.AssignmentStatus.Option_Assigned || - status == IpAssignment.AssignmentStatus.Option_Requested) { - // Client has a currently Active Binding. - if (ipWithinRange(ipAddr)) { - return ipAddr; - } - - } else if (status == IpAssignment.AssignmentStatus.Option_Expired) { - // Client has a Released or Expired Binding. - if (freeIPPool.contains(ipAddr)) { - assignmentInfo = IpAssignment.builder() - .ipAddress(ipAddr) - .timestamp(new Date()) - .leasePeriod(timeoutForPendingAssignments) - .assignmentStatus(IpAssignment.AssignmentStatus.Option_Requested) - .build(); - if (freeIPPool.remove(ipAddr)) { - allocationMap.put(hostId, assignmentInfo); - return ipAddr; - } - } - } - } else if (requestedIP.toInt() != 0) { - // Client has requested an IP. - if (freeIPPool.contains(requestedIP)) { - assignmentInfo = IpAssignment.builder() - .ipAddress(requestedIP) - .timestamp(new Date()) - .leasePeriod(timeoutForPendingAssignments) - .assignmentStatus(IpAssignment.AssignmentStatus.Option_Requested) - .build(); - if (freeIPPool.remove(requestedIP)) { - allocationMap.put(hostId, assignmentInfo); - return requestedIP; - } - } - } - - // Allocate a new IP from the server's pool of available IP. - Ip4Address nextIPAddr = fetchNextIP(); - if (nextIPAddr != null) { - assignmentInfo = IpAssignment.builder() - .ipAddress(nextIPAddr) - .timestamp(new Date()) - .leasePeriod(timeoutForPendingAssignments) - .assignmentStatus(IpAssignment.AssignmentStatus.Option_Requested) - .build(); - - allocationMap.put(hostId, assignmentInfo); - } - return nextIPAddr; - - } - - @Override - public boolean assignIP(HostId hostId, Ip4Address ipAddr, int leaseTime) { - - IpAssignment assignmentInfo; - if (allocationMap.containsKey(hostId)) { - assignmentInfo = allocationMap.get(hostId).value(); - IpAssignment.AssignmentStatus status = assignmentInfo.assignmentStatus(); - - if (Objects.equals(assignmentInfo.ipAddress(), ipAddr) && ipWithinRange(ipAddr)) { - - if (status == IpAssignment.AssignmentStatus.Option_Assigned || - status == IpAssignment.AssignmentStatus.Option_Requested) { - // Client has a currently active binding with the server. - assignmentInfo = IpAssignment.builder() - .ipAddress(ipAddr) - .timestamp(new Date()) - .leasePeriod(leaseTime) - .assignmentStatus(IpAssignment.AssignmentStatus.Option_Assigned) - .build(); - allocationMap.put(hostId, assignmentInfo); - return true; - } else if (status == IpAssignment.AssignmentStatus.Option_Expired) { - // Client has an expired binding with the server. - if (freeIPPool.contains(ipAddr)) { - assignmentInfo = IpAssignment.builder() - .ipAddress(ipAddr) - .timestamp(new Date()) - .leasePeriod(leaseTime) - .assignmentStatus(IpAssignment.AssignmentStatus.Option_Assigned) - .build(); - if (freeIPPool.remove(ipAddr)) { - allocationMap.put(hostId, assignmentInfo); - return true; - } - } - } - } - } else if (freeIPPool.contains(ipAddr)) { - assignmentInfo = IpAssignment.builder() - .ipAddress(ipAddr) - .timestamp(new Date()) - .leasePeriod(leaseTime) - .assignmentStatus(IpAssignment.AssignmentStatus.Option_Assigned) - .build(); - if (freeIPPool.remove(ipAddr)) { - allocationMap.put(hostId, assignmentInfo); - return true; - } - } - return false; - } - - @Override - public Ip4Address releaseIP(HostId hostId) { - if (allocationMap.containsKey(hostId)) { - IpAssignment newAssignment = IpAssignment.builder(allocationMap.get(hostId).value()) - .assignmentStatus(IpAssignment.AssignmentStatus.Option_Expired) - .build(); - Ip4Address freeIP = newAssignment.ipAddress(); - allocationMap.put(hostId, newAssignment); - if (ipWithinRange(freeIP)) { - freeIPPool.add(freeIP); - } - return freeIP; - } - return null; - } - - @Override - public void setDefaultTimeoutForPurge(int timeInSeconds) { - timeoutForPendingAssignments = timeInSeconds; - } - - @Override - public Map listAssignedMapping() { - - Map validMapping = new HashMap<>(); - IpAssignment assignment; - for (Map.Entry> entry: allocationMap.entrySet()) { - assignment = entry.getValue().value(); - if (assignment.assignmentStatus() == IpAssignment.AssignmentStatus.Option_Assigned) { - validMapping.put(entry.getKey(), assignment); - } - } - return validMapping; - } - - @Override - public Map listAllMapping() { - Map validMapping = new HashMap<>(); - for (Map.Entry> entry: allocationMap.entrySet()) { - validMapping.put(entry.getKey(), entry.getValue().value()); - } - return validMapping; - } - - @Override - public boolean assignStaticIP(MacAddress macID, Ip4Address ipAddr) { - HostId host = HostId.hostId(macID); - return assignIP(host, ipAddr, -1); - } - - @Override - public boolean removeStaticIP(MacAddress macID) { - HostId host = HostId.hostId(macID); - if (allocationMap.containsKey(host)) { - IpAssignment assignment = allocationMap.get(host).value(); - Ip4Address freeIP = assignment.ipAddress(); - if (assignment.leasePeriod() < 0) { - allocationMap.remove(host); - if (ipWithinRange(freeIP)) { - freeIPPool.add(freeIP); - } - return true; - } - } - return false; - } - - @Override - public Iterable getAvailableIPs() { - return ImmutableSet.copyOf(freeIPPool); - } - - @Override - public void populateIPPoolfromRange(Ip4Address startIP, Ip4Address endIP) { - // Clear all entries from previous range. - allocationMap.clear(); - freeIPPool.clear(); - startIPRange = startIP; - endIPRange = endIP; - - int lastIP = endIP.toInt(); - Ip4Address nextIP; - for (int loopCounter = startIP.toInt(); loopCounter <= lastIP; loopCounter++) { - nextIP = Ip4Address.valueOf(loopCounter); - freeIPPool.add(nextIP); - } - } - - /** - * Fetches the next available IP from the free pool pf IPs. - * - * @return the next available IP address - */ - private Ip4Address fetchNextIP() { - for (Ip4Address freeIP : freeIPPool) { - if (freeIPPool.remove(freeIP)) { - return freeIP; - } - } - return null; - } - - /** - * Returns true if the given ip is within the range of available IPs. - * - * @param ip given ip address - * @return true if within range, false otherwise - */ - private boolean ipWithinRange(Ip4Address ip) { - if ((ip.toInt() >= startIPRange.toInt()) && (ip.toInt() <= endIPRange.toInt())) { - return true; - } - return false; - } -} diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/package-info.java b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/package-info.java deleted file mode 100644 index 12e14e48..00000000 --- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Implementation classes for sample application that assigns and manages DHCP leases. - */ -package org.onosproject.dhcp.impl; \ No newline at end of file diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/package-info.java b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/package-info.java deleted file mode 100644 index 56778a35..00000000 --- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Sample application that assigns and manages DHCP leases. - */ -package org.onosproject.dhcp; \ No newline at end of file diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/rest/DHCPWebResource.java b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/rest/DHCPWebResource.java deleted file mode 100644 index 646ab7ea..00000000 --- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/rest/DHCPWebResource.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.onosproject.dhcp.rest; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.ObjectNode; -import org.onlab.packet.Ip4Address; -import org.onlab.packet.MacAddress; -import org.onosproject.dhcp.DhcpService; -import org.onosproject.dhcp.IpAssignment; -import org.onosproject.net.HostId; -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.util.Map; - -/** - * Manage DHCP address assignments. - */ -@Path("dhcp") -public class DHCPWebResource extends AbstractWebResource { - - final DhcpService service = get(DhcpService.class); - - /** - * Get DHCP server configuration data. - * Shows lease, renewal and rebinding times in seconds. - * - * @return 200 OK - */ - @GET - @Path("config") - public Response getConfigs() { - DhcpService service = get(DhcpService.class); - ObjectNode node = mapper().createObjectNode() - .put("leaseTime", service.getLeaseTime()) - .put("renewalTime", service.getRenewalTime()) - .put("rebindingTime", service.getRebindingTime()); - return ok(node.toString()).build(); - } - - /** - * Get all MAC/IP mappings. - * Shows all MAC/IP mappings held by the DHCP server. - * - * @return 200 OK - */ - @GET - @Path("mappings") - public Response listMappings() { - ObjectNode root = mapper().createObjectNode(); - - final Map intents = service.listMapping(); - ArrayNode arrayNode = root.putArray("mappings"); - intents.entrySet().forEach(i -> arrayNode.add(mapper().createObjectNode() - .put("host", i.getKey().toString()) - .put("ip", i.getValue().ipAddress().toString()))); - - return ok(root.toString()).build(); - } - - - - /** - * Get all available IPs. - * Shows all the IPs in the free pool of the DHCP Server. - * - * @return 200 OK - */ - @GET - @Path("available") - public Response listAvailableIPs() { - final Iterable availableIPList = service.getAvailableIPs(); - - final ObjectNode root = mapper().createObjectNode(); - ArrayNode arrayNode = root.putArray("availableIP"); - availableIPList.forEach(i -> arrayNode.add(i.toString())); - return ok(root.toString()).build(); - } - - /** - * Post a new static MAC/IP binding. - * Registers a static binding to the DHCP server, and displays the current set of bindings. - * - * @param stream JSON stream - * @return 200 OK - */ - @POST - @Path("mappings") - @Consumes(MediaType.APPLICATION_JSON) - public Response setMapping(InputStream stream) { - ObjectNode root = mapper().createObjectNode(); - - try { - ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream); - JsonNode macID = jsonTree.get("mac"); - JsonNode ip = jsonTree.get("ip"); - if (macID != null && ip != null) { - - if (!service.setStaticMapping(MacAddress.valueOf(macID.asText()), - Ip4Address.valueOf(ip.asText()))) { - throw new IllegalArgumentException("Static Mapping Failed. The IP maybe unavailable."); - } - } - - final Map intents = service.listMapping(); - ArrayNode arrayNode = root.putArray("mappings"); - intents.entrySet().forEach(i -> arrayNode.add(mapper().createObjectNode() - .put("host", i.getKey().toString()) - .put("ip", i.getValue().ipAddress().toString()))); - } catch (IOException e) { - throw new IllegalArgumentException(e.getMessage()); - } - return ok(root.toString()).build(); - } - - /** - * Delete a static MAC/IP binding. - * Removes a static binding from the DHCP Server, and displays the current set of bindings. - * - * @param macID mac address identifier - * @return 200 OK - */ - @DELETE - @Path("mappings/{macID}") - public Response deleteMapping(@PathParam("macID") String macID) { - - ObjectNode root = mapper().createObjectNode(); - - if (!service.removeStaticMapping(MacAddress.valueOf(macID))) { - throw new IllegalArgumentException("Static Mapping Removal Failed."); - } - final Map intents = service.listMapping(); - ArrayNode arrayNode = root.putArray("mappings"); - intents.entrySet().forEach(i -> arrayNode.add(mapper().createObjectNode() - .put("host", i.getKey().toString()) - .put("ip", i.getValue().ipAddress().toString()))); - - return ok(root.toString()).build(); - } -} diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/rest/package-info.java b/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/rest/package-info.java deleted file mode 100644 index 73173c55..00000000 --- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/rest/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * REST APIs for sample application that assigns and manages DHCP leases. - */ -package org.onosproject.dhcp.rest; \ No newline at end of file diff --git a/framework/src/onos/apps/dhcp/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/framework/src/onos/apps/dhcp/src/main/resources/OSGI-INF/blueprint/shell-config.xml deleted file mode 100644 index ce716315..00000000 --- a/framework/src/onos/apps/dhcp/src/main/resources/OSGI-INF/blueprint/shell-config.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/framework/src/onos/apps/dhcp/src/main/resources/app/view/dhcp/dhcp.css b/framework/src/onos/apps/dhcp/src/main/resources/app/view/dhcp/dhcp.css deleted file mode 100644 index e0a29314..00000000 --- a/framework/src/onos/apps/dhcp/src/main/resources/app/view/dhcp/dhcp.css +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - ONOS GUI -- DHCP Server -- CSS file - */ - -#ov-dhcp h2 { - display: inline-block; -} - -#ov-dhcp div.ctrl-btns { - width: 45px; -} diff --git a/framework/src/onos/apps/dhcp/src/main/resources/app/view/dhcp/dhcp.html b/framework/src/onos/apps/dhcp/src/main/resources/app/view/dhcp/dhcp.html deleted file mode 100644 index 5782badf..00000000 --- a/framework/src/onos/apps/dhcp/src/main/resources/app/view/dhcp/dhcp.html +++ /dev/null @@ -1,47 +0,0 @@ - -
-
-

DHCP Mappings ({{tableData.length}} total)

-
-
-
-
- -
-
- -
- - - - - - -
Host IDIP AddressLease Expiry
-
- -
- - - - - - - - - - -
- No mappings found -
{{dhcp.host}}{{dhcp.ip}}{{dhcp.lease}}
-
- -
- -
diff --git a/framework/src/onos/apps/dhcp/src/main/resources/app/view/dhcp/dhcp.js b/framework/src/onos/apps/dhcp/src/main/resources/app/view/dhcp/dhcp.js deleted file mode 100644 index 061d0de6..00000000 --- a/framework/src/onos/apps/dhcp/src/main/resources/app/view/dhcp/dhcp.js +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - ONOS GUI -- DHCP Server View Module - */ - -(function () { - 'use strict'; - - // injected refs - var $log, $scope; - - angular.module('ovDhcp', []) - .controller('OvDhcpCtrl', - ['$log', '$scope', 'TableBuilderService', - - function (_$log_, _$scope_, tbs) { - $log = _$log_; - $scope = _$scope_; - - function selCb($event, row) { - $log.debug('Got a click on:', row); - } - - tbs.buildTable({ - scope: $scope, - tag: 'dhcp', - selCb: selCb - }); - - $scope.$on('$destroy', function () { - $log.debug('OvDhcpCtrl has been destroyed'); - }); - - $log.log('OvDhcpCtrl has been created'); - }]); -}()); \ No newline at end of file diff --git a/framework/src/onos/apps/dhcp/src/main/resources/gui/css.html b/framework/src/onos/apps/dhcp/src/main/resources/gui/css.html deleted file mode 100644 index d02ad44a..00000000 --- a/framework/src/onos/apps/dhcp/src/main/resources/gui/css.html +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/framework/src/onos/apps/dhcp/src/main/resources/gui/js.html b/framework/src/onos/apps/dhcp/src/main/resources/gui/js.html deleted file mode 100644 index d37b5768..00000000 --- a/framework/src/onos/apps/dhcp/src/main/resources/gui/js.html +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/framework/src/onos/apps/dhcp/src/main/webapp/WEB-INF/web.xml b/framework/src/onos/apps/dhcp/src/main/webapp/WEB-INF/web.xml deleted file mode 100644 index 27504548..00000000 --- a/framework/src/onos/apps/dhcp/src/main/webapp/WEB-INF/web.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - DHCP Server REST API v1.0 - - - JAX-RS Service - com.sun.jersey.spi.container.servlet.ServletContainer - - com.sun.jersey.config.property.resourceConfigClass - com.sun.jersey.api.core.ClassNamesResourceConfig - - - com.sun.jersey.config.property.classnames - - org.onosproject.dhcp.rest.DHCPWebResource - - - 1 - - - - JAX-RS Service - /* - - diff --git a/framework/src/onos/apps/dhcp/src/test/java/org/onosproject/dhcp/IpAssignmentTest.java b/framework/src/onos/apps/dhcp/src/test/java/org/onosproject/dhcp/IpAssignmentTest.java deleted file mode 100644 index 3ecc5cfa..00000000 --- a/framework/src/onos/apps/dhcp/src/test/java/org/onosproject/dhcp/IpAssignmentTest.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.onosproject.dhcp; - -import com.google.common.testing.EqualsTester; -import org.junit.Assert; -import org.junit.Test; -import org.onlab.packet.Ip4Address; - -import java.util.Date; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.fail; - -/** - * Unit Tests for IPAssignment class. - */ -public class IpAssignmentTest { - - private final Date dateNow = new Date(); - - private final IpAssignment stats1 = IpAssignment.builder() - .ipAddress(Ip4Address.valueOf("10.10.10.10")) - .leasePeriod(300) - .assignmentStatus(IpAssignment.AssignmentStatus.Option_Expired) - .timestamp(dateNow) - .build(); - - private final IpAssignment stats2 = IpAssignment.builder() - .ipAddress(Ip4Address.valueOf("10.10.10.10")) - .leasePeriod(300) - .assignmentStatus(IpAssignment.AssignmentStatus.Option_Assigned) - .timestamp(dateNow) - .build(); - - private final IpAssignment stats3 = IpAssignment.builder(stats1) - .build(); - - /** - * Tests the constructor for the class. - */ - @Test - public void testConstruction() { - assertThat(stats3.ipAddress(), is(Ip4Address.valueOf("10.10.10.10"))); - assertThat(stats3.timestamp(), is(dateNow)); - assertThat(stats3.leasePeriod(), is(300)); - assertThat(stats3.assignmentStatus(), is(IpAssignment.AssignmentStatus.Option_Expired)); - } - - /** - * Tests the equality and inequality of objects using Guava EqualsTester. - */ - @Test - public void testEquals() { - new EqualsTester() - .addEqualityGroup(stats1, stats1) - .addEqualityGroup(stats2) - .testEquals(); - } - - /** - * Tests if the toString method returns a consistent value for hashing. - */ - @Test - public void testToString() { - assertThat(stats1.toString(), is(stats1.toString())); - } - - /** - * Tests if the validateInputs method returns an exception for malformed object. - */ - @Test - public void testValidateInputs() { - try { - IpAssignment stats4 = IpAssignment.builder() - .ipAddress(Ip4Address.valueOf("10.10.10.10")) - .leasePeriod(300) - .build(); - - fail("Construction of a malformed IPAssignment did not throw an exception"); - } catch (NullPointerException e) { - Assert.assertThat(e.getMessage(), containsString("must be specified")); - } - } -} 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 deleted file mode 100644 index fd4701c6..00000000 --- a/framework/src/onos/apps/dhcp/src/test/java/org/onosproject/dhcp/impl/DhcpManagerTest.java +++ /dev/null @@ -1,392 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.onosproject.dhcp.impl; - -import com.google.common.collect.ImmutableSet; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.onlab.packet.DHCP; -import org.onlab.packet.DHCPOption; -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; -import org.onosproject.dhcp.DhcpStore; -import org.onosproject.dhcp.IpAssignment; -import org.onosproject.net.Host; -import org.onosproject.net.HostId; -import org.onosproject.net.config.NetworkConfigRegistryAdapter; -import org.onosproject.net.host.HostDescription; -import org.onosproject.net.host.HostProvider; -import org.onosproject.net.host.HostProviderRegistry; -import org.onosproject.net.host.HostProviderService; -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.AbstractProvider; -import org.onosproject.net.provider.AbstractProviderService; -import org.onosproject.net.provider.ProviderId; - -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; -import static org.onosproject.net.NetTestTools.connectPoint; - -/** - * Set of tests of the ONOS application component. - */ - -public class DhcpManagerTest { - - private DhcpManager dhcpXManager; - - protected PacketProcessor packetProcessor; - - protected HostProviderService hostProviderService; - - private static final HostId CLIENT1_HOST = HostId.hostId(MacAddress.valueOf("1a:1a:1a:1a:1a:1a")); - - private static final String EXPECTED_IP = "10.2.0.2"; - - private static final Ip4Address BROADCAST = Ip4Address.valueOf("255.255.255.255"); - - private static final int TRANSACTION_ID = 1000; - - private static final ProviderId PID = new ProviderId("of", "foo"); - - @Before - public void setUp() { - dhcpXManager = new DhcpManager(); - dhcpXManager.cfgService = new TestNetworkConfigRegistry(); - dhcpXManager.packetService = new TestPacketService(); - dhcpXManager.coreService = new TestCoreService(); - dhcpXManager.dhcpStore = new TestDhcpStore(); - hostProviderService = new TestHostProviderService(new TestHostProvider()); - dhcpXManager.hostProviderService = hostProviderService; - dhcpXManager.hostProviderRegistry = new TestHostRegistry(); - dhcpXManager.activate(); - } - - @After - public void tearDown() { - dhcpXManager.deactivate(); - } - - /** - * Tests the response to a DHCP Discover Packet. - */ - @Test - public void testDiscover() { - Ethernet reply = constructDHCPPacket(DHCPPacketType.DHCPDISCOVER); - sendPacket(reply); - } - - /** - * Tests the response to a DHCP Request Packet. - */ - @Test - public void testRequest() { - Ethernet reply = constructDHCPPacket(DHCPPacketType.DHCPREQUEST); - sendPacket(reply); - } - - /** - * 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 DHCP Payload. - * @param packetType DHCP Message Type - * @return Ethernet packet - */ - private Ethernet constructDHCPPacket(DHCPPacketType packetType) { - - // Ethernet Frame. - Ethernet ethReply = new Ethernet(); - ethReply.setSourceMACAddress(CLIENT1_HOST.mac()); - ethReply.setDestinationMACAddress(MacAddress.BROADCAST); - ethReply.setEtherType(Ethernet.TYPE_IPV4); - ethReply.setVlanID((short) 2); - - // IP Packet - IPv4 ipv4Reply = new IPv4(); - ipv4Reply.setSourceAddress(0); - ipv4Reply.setDestinationAddress(BROADCAST.toInt()); - ipv4Reply.setTtl((byte) 127); - - // UDP Datagram. - UDP udpReply = new UDP(); - udpReply.setSourcePort((byte) UDP.DHCP_CLIENT_PORT); - udpReply.setDestinationPort((byte) UDP.DHCP_SERVER_PORT); - - // DHCP Payload. - DHCP dhcpReply = new DHCP(); - dhcpReply.setOpCode(DHCP.OPCODE_REQUEST); - - dhcpReply.setYourIPAddress(0); - dhcpReply.setServerIPAddress(0); - - dhcpReply.setTransactionId(TRANSACTION_ID); - dhcpReply.setClientHardwareAddress(CLIENT1_HOST.mac().toBytes()); - dhcpReply.setHardwareType(DHCP.HWTYPE_ETHERNET); - dhcpReply.setHardwareAddressLength((byte) 6); - - // DHCP Options. - DHCPOption option = new DHCPOption(); - List optionList = new ArrayList<>(); - - // DHCP Message Type. - option.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue()); - option.setLength((byte) 1); - byte[] optionData = {(byte) packetType.getValue()}; - option.setData(optionData); - optionList.add(option); - - // DHCP Requested IP. - option = new DHCPOption(); - option.setCode(DHCP.DHCPOptionCode.OptionCode_RequestedIP.getValue()); - option.setLength((byte) 4); - optionData = Ip4Address.valueOf(EXPECTED_IP).toOctets(); - option.setData(optionData); - optionList.add(option); - - // End Option. - option = new DHCPOption(); - option.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue()); - option.setLength((byte) 1); - optionList.add(option); - - dhcpReply.setOptions(optionList); - - udpReply.setPayload(dhcpReply); - ipv4Reply.setPayload(udpReply); - ethReply.setPayload(ipv4Reply); - - return ethReply; - } - - /** - * Validates the contents of the packet sent by the DHCP Manager. - * @param packet Ethernet packet received - */ - private void validatePacket(Ethernet packet) { - DHCP dhcpPacket = (DHCP) packet.getPayload().getPayload().getPayload(); - assertEquals(MacAddress.valueOf(dhcpPacket.getClientHardwareAddress()), CLIENT1_HOST.mac()); - assertEquals(Ip4Address.valueOf(dhcpPacket.getYourIPAddress()), Ip4Address.valueOf(EXPECTED_IP)); - assertEquals(dhcpPacket.getTransactionId(), TRANSACTION_ID); - } - - /** - * Mocks the DHCPStore. - */ - private final class TestDhcpStore implements DhcpStore { - - - public void populateIPPoolfromRange(Ip4Address startIP, Ip4Address endIP) { - } - - public Ip4Address suggestIP(HostId hostId, Ip4Address requestedIP) { - return Ip4Address.valueOf(EXPECTED_IP); - } - - public boolean assignIP(HostId hostId, Ip4Address ipAddr, int leaseTime) { - return true; - } - - public void setDefaultTimeoutForPurge(int timeInSeconds) { - } - - public Ip4Address releaseIP(HostId hostId) { - return null; - } - - public Map listAssignedMapping() { - return listAllMapping(); - } - - public Map listAllMapping() { - Map map = new HashMap<>(); - IpAssignment assignment = IpAssignment.builder() - .ipAddress(Ip4Address.valueOf(EXPECTED_IP)) - .assignmentStatus(IpAssignment.AssignmentStatus.Option_Assigned) - .leasePeriod(300) - .timestamp(new Date()) - .build(); - map.put(CLIENT1_HOST, assignment); - return map; - } - - public boolean assignStaticIP(MacAddress macID, Ip4Address ipAddr) { - return true; - } - - public boolean removeStaticIP(MacAddress macID) { - return true; - } - - public Iterable getAvailableIPs() { - List ipList = new ArrayList<>(); - ipList.add(Ip4Address.valueOf(EXPECTED_IP)); - return ImmutableSet.copyOf(ipList); - } - } - - /** - * Mocks the DefaultPacket context. - */ - 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. - } - } - - /** - * Keeps a reference to the PacketProcessor and verifies the OutboundPackets. - */ - private class TestPacketService 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); - validatePacket(eth); - } catch (Exception e) { - fail(e.getMessage()); - } - } - } - - /** - * Mocks the CoreService. - */ - private class TestCoreService extends CoreServiceAdapter { - - } - - /** - * Mocks the NetworkConfigRegistry. - */ - private class TestNetworkConfigRegistry extends NetworkConfigRegistryAdapter { - - } - - /** - * Mocks the HostProviderService. - */ - private class TestHostProviderService extends AbstractProviderService - implements HostProviderService { - - protected TestHostProviderService(HostProvider provider) { - super(provider); - } - - @Override - public void hostDetected(HostId hostId, HostDescription hostDescription, boolean replaceIps) { - - } - - @Override - public void hostVanished(HostId hostId) { - } - - @Override - public void removeIpFromHost(HostId hostId, IpAddress ipAddress) { - - } - - } - - /** - * Mocks the HostProvider. - */ - private static class TestHostProvider extends AbstractProvider - implements HostProvider { - - protected TestHostProvider() { - super(PID); - } - - @Override - public ProviderId id() { - return PID; - } - - @Override - public void triggerProbe(Host host) { - } - - } - - /** - * Mocks the HostProviderRegistry. - */ - private class TestHostRegistry implements HostProviderRegistry { - - @Override - public HostProviderService register(HostProvider provider) { - return hostProviderService; - } - - @Override - public void unregister(HostProvider provider) { - } - - @Override - public Set getProviders() { - return null; - } - - } - -} diff --git a/framework/src/onos/apps/dhcp/src/test/resources/dhcp-cfg.json b/framework/src/onos/apps/dhcp/src/test/resources/dhcp-cfg.json deleted file mode 100644 index abc48a83..00000000 --- a/framework/src/onos/apps/dhcp/src/test/resources/dhcp-cfg.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "apps": { - "org.onosproject.dhcp" : { - "dhcp" : { - "ip": "10.0.0.1", - "mac": "1a:2b:3c:4e:5e:6f", - "subnet": "255.0.0.0", - "broadcast": "10.255.255.255", - "router": "10.0.0.1", - "domain": "10.0.0.1", - "ttl": "63", - "lease": "300", - "renew": "150", - "rebind": "200", - "delay": "3", - "timeout": "150", - "startip": "10.0.0.110", - "endip": "10.0.0.130" - } - } - } -} \ No newline at end of file diff --git a/framework/src/onos/apps/igmp/src/main/java/org/onosproject/igmp/impl/package-info.java b/framework/src/onos/apps/igmp/src/main/java/org/onosproject/igmp/impl/package-info.java new file mode 100644 index 00000000..7d420198 --- /dev/null +++ b/framework/src/onos/apps/igmp/src/main/java/org/onosproject/igmp/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. + */ + +/** + * IGMP implementation. + */ +package org.onosproject.igmp.impl; diff --git a/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/rest/package-info.java b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/rest/package-info.java new file mode 100644 index 00000000..b42586fe --- /dev/null +++ b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/rest/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. + */ + +/** + * REST API for multicase forwarding. + */ +package org.onosproject.mfwd.rest; diff --git a/framework/src/onos/apps/mlb/src/main/java/org/onosproject/mlb/package-info.java b/framework/src/onos/apps/mlb/src/main/java/org/onosproject/mlb/package-info.java new file mode 100644 index 00000000..a7d83757 --- /dev/null +++ b/framework/src/onos/apps/mlb/src/main/java/org/onosproject/mlb/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. + */ + +/** + * Mastership load balancer. + */ +package org.onosproject.mlb; diff --git a/framework/src/onos/apps/openstackswitching/pom.xml b/framework/src/onos/apps/openstackswitching/pom.xml new file mode 100644 index 00000000..245b9e80 --- /dev/null +++ b/framework/src/onos/apps/openstackswitching/pom.xml @@ -0,0 +1,121 @@ + + + + 4.0.0 + + + org.onosproject + onos-apps + 1.4.0-SNAPSHOT + ../pom.xml + + + onos-app-openstackswitching + bundle + + SONA Openstack Switching applications + + 1.4.0-SNAPSHOT + org.onosproject.openstackswitching + /onos/openstackswitching + 1.0.0 + ONOS OpenStack Switching REST API + + APIs for receiving Neutron information. + + org.onosproject.openstackswitching.web + SKT, Inc. + + + + + + org.onosproject + onos-rest + ${project.version} + + + org.onosproject + onlab-rest + ${project.version} + + + javax.ws.rs + jsr311-api + 1.1.1 + + + com.sun.jersey + jersey-servlet + + + com.fasterxml.jackson.core + jackson-databind + + + com.fasterxml.jackson.core + jackson-annotations + + + org.osgi + org.osgi.compendium + + + org.osgi + org.osgi.core + + + + + + + org.apache.felix + maven-bundle-plugin + true + + + <_wab>src/main/webapp/ + + ${project.groupId}.${project.artifactId} + + + org.slf4j, + org.osgi.framework, + javax.ws.rs, + javax.ws.rs.core, + com.sun.jersey.api.core, + com.sun.jersey.spi.container.servlet, + com.sun.jersey.server.impl.container.servlet, + com.fasterxml.jackson.databind, + com.fasterxml.jackson.databind.node, + com.fasterxml.jackson.core, + org.apache.karaf.shell.commands, + com.google.common.*, + org.onlab.packet.*, + org.onosproject.* + + ${web.context} + + + + + + + + diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackArpHandler.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackArpHandler.java new file mode 100644 index 00000000..afaf7a22 --- /dev/null +++ b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackArpHandler.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.openstackswitching; + +import org.onosproject.net.packet.InboundPacket; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; + +/** + * It handles ARP packet from VMs. + */ +public class OpenstackArpHandler { + + private static Logger log = LoggerFactory + .getLogger(OpenstackArpHandler.class); + + HashMap openstackPortHashMap; + + /** + * Constructs an OpenstackArpHandler. + * + * @param openstackPortMap port map + */ + public OpenstackArpHandler(HashMap openstackPortMap) { + this.openstackPortHashMap = openstackPortMap; + } + + /** + * Processes ARP packets. + * + * @param pkt ARP request packet + */ + public void processPacketIn(InboundPacket pkt) { + log.warn("Received an ARP packet"); + } +} diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackDhcpHandler.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackDhcpHandler.java new file mode 100644 index 00000000..9c3641c1 --- /dev/null +++ b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackDhcpHandler.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.openstackswitching; + +import org.onosproject.net.packet.InboundPacket; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * It handles DHCP request packets. + */ +public class OpenstackDhcpHandler { + + private static Logger log = LoggerFactory + .getLogger(OpenstackDhcpHandler.class); + + /** + * Returns OpenstackDhcpHandler reference. + */ + public OpenstackDhcpHandler() { + + } + + /** + * Processes DHCP request packets. + * + * @param pkt DHCP request packet + */ + public void processPacketIn(InboundPacket pkt) { + log.warn("Received a DHCP packet"); + } +} diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackNetwork.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackNetwork.java new file mode 100644 index 00000000..dc7c0263 --- /dev/null +++ b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackNetwork.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.openstackswitching; + +import static com.google.common.base.Preconditions.checkNotNull; + + +/** + * Represents the network information given by Neutron. + */ +public final class OpenstackNetwork { + + private String name; + private String tenantId; + private String segmentId; + private String networkType; + private String id; + + /** + * Returns the builder object of the OpenstackNetwork class. + * + * @return OpenstackNetwork builder object + */ + public static OpenstackNetwork.Builder builder() { + return new Builder(); + } + + private OpenstackNetwork(String name, String tenantId, String id, String sid, + String type) { + this.name = checkNotNull(name); + this.tenantId = checkNotNull(tenantId); + this.segmentId = checkNotNull(sid); + this.id = checkNotNull(id); + this.networkType = checkNotNull(type); + } + + public String name() { + return this.name; + } + + public String tenantId() { + return this.tenantId; + } + + public String id() { + return this.id; + } + + public String segmentId() { + return this.segmentId; + } + + public String networkType() { + return this.networkType; + } + + public static final class Builder { + private String name; + private String tenantId; + private String id; + private String sid; + private String networkType; + + public Builder name(String name) { + this.name = name; + + return this; + } + + public Builder tenantId(String tenantId) { + this.tenantId = tenantId; + + return this; + } + + public Builder id(String id) { + this.id = id; + + return this; + } + + public Builder segmentId(String sid) { + this.sid = sid; + + return this; + } + + public Builder networkType(String type) { + this.networkType = type; + + return this; + } + + public OpenstackNetwork build() { + return new OpenstackNetwork(name, tenantId, id, sid, networkType); + } + + } +} diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackPort.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackPort.java new file mode 100644 index 00000000..4326b4fc --- /dev/null +++ b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackPort.java @@ -0,0 +1,350 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.openstackswitching; + +import com.google.common.collect.Lists; +import org.onlab.packet.Ip4Address; +import org.onlab.packet.MacAddress; + +import java.util.HashMap; +import java.util.List; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * It represents the Openstack Port information. + */ +public final class OpenstackPort { + + public enum PortStatus { + UP, + DOWN + } + + private PortStatus status; + private String name; + // FIX_ME + private String allowedAddressPairs; + private boolean adminStateUp; + private String networkId; + private String tenantId; + private String deviceOwner; + private MacAddress macAddress; + // + private HashMap fixedIps; + private String id; + private List securityGroups; + private String deviceId; + + private OpenstackPort(PortStatus status, String name, boolean adminStateUp, + String networkId, String tenantId, String deviceOwner, + MacAddress macAddress, HashMap fixedIps, String id, + List securityGroups, String deviceId) { + + this.status = status; + this.name = name; + this.adminStateUp = adminStateUp; + this.networkId = checkNotNull(networkId); + this.tenantId = checkNotNull(tenantId); + this.deviceOwner = deviceOwner; + this.macAddress = checkNotNull(macAddress); + this.fixedIps = checkNotNull(fixedIps); + this.id = checkNotNull(id); + this.securityGroups = securityGroups; + this.deviceId = deviceId; + } + + + + /** + * Returns OpenstackPort builder object. + * + * @return OpenstackPort builder + */ + public static OpenstackPort.Builder builder() { + return new Builder(); + } + + /** + * Returns port status. + * + * @return port status + */ + public PortStatus status() { + return status; + } + + /** + * Returns port name. + * + * @return port name + */ + public String name() { + return name; + } + + /** + * Returns whether admin state up or not. + * + * @return true if admin state up, false otherwise + */ + public boolean isAdminStateUp() { + return adminStateUp; + } + + /** + * Returns network ID. + * + * @return network ID + */ + public String networkId() { + return networkId; + } + + /** + * Returns device owner. + * + * @return device owner + */ + public String deviceOwner() { + return deviceOwner; + } + + /** + * Returns mac address. + * + * @return mac address + */ + public MacAddress macAddress() { + return macAddress; + } + + /** + * Returns the fixed IP information. + * + * @return fixed IP info + */ + public HashMap fixedIps() { + return fixedIps; + } + + /** + * Returns port ID. + * + * @return port ID + */ + public String id() { + return id; + } + + /** + * Returns security group information. + * + * @return security group info + */ + public List securityGroups() { + return securityGroups; + } + + /** + * Returns device ID. + * + * @return device ID + */ + public String deviceId() { + return deviceId; + } + + // TODO : Implement the following functions when necessary + //@Override + //public void equals(Object that) { + // + //} + // + //@Override + //public int hashCode() { + // + //} + + /** + * OpenstackPort Builder class. + */ + public static final class Builder { + + private PortStatus status; + private String name; + // FIX_ME + private String allowedAddressPairs; + private boolean adminStateUp; + private String networkId; + private String tenantId; + private String deviceOwner; + private MacAddress macAddress; + // list of hash map + private HashMap fixedIps; + private String id; + private List securityGroups; + private String deviceId; + + Builder() { + fixedIps = new HashMap<>(); + securityGroups = Lists.newArrayList(); + } + + /** + * Sets port status. + * + * @param status port status + * @return Builder object + */ + public Builder portStatus(PortStatus status) { + this.status = status; + + return this; + } + + /** + * Sets port name. + * + * @param name port name + * @return Builder object + */ + public Builder name(String name) { + this.name = name; + + return this; + } + + /** + * Sets whether admin state up or not. + * + * @param isAdminStateUp true if admin state is up, false otherwise + * @return Builder object + */ + public Builder adminState(boolean isAdminStateUp) { + this.adminStateUp = isAdminStateUp; + + return this; + } + + /** + * Sets network ID. + * + * @param networkId network ID + * @return Builder object + */ + public Builder netwrokId(String networkId) { + this.networkId = networkId; + + return this; + } + + /** + * Sets tenant ID. + * + * @param tenantId tenant ID + * @return Builder object + */ + public Builder tenantId(String tenantId) { + this.tenantId = tenantId; + + return this; + } + + /** + * Sets device owner. + * + * @param owner device owner + * @return Builder object + */ + public Builder deviceOwner(String owner) { + this.deviceOwner = owner; + + return this; + } + + /** + * Sets MAC address of the port. + * + * @param mac MAC address + * @return Builder object + */ + public Builder macAddress(MacAddress mac) { + this.macAddress = mac; + + return this; + } + + /** + * Sets Fixed IP address information. + * + * @param fixedIpList Fixed IP info + * @return Builder object + */ + public Builder fixedIps(HashMap fixedIpList) { + fixedIps.putAll(fixedIpList); + + return this; + } + + /** + * Sets ID of the port. + * + * @param id ID of the port + * @return Builder object + */ + public Builder id(String id) { + this.id = id; + + return this; + } + + /** + * Sets security group of the port. + * + * @param securityGroup security group of the port + * @return Builder object + */ + public Builder securityGroup(String securityGroup) { + securityGroups.add(securityGroup); + + return this; + } + + /** + * Sets device ID of the port. + * + * @param deviceId device ID + * @return Builder object + */ + public Builder deviceId(String deviceId) { + this.deviceId = deviceId; + + return this; + } + + /** + * Builds an OpenstackPort object. + * + * @return OpenstackPort objecet + */ + public OpenstackPort build() { + return new OpenstackPort(status, name, adminStateUp, networkId, networkId, + deviceOwner, macAddress, fixedIps, id, securityGroups, deviceId); + } + } +} + diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingManager.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingManager.java new file mode 100644 index 00000000..baae7f80 --- /dev/null +++ b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingManager.java @@ -0,0 +1,437 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.openstackswitching; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import org.apache.felix.scr.annotations.Activate; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Deactivate; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.ReferenceCardinality; +import org.apache.felix.scr.annotations.Service; +import org.onlab.packet.Ethernet; +import org.onlab.packet.IPv4; +import org.onlab.packet.Ip4Address; +import org.onlab.packet.Ip4Prefix; +import org.onlab.packet.MacAddress; +import org.onlab.packet.UDP; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.CoreService; +import org.onosproject.net.Device; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Port; +import org.onosproject.net.device.DeviceEvent; +import org.onosproject.net.device.DeviceListener; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.flowobjective.FlowObjectiveService; +import org.onosproject.net.packet.InboundPacket; +import org.onosproject.net.packet.PacketContext; +import org.onosproject.net.packet.PacketProcessor; +import org.onosproject.net.packet.PacketService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +@SuppressWarnings("ALL") +@Service +@Component(immediate = true) +/** + * It populates forwarding rules for VMs created by Openstack. + */ +public class OpenstackSwitchingManager implements OpenstackSwitchingService { + + private static Logger log = LoggerFactory + .getLogger(OpenstackSwitchingManager.class); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected CoreService coreService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected PacketService packetService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected DeviceService deviceService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected FlowObjectiveService flowObjectiveService; + + + public static final int DHCP_PORT = 67; + + private ApplicationId appId; + private OpenstackArpHandler arpHandler; + private OpenstackDhcpHandler dhcpHandler = new OpenstackDhcpHandler(); + private OpenstackSwitchingRulePopulator rulePopulator; + private ExecutorService deviceEventExcutorService = Executors.newFixedThreadPool(10); + + private InternalPacketProcessor internalPacketProcessor = new InternalPacketProcessor(); + private InternalDeviceListener internalDeviceListener = new InternalDeviceListener(); + + // Map + private HashMap openstackPortMap; + // Map + private HashMap openstackNetworkMap; + // Map > + private HashMap> vniPortMap; + private HashMap tunnelPortMap; + + + @Activate + protected void activate() { + appId = coreService + .registerApplication("org.onosproject.openstackswitching"); + rulePopulator = new OpenstackSwitchingRulePopulator(appId, flowObjectiveService); + packetService.addProcessor(internalPacketProcessor, PacketProcessor.director(1)); + deviceService.addListener(internalDeviceListener); + + openstackPortMap = Maps.newHashMap(); + openstackNetworkMap = Maps.newHashMap(); + vniPortMap = Maps.newHashMap(); + tunnelPortMap = Maps.newHashMap(); + + arpHandler = new OpenstackArpHandler(openstackPortMap); + + log.info("Started"); + } + + @Deactivate + protected void deactivate() { + packetService.removeProcessor(internalPacketProcessor); + deviceService.removeListener(internalDeviceListener); + + deviceEventExcutorService.shutdown(); + + log.info("Stopped"); + } + + @Override + public void createPorts(OpenstackPort openstackPort) { + openstackPortMap.put(openstackPort.id(), openstackPort); + } + + @Override + public void deletePorts() { + + } + + @Override + public void updatePorts() { + + } + + @Override + public void createNetwork(OpenstackNetwork openstackNetwork) { + openstackNetworkMap.put(openstackNetwork.id(), openstackNetwork); + } + + private void processDeviceAdded(Device device) { + log.warn("device {} is added", device.id()); + rulePopulator.populateDefaultRules(device.id()); + } + + private void processPortAdded(Device device, Port port) { + // TODO: Simplify the data structure to store the network info + // TODO: Make it stateless + // TODO: All the logics need to be processed inside of the rulePopulator class + synchronized (vniPortMap) { + log.warn("port {} is updated", port.toString()); + + updatePortMaps(device, port); + if (!port.annotations().value("portName").equals("vxlan")) { + populateFlowRulesForTrafficToSameCnode(device, port); + populateFlowRulesForTrafficToDifferentCnode(device, port); + } + } + } + + private void processPortRemoved(Device device, Port port) { + log.warn("port {} is removed", port.toString()); + // TODO: need to update the vniPortMap + } + + /** + * Populates the flow rules for traffic to VMs in different Cnode using + * Nicira extention. + * + * @param device device to put rules + * @param port port information of the VM + */ + private void populateFlowRulesForTrafficToDifferentCnode(Device device, Port port) { + String portName = port.annotations().value("portName"); + String channelId = device.annotations().value("channelId"); + Ip4Address hostIpAddress = Ip4Address.valueOf(channelId.split(":")[0]); + Ip4Address fixedIp = getFixedIpAddressForPort(portName); + // TODO: Avoid duplicate flow rule set up for VMs in other Cnode + // (possibly avoided by flowrule subsystem?) + if (tunnelPortMap.get(hostIpAddress) == null) { + log.warn("There is no tunnel port information"); + return; + } + String vni = getVniForPort(portName); + MacAddress vmMac = getVmMacAddressForPort(portName); + if (!vniPortMap.isEmpty() && vniPortMap.get(vni) != null) { + for (PortInfo portInfo : vniPortMap.get(vni)) { + if (!portInfo.portName.equals(portName) && + !portInfo.hostIp.equals(hostIpAddress)) { + MacAddress vmMacx = getVmMacAddressForPort(portInfo.portName); + rulePopulator.populateForwardingRuleForOtherCnode(vni, + device.id(), portInfo.hostIp, portInfo.fixedIp, vmMacx, + tunnelPortMap.get(hostIpAddress).number(), + portInfo.deviceId, hostIpAddress, fixedIp, vmMac, + tunnelPortMap.get(portInfo.hostIp).number()); + } + } + } + } + + /** + * Populates the flow rules for traffic to VMs in the same Cnode as the sender. + * + * @param device device to put the rules + * @param port port info of the VM + */ + private void populateFlowRulesForTrafficToSameCnode(Device device, Port port) { + Ip4Prefix cidr = getCidrForPort(port.annotations().value("portName")); + Ip4Address vmIp = getFixedIpAddressForPort(port.annotations().value("portName")); + if (vmIp != null) { + rulePopulator.populateForwardingRule(vmIp, device.id(), port, cidr); + } + } + + /** + * Updates the port maps using the port information. + * + * @param device device info + * @param port port of the VM + */ + private void updatePortMaps(Device device, Port port) { + String portName = port.annotations().value("portName"); + String channelId = device.annotations().value("channelId"); + Ip4Address hostIpAddress = Ip4Address.valueOf(channelId.split(":")[0]); + if (portName.startsWith("vxlan")) { + tunnelPortMap.put(hostIpAddress, port); + } else { + String vni = getVniForPort(portName); + Ip4Address fixedIp = getFixedIpAddressForPort(portName); + if (vniPortMap.get(vni) == null) { + vniPortMap.put(vni, Lists.newArrayList()); + } + vniPortMap.get(vni).add(new PortInfo(device.id(), portName, fixedIp, hostIpAddress)); + } + } + + /** + * Returns CIDR information from the subnet map for the port. + * + * @param portName port name of the port of the VM + * @return CIDR of the VNI of the VM + */ + private Ip4Prefix getCidrForPort(String portName) { + String networkId = null; + String uuid = portName.substring(3); + OpenstackPort port = openstackPortMap.values().stream() + .filter(p -> p.id().startsWith(uuid)) + .findFirst().get(); + if (port == null) { + log.warn("No port information for port {}", portName); + return null; + } + + //OpenstackSubnet subnet = openstackSubnetMap.values().stream() + // .filter(s -> s.networkId().equals(port.networkId())) + // .findFirst().get(); + //if (subnet == null) { + // log.warn("No subnet information for network {}", subnet.id()); + // return null; + //} + + //return Ip4Prefix.valueOf(subnet.cidr()); + return null; + } + + /** + * Returns the VNI of the VM of the port. + * + * @param portName VM port + * @return VNI + */ + private String getVniForPort(String portName) { + String networkId = null; + String uuid = portName.substring(3); + OpenstackPort port = openstackPortMap.values().stream() + .filter(p -> p.id().startsWith(uuid)) + .findFirst().get(); + if (port == null) { + log.warn("No port information for port {}", portName); + return null; + } + OpenstackNetwork network = openstackNetworkMap.values().stream() + .filter(n -> n.id().equals(port.networkId())) + .findFirst().get(); + if (network == null) { + log.warn("No VNI information for network {}", network.id()); + return null; + } + + return network.segmentId(); + } + + /** + * Returns the Fixed IP address of the VM. + * + * @param portName VM port info + * @return IP address of the VM + */ + private Ip4Address getFixedIpAddressForPort(String portName) { + + // FIXME - For now we use the information stored from neutron Rest API call. + // TODO - Later, the information needs to be extracted from Neutron on-demand. + String uuid = portName.substring(3); + OpenstackPort port = openstackPortMap.values().stream() + .filter(p -> p.id().startsWith(uuid)) + .findFirst().get(); + + if (port == null) { + log.error("There is no port information for port name {}", portName); + return null; + } + + if (port.fixedIps().isEmpty()) { + log.error("There is no fixed IP info in the port information"); + return null; + } + + return (Ip4Address) port.fixedIps().values().toArray()[0]; + } + + /** + * Returns the MAC address of the VM of the port. + * + * @param portName VM port + * @return MAC address of the VM + */ + private MacAddress getVmMacAddressForPort(String portName) { + + String uuid = portName.substring(3); + OpenstackPort port = openstackPortMap.values().stream() + .filter(p -> p.id().startsWith(uuid)) + .findFirst().get(); + + if (port == null) { + log.error("There is no mac information for port name {}", portName); + return null; + } + + return port.macAddress(); + } + + private class InternalPacketProcessor implements PacketProcessor { + + @Override + public void process(PacketContext context) { + + if (context.isHandled()) { + return; + } + + InboundPacket pkt = context.inPacket(); + Ethernet ethernet = pkt.parsed(); + + if (ethernet.getEtherType() == Ethernet.TYPE_ARP) { + arpHandler.processPacketIn(pkt); + } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) { + IPv4 ipPacket = (IPv4) ethernet.getPayload(); + + if (ipPacket.getProtocol() == IPv4.PROTOCOL_UDP) { + UDP udpPacket = (UDP) ipPacket.getPayload(); + if (udpPacket.getDestinationPort() == DHCP_PORT) { + dhcpHandler.processPacketIn(pkt); + } + } + } + } + } + + private class InternalDeviceListener implements DeviceListener { + + @Override + public void event(DeviceEvent event) { + deviceEventExcutorService.execute(new InternalEventHandler(event)); + } + } + + private class InternalEventHandler implements Runnable { + + volatile DeviceEvent deviceEvent; + + InternalEventHandler(DeviceEvent deviceEvent) { + this.deviceEvent = deviceEvent; + } + + @Override + public void run() { + switch (deviceEvent.type()) { + case DEVICE_ADDED: + processDeviceAdded((Device) deviceEvent.subject()); + break; + case DEVICE_UPDATED: + Port port = (Port) deviceEvent.subject(); + if (port.isEnabled()) { + processPortAdded((Device) deviceEvent.subject(), deviceEvent.port()); + } + break; + case DEVICE_AVAILABILITY_CHANGED: + Device device = (Device) deviceEvent.subject(); + if (deviceService.isAvailable(device.id())) { + processDeviceAdded(device); + } + break; + case PORT_ADDED: + processPortAdded((Device) deviceEvent.subject(), deviceEvent.port()); + break; + case PORT_UPDATED: + processPortAdded((Device) deviceEvent.subject(), deviceEvent.port()); + break; + case PORT_REMOVED: + processPortRemoved((Device) deviceEvent.subject(), deviceEvent.port()); + break; + default: + break; + } + } + } + + private final class PortInfo { + DeviceId deviceId; + String portName; + Ip4Address fixedIp; + Ip4Address hostIp; + + private PortInfo(DeviceId deviceId, String portName, Ip4Address fixedIp, + Ip4Address hostIp) { + this.deviceId = deviceId; + this.portName = portName; + this.fixedIp = fixedIp; + this.hostIp = hostIp; + } + } + +} \ No newline at end of file diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingRulePopulator.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingRulePopulator.java new file mode 100644 index 00000000..9ead05f0 --- /dev/null +++ b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingRulePopulator.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.openstackswitching; + +import org.onlab.packet.Ethernet; +import org.onlab.packet.IPv4; +import org.onlab.packet.Ip4Address; +import org.onlab.packet.Ip4Prefix; +import org.onlab.packet.MacAddress; +import org.onlab.packet.TpPort; +import org.onosproject.core.ApplicationId; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Port; +import org.onosproject.net.PortNumber; +import org.onosproject.net.flow.DefaultTrafficSelector; +import org.onosproject.net.flow.DefaultTrafficTreatment; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.flowobjective.DefaultForwardingObjective; +import org.onosproject.net.flowobjective.FlowObjectiveService; +import org.onosproject.net.flowobjective.ForwardingObjective; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * It populates switching flow rules. + * + */ +public class OpenstackSwitchingRulePopulator { + + private static Logger log = LoggerFactory + .getLogger(OpenstackSwitchingRulePopulator.class); + + private FlowObjectiveService flowObjectiveService; + private ApplicationId appId; + + /** + * Creates OpenstackSwitchingRulPopulator. + * + * @param appId application id + * @param flowObjectiveService FlowObjectiveService reference + */ + public OpenstackSwitchingRulePopulator(ApplicationId appId, + FlowObjectiveService flowObjectiveService) { + this.flowObjectiveService = flowObjectiveService; + this.appId = appId; + } + + /** + * Populates flows rules for forwarding packets to and from VMs. + * + * @param ip v4 IP Address + * @param id device ID + * @param port port + * @param cidr v4 IP prefix + * @return true if it succeeds to populate rules, false otherwise. + */ + public boolean populateForwardingRule(Ip4Address ip, DeviceId id, Port port, Ip4Prefix cidr) { + + + setFlowRuleForVMsInSameCnode(ip, id, port, cidr); + + return true; + } + + /** + * Populates the common flows rules for all VMs. + * + * - Send ARP packets to the controller + * - Send DHCP packets to the controller + * + * @param id Device ID to populates rules to + */ + public void populateDefaultRules(DeviceId id) { + + //setFlowRuleForDHCP(id); + setFlowRuleForArp(id); + + log.warn("Default rule has been set"); + } + + /** + * Populates the forwarding rules for VMs with the same VNI but in other Code. + * + * @param vni VNI for the networks + * @param id device ID to populates the flow rules + * @param hostIp host IP address of the VM + * @param vmIp fixed IP address for the VM + * @param vmMac MAC address for the VM + * @param tunnelPort tunnel port number for the VM + * @param idx device ID for OVS of the other VM + * @param hostIpx host IP address of the other VM + * @param vmIpx fixed IP address of the other VM + * @param vmMacx MAC address for the other VM + * @param tunnelPortx x tunnel port number for other VM + */ + public void populateForwardingRuleForOtherCnode(String vni, DeviceId id, Ip4Address hostIp, + Ip4Address vmIp, MacAddress vmMac, PortNumber tunnelPort, + DeviceId idx, Ip4Address hostIpx, + Ip4Address vmIpx, MacAddress vmMacx, PortNumber tunnelPortx) { + setVxLanFlowRule(vni, id, hostIp, vmIp, vmMac, tunnelPort); + setVxLanFlowRule(vni, idx, hostIpx, vmIpx, vmMacx, tunnelPortx); + } + + /** + * Populates the flow rules for DHCP packets from VMs. + * + * @param id device ID to set the rules + */ + private void setFlowRuleForDHCP(DeviceId id) { + TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); + + sBuilder.matchEthType(Ethernet.TYPE_IPV4) + .matchIPProtocol(IPv4.PROTOCOL_UDP) + .matchUdpDst(TpPort.tpPort(OpenstackSwitchingManager.DHCP_PORT)); + tBuilder.setOutput(PortNumber.CONTROLLER); + + ForwardingObjective fo = DefaultForwardingObjective.builder() + .withSelector(sBuilder.build()) + .withTreatment(tBuilder.build()) + .withPriority(5000) + .withFlag(ForwardingObjective.Flag.VERSATILE) + .fromApp(appId) + .add(); + + flowObjectiveService.forward(id, fo); + } + + /** + * Populates the flow rules for ARP packets from VMs. + * + * @param id device ID to put rules. + */ + private void setFlowRuleForArp(DeviceId id) { + TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); + + sBuilder.matchEthType(Ethernet.TYPE_ARP); + tBuilder.setOutput(PortNumber.CONTROLLER); + + ForwardingObjective fo = DefaultForwardingObjective.builder() + .withSelector(sBuilder.build()) + .withTreatment(tBuilder.build()) + .withPriority(5000) + .withFlag(ForwardingObjective.Flag.VERSATILE) + .fromApp(appId) + .add(); + + flowObjectiveService.forward(id, fo); + } + + /** + * Sets the flow rules for traffic between VMs in the same Cnode. + * + * @param ip4Address VM IP address + * @param id device ID to put rules + * @param port VM port + * @param cidr subnet info of the VMs + */ + private void setFlowRuleForVMsInSameCnode(Ip4Address ip4Address, DeviceId id, + Port port, Ip4Prefix cidr) { + TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); + + sBuilder.matchEthType(Ethernet.TYPE_IPV4) + .matchIPDst(ip4Address.toIpPrefix()) + .matchIPSrc(cidr); + tBuilder.setOutput(port.number()); + + ForwardingObjective fo = DefaultForwardingObjective.builder() + .withSelector(sBuilder.build()) + .withTreatment(tBuilder.build()) + .withPriority(5000) + .withFlag(ForwardingObjective.Flag.VERSATILE) + .fromApp(appId) + .add(); + + flowObjectiveService.forward(id, fo); + } + + /** + * Sets the flow rules between traffic from VMs in different Cnode. + * + * @param vni VNI + * @param id device ID + * @param hostIp host IP of the VM + * @param vmIp fixed IP of the VM + * @param vmMac MAC address of the VM + * @param tunnelPort tunnel port to forward traffic to + */ + private void setVxLanFlowRule(String vni, DeviceId id, Ip4Address hostIp, + Ip4Address vmIp, MacAddress vmMac, PortNumber tunnelPort) { + TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); + + sBuilder.matchEthType(Ethernet.TYPE_IPV4) + .matchIPDst(vmIp.toIpPrefix()); + tBuilder.setTunnelId(Long.parseLong(vni)) + //.setTunnelDst() <- for Nicira ext + //.setEthDst(vmMac) + .setOutput(tunnelPort); + + ForwardingObjective fo = DefaultForwardingObjective.builder() + .withSelector(sBuilder.build()) + .withTreatment(tBuilder.build()) + .withPriority(5000) + .withFlag(ForwardingObjective.Flag.VERSATILE) + .fromApp(appId) + .add(); + + flowObjectiveService.forward(id, fo); + } +} diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingService.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingService.java new file mode 100644 index 00000000..d97b39c8 --- /dev/null +++ b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingService.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.openstackswitching; + +/** + * It handles port management REST API from Openstack for VMs. + */ +public interface OpenstackSwitchingService { + + /** + * Store the port information created by Openstack. + * + * @param openstackPort port information + */ + void createPorts(OpenstackPort openstackPort); + + /** + * Removes flow rules corresponding to the port removed by Openstack. + * + */ + void deletePorts(); + + /** + * Updates flow rules corresponding to the port information updated by Openstack. + * + */ + void updatePorts(); + + /** + * Store the network information created by openstack. + * + * @param openstackNetwork network information + */ + void createNetwork(OpenstackNetwork openstackNetwork); + +} diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/package-info.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/package-info.java new file mode 100644 index 00000000..cd50f912 --- /dev/null +++ b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/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. + */ + +/** + * OpenStack switch interface. + */ +package org.onosproject.openstackswitching; diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackNetworkCodec.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackNetworkCodec.java new file mode 100644 index 00000000..43bd1583 --- /dev/null +++ b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackNetworkCodec.java @@ -0,0 +1,64 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.openstackswitching.web; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; +import org.onosproject.openstackswitching.OpenstackNetwork; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Implementation of the OpenstackNetwork Codec. + * + */ +public class OpenstackNetworkCodec extends JsonCodec { + + protected static final Logger log = LoggerFactory + .getLogger(OpenstackNetworkCodec.class); + + private static final String NETWORK = "network"; + private static final String NAME = "name"; + private static final String TENANT_ID = "tenant_id"; + private static final String SEGMENTATION_ID = "provider:segmentation_id"; + private static final String NETWORK_TYPE = "provider:network_type"; + private static final String ID = "id"; + + @Override + public OpenstackNetwork decode(ObjectNode json, CodecContext context) { + + JsonNode networkInfo = json.get(NETWORK); + + String name = networkInfo.path(NAME).asText(); + String tenantId = networkInfo.path(TENANT_ID).asText(); + String id = networkInfo.path(ID).asText(); + + OpenstackNetwork.Builder onb = OpenstackNetwork.builder(); + onb.name(name) + .tenantId(tenantId) + .id(id); + + if (!networkInfo.path(NETWORK_TYPE).isMissingNode()) { + onb.name(networkInfo.path(NETWORK_TYPE).asText()); + onb.segmentId(networkInfo.path(SEGMENTATION_ID).asText()); + } + + return onb.build(); + } + +} diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackNetworkWebResource.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackNetworkWebResource.java new file mode 100644 index 00000000..f4c401fb --- /dev/null +++ b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackNetworkWebResource.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.openstackswitching.web; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.onosproject.openstackswitching.OpenstackNetwork; +import org.onosproject.openstackswitching.OpenstackSwitchingService; +import org.onosproject.rest.AbstractWebResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.ws.rs.Consumes; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.io.InputStream; + +@Path("networks") +public class OpenstackNetworkWebResource extends AbstractWebResource { + + protected static final Logger log = LoggerFactory + .getLogger(OpenstackNetworkWebResource.class); + + private static final OpenstackNetworkCodec NETWORK_CODEC = new OpenstackNetworkCodec(); + + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response createNetwork(InputStream input) { + try { + ObjectMapper mapper = new ObjectMapper(); + ObjectNode networkNode = (ObjectNode) mapper.readTree(input); + + OpenstackNetwork openstackNetwork = NETWORK_CODEC.decode(networkNode, this); + + OpenstackSwitchingService switchingService = get(OpenstackSwitchingService.class); + switchingService.createNetwork(openstackNetwork); + return Response.status(Response.Status.OK).build(); + } catch (Exception e) { + log.error("Creates VirtualPort failed because of exception {}", + e.toString()); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.toString()) + .build(); + } + } +} diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackPortCodec.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackPortCodec.java new file mode 100644 index 00000000..765b6901 --- /dev/null +++ b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackPortCodec.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.openstackswitching.web; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.onlab.packet.Ip4Address; +import org.onlab.packet.MacAddress; +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; +import org.onosproject.openstackswitching.OpenstackPort; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; + +/** + * It encodes and decodes the OpenstackPort. + */ +public class OpenstackPortCodec extends JsonCodec { + + private static Logger log = LoggerFactory + .getLogger(OpenstackPortCodec.class); + + // JSON field names + private static final String PORT = "port"; + private static final String STATUS = "status"; + private static final String NAME = "name"; + private static final String ADDRESS_PAIR = "allowed_address_pairs"; + private static final String ADMIN_STATUS = "admin_status"; + private static final String NETWORK_ID = "network_id"; + private static final String TENANT_ID = "tenant_id"; + private static final String DEVICE_OWNER = "device_owner"; + private static final String MAC_ADDRESS = "mac_address"; + private static final String FIXED_IPS = "fixed_ips"; + private static final String SUBNET_ID = "subnet_id"; + private static final String IP_ADDRESS = "ip_address"; + private static final String ID = "id"; + private static final String SECURITY_GROUPS = "security_groups"; + private static final String DEVICE_ID = "device_id"; + + @Override + public OpenstackPort decode(ObjectNode json, CodecContext context) { + + HashMap fixedIpMap = new HashMap<>(); + JsonNode portInfo = json.get(PORT); + + String status = portInfo.path(STATUS).asText(); + String name = portInfo.path(NAME).asText(); + boolean adminStateUp = portInfo.path(ADMIN_STATUS).asBoolean(); + String networkId = portInfo.path(NETWORK_ID).asText(); + String tenantId = portInfo.path(TENANT_ID).asText(); + String deviceOwner = portInfo.path(DEVICE_OWNER).asText(); + String macStr = portInfo.path(MAC_ADDRESS).asText(); + ArrayNode fixedIpList = (ArrayNode) portInfo.path(FIXED_IPS); + for (JsonNode fixedIpInfo: fixedIpList) { + String subnetId = fixedIpInfo.path(SUBNET_ID).asText(); + String ipAddressStr = fixedIpInfo.path(IP_ADDRESS).asText(); + if (ipAddressStr != null) { + Ip4Address ipAddress = Ip4Address.valueOf(ipAddressStr); + fixedIpMap.put(subnetId, ipAddress); + } + } + String id = portInfo.path(ID).asText(); + String securityGroups = portInfo.path(SECURITY_GROUPS).asText(); + String deviceId = portInfo.path(DEVICE_ID).asText(); + + OpenstackPort.Builder openstackPortBuilder = OpenstackPort.builder(); + openstackPortBuilder.portStatus(OpenstackPort.PortStatus.valueOf(status)) + .name(name) + .adminState(adminStateUp) + .netwrokId(networkId) + .tenantId(tenantId) + .deviceOwner(deviceOwner) + .macAddress(MacAddress.valueOf(macStr)) + .fixedIps(fixedIpMap) + .id(id) + .deviceId(deviceId); + + // FIX ME + if (!securityGroups.isEmpty()) { + openstackPortBuilder.securityGroup(securityGroups); + } + + OpenstackPort openstackPort = openstackPortBuilder.build(); + + return openstackPort; + } + +} diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackPortWebResource.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackPortWebResource.java new file mode 100644 index 00000000..67a9cebb --- /dev/null +++ b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackPortWebResource.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.openstackswitching.web; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.onosproject.openstackswitching.OpenstackPort; +import org.onosproject.openstackswitching.OpenstackSwitchingService; +import org.onosproject.rest.AbstractWebResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.io.InputStream; + +@Path("ports") +public class OpenstackPortWebResource extends AbstractWebResource { + + protected static final Logger log = LoggerFactory + .getLogger(OpenstackPortWebResource.class); + + private static final OpenstackPortCodec PORT_CODEC = new OpenstackPortCodec(); + + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response createPorts(InputStream input) { + try { + ObjectMapper mapper = new ObjectMapper(); + ObjectNode portNode = (ObjectNode) mapper.readTree(input); + + OpenstackPort openstackPort = PORT_CODEC.decode(portNode, this); + + OpenstackSwitchingService switchingService = get(OpenstackSwitchingService.class); + switchingService.createPorts(openstackPort); + log.info("REST API ports is called with {}", portNode.toString()); + return Response.status(Response.Status.OK).build(); + } catch (Exception e) { + log.error("Creates VirtualPort failed because of exception {}", + e.toString()); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.toString()) + .build(); + } + } + + @DELETE + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response deletesPorts(InputStream input) { + try { + ObjectMapper mapper = new ObjectMapper(); + ObjectNode portNode = (ObjectNode) mapper.readTree(input); + + OpenstackSwitchingService switchingService = get(OpenstackSwitchingService.class); + switchingService.deletePorts(); + log.info("REST API ports is called with {}", portNode.toString()); + return Response.status(Response.Status.OK).build(); + } catch (Exception e) { + log.error("Delete VirtualPort failed because of exception {}", + e.toString()); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.toString()) + .build(); + } + } + + @PUT + @Path("{id}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response updatePorts(InputStream input) { + try { + ObjectMapper mapper = new ObjectMapper(); + ObjectNode portNode = (ObjectNode) mapper.readTree(input); + + OpenstackSwitchingService switchingService = get(OpenstackSwitchingService.class); + switchingService.updatePorts(); + log.info("REST API ports is called with {}", portNode.toString()); + return Response.status(Response.Status.OK).build(); + } catch (Exception e) { + log.error("Update VirtualPort failed because of exception {}", + e.toString()); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.toString()) + .build(); + } + } +} diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/package-info.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/package-info.java new file mode 100644 index 00000000..91e19c62 --- /dev/null +++ b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/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. + */ + +/** + * OpenStack switching REST API. + */ +package org.onosproject.openstackswitching.web; diff --git a/framework/src/onos/apps/openstackswitching/src/main/webapp/WEB-INF/web.xml b/framework/src/onos/apps/openstackswitching/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000..53b0e2e9 --- /dev/null +++ b/framework/src/onos/apps/openstackswitching/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,44 @@ + + + + Openstack Switching REST API v1.0 + + + JAX-RS Service + com.sun.jersey.spi.container.servlet.ServletContainer + + com.sun.jersey.config.property.resourceConfigClass + com.sun.jersey.api.core.ClassNamesResourceConfig + + + com.sun.jersey.config.property.classnames + + org.onosproject.openstackswitching.web.OpenstackPortWebResource, + org.onosproject.openstackswitching.web.OpenstackNetworkWebResource + + + 1 + + + + JAX-RS Service + /* + + 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 8466b95e..e0545023 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 @@ -15,6 +15,7 @@ */ package org.onosproject.optical; +import com.google.common.collect.ImmutableList; import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Deactivate; @@ -45,16 +46,16 @@ import org.onosproject.net.intent.IntentState; import org.onosproject.net.intent.OpticalCircuitIntent; import org.onosproject.net.intent.OpticalConnectivityIntent; import org.onosproject.net.intent.PointToPointIntent; +import org.onosproject.net.newresource.ResourceAllocation; import org.onosproject.net.newresource.ResourceService; import org.onosproject.net.resource.device.IntentSetMultimap; -import org.onosproject.net.resource.link.LinkResourceAllocations; -import org.onosproject.net.resource.link.LinkResourceService; import org.onosproject.net.topology.LinkWeight; import org.onosproject.net.topology.PathService; import org.onosproject.net.topology.TopologyEdge; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; @@ -100,9 +101,6 @@ public class OpticalPathProvisioner { @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected IntentSetMultimap intentSetMultimap; - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected LinkResourceService linkResourceService; - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected ResourceService resourceService; @@ -377,17 +375,17 @@ public class OpticalPathProvisioner { * @param intent the intent */ private void releaseResources(Intent intent) { - LinkResourceAllocations lra = linkResourceService.getAllocations(intent.id()); + Collection allocations = resourceService.getResourceAllocations(intent.id()); if (intent instanceof OpticalConnectivityIntent) { resourceService.release(intent.id()); - if (lra != null) { - linkResourceService.releaseResources(lra); + if (!allocations.isEmpty()) { + resourceService.release(ImmutableList.copyOf(allocations)); } } else if (intent instanceof OpticalCircuitIntent) { resourceService.release(intent.id()); intentSetMultimap.releaseMapping(intent.id()); - if (lra != null) { - linkResourceService.releaseResources(lra); + if (!allocations.isEmpty()) { + resourceService.release(ImmutableList.copyOf(allocations)); } } } diff --git a/framework/src/onos/apps/pom.xml b/framework/src/onos/apps/pom.xml index 98210736..005052fb 100644 --- a/framework/src/onos/apps/pom.xml +++ b/framework/src/onos/apps/pom.xml @@ -13,10 +13,7 @@ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ~ See the License for the specific language governing permissions and ~ limitations under the License. - --> - + --> 4.0.0 @@ -60,6 +57,7 @@ igmp pim mlb + openstackswitching 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 b2ce0f8a..a27baaf9 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,8 +15,6 @@ */ package org.onosproject.sdnip; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; import org.onlab.packet.Ethernet; import org.onlab.packet.IPv4; import org.onlab.packet.IPv6; @@ -27,6 +25,8 @@ import org.onosproject.core.ApplicationId; import org.onosproject.incubator.net.intf.Interface; import org.onosproject.incubator.net.intf.InterfaceService; import org.onosproject.net.ConnectPoint; +import org.onosproject.net.config.NetworkConfigEvent; +import org.onosproject.net.config.NetworkConfigListener; import org.onosproject.net.config.NetworkConfigService; import org.onosproject.net.flow.DefaultTrafficSelector; import org.onosproject.net.flow.DefaultTrafficTreatment; @@ -43,7 +43,9 @@ import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.List; +import java.util.Map; import static com.google.common.base.Preconditions.checkNotNull; @@ -69,9 +71,10 @@ public class PeerConnectivityManager { private final ApplicationId appId; private final ApplicationId routerAppId; - // Just putting something random here for now. Figure out exactly what - // indexes we need when we start making use of them. - private final Multimap peerIntents; + private final Map peerIntents; + + private final InternalNetworkConfigListener configListener + = new InternalNetworkConfigListener(); /** * Creates a new PeerConnectivityManager. @@ -93,13 +96,14 @@ public class PeerConnectivityManager { this.routerAppId = routerAppId; this.interfaceService = interfaceService; - peerIntents = HashMultimap.create(); + peerIntents = new HashMap<>(); } /** * Starts the peer connectivity manager. */ public void start() { + configService.addListener(configListener); setUpConnectivity(); } @@ -107,6 +111,7 @@ public class PeerConnectivityManager { * Stops the peer connectivity manager. */ public void stop() { + configService.removeListener(configListener); } /** @@ -121,16 +126,27 @@ public class PeerConnectivityManager { return; } + Map existingIntents = new HashMap<>(peerIntents); + for (BgpConfig.BgpSpeakerConfig bgpSpeaker : config.bgpSpeakers()) { log.debug("Start to set up BGP paths for BGP speaker: {}", bgpSpeaker); buildSpeakerIntents(bgpSpeaker).forEach(i -> { - peerIntents.put(bgpSpeaker, i); - intentSynchronizer.submit(i); + PointToPointIntent intent = existingIntents.remove(i.key()); + if (intent == null || !IntentUtils.equals(i, intent)) { + peerIntents.put(i.key(), i); + intentSynchronizer.submit(i); + } }); - } + + // Remove any remaining intents that we used to have that we don't need + // anymore + existingIntents.values().forEach(i -> { + peerIntents.remove(i.key()); + intentSynchronizer.withdraw(i); + }); } private Collection buildSpeakerIntents(BgpConfig.BgpSpeakerConfig speaker) { @@ -356,7 +372,7 @@ public class PeerConnectivityManager { * @param srcIp source IP address * @param dstIp destination IP address * @param suffix suffix string - * @return + * @return intent key */ private Key buildKey(IpAddress srcIp, IpAddress dstIp, String suffix) { String keyString = new StringBuilder() @@ -370,4 +386,26 @@ public class PeerConnectivityManager { return Key.of(keyString, appId); } + private class InternalNetworkConfigListener implements NetworkConfigListener { + + @Override + public void event(NetworkConfigEvent event) { + switch (event.type()) { + case CONFIG_REGISTERED: + break; + case CONFIG_UNREGISTERED: + break; + case CONFIG_ADDED: + case CONFIG_UPDATED: + case CONFIG_REMOVED: + if (event.configClass() == RoutingService.CONFIG_CLASS) { + setUpConnectivity(); + } + break; + default: + break; + } + } + } + } 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 c4b2daad..0dcc969d 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 @@ -34,6 +34,7 @@ import org.onosproject.incubator.net.intf.InterfaceService; import org.onosproject.net.ConnectPoint; import org.onosproject.net.DeviceId; import org.onosproject.net.PortNumber; +import org.onosproject.net.config.NetworkConfigListener; import org.onosproject.net.config.NetworkConfigService; import org.onosproject.net.flow.DefaultTrafficSelector; import org.onosproject.net.flow.DefaultTrafficTreatment; @@ -60,8 +61,10 @@ import java.util.Map; import java.util.Optional; import java.util.Set; +import static org.easymock.EasyMock.anyObject; import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.expectLastCall; import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.reset; import static org.easymock.EasyMock.verify; @@ -119,6 +122,8 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest { routingConfig = createMock(RoutingConfigurationService.class); interfaceService = createMock(InterfaceService.class); networkConfigService = createMock(NetworkConfigService.class); + networkConfigService.addListener(anyObject(NetworkConfigListener.class)); + expectLastCall().anyTimes(); bgpConfig = createMock(BgpConfig.class); // These will set expectations on routingConfig and interfaceService diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/ArpHandler.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/ArpHandler.java index f42f84b1..36563f01 100644 --- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/ArpHandler.java +++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/ArpHandler.java @@ -35,7 +35,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.nio.ByteBuffer; -import java.util.List; +import java.util.Set; + import static com.google.common.base.Preconditions.checkNotNull; public class ArpHandler { @@ -112,7 +113,7 @@ public class ArpHandler { private boolean isArpReqForRouter(DeviceId deviceId, ARP arpRequest) { - List gatewayIpAddresses = config.getSubnetGatewayIps(deviceId); + Set gatewayIpAddresses = config.getPortIPs(deviceId); if (gatewayIpAddresses != null) { Ip4Address targetProtocolAddress = Ip4Address.valueOf(arpRequest .getTargetProtocolAddress()); diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java index 40ee55fc..c4a91c75 100644 --- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java +++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java @@ -23,14 +23,12 @@ import org.onlab.packet.IpPrefix; import org.onosproject.net.Device; import org.onosproject.net.DeviceId; import org.onosproject.net.Link; -import org.onosproject.net.MastershipRole; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; -import java.util.List; import java.util.Set; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; @@ -97,7 +95,7 @@ public class DefaultRoutingHandler { log.debug("populateAllRoutingRules: populationStatus is STARTED"); for (Device sw : srManager.deviceService.getDevices()) { - if (srManager.mastershipService.getLocalRole(sw.id()) != MastershipRole.MASTER) { + if (!srManager.mastershipService.isLocalMaster(sw.id())) { log.debug("populateAllRoutingRules: skipping device {}...we are not master", sw.id()); continue; @@ -146,8 +144,7 @@ public class DefaultRoutingHandler { // Take the snapshots of the links updatedEcmpSpgMap = new HashMap<>(); for (Device sw : srManager.deviceService.getDevices()) { - if (srManager.mastershipService. - getLocalRole(sw.id()) != MastershipRole.MASTER) { + if (!srManager.mastershipService.isLocalMaster(sw.id())) { continue; } ECMPShortestPathGraph ecmpSpgUpdated = @@ -273,8 +270,7 @@ public class DefaultRoutingHandler { for (Device sw : srManager.deviceService.getDevices()) { log.debug("Computing the impacted routes for device {} due to link fail", sw.id()); - if (srManager.mastershipService. - getLocalRole(sw.id()) != MastershipRole.MASTER) { + if (!srManager.mastershipService.isLocalMaster(sw.id())) { continue; } ECMPShortestPathGraph ecmpSpg = currentEcmpSpgMap.get(sw.id()); @@ -320,8 +316,7 @@ public class DefaultRoutingHandler { for (Device sw : srManager.deviceService.getDevices()) { log.debug("Computing the impacted routes for device {}", sw.id()); - if (srManager.mastershipService. - getLocalRole(sw.id()) != MastershipRole.MASTER) { + if (!srManager.mastershipService.isLocalMaster(sw.id())) { log.debug("No mastership for {} and skip route optimization", sw.id()); continue; @@ -455,7 +450,7 @@ public class DefaultRoutingHandler { // If both target switch and dest switch are edge routers, then set IP // rule for both subnet and router IP. if (config.isEdgeDevice(targetSw) && config.isEdgeDevice(destSw)) { - List subnets = config.getSubnets(destSw); + Set subnets = config.getSubnets(destSw); log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for subnets {}", targetSw, destSw, subnets); result = rulePopulator.populateIpRuleForSubnet(targetSw, @@ -499,14 +494,13 @@ public class DefaultRoutingHandler { } /** - * Populates table miss entries for all tables, and pipeline rules for VLAN - * and TCAM tables. XXX rename/rethink + * Populates filtering rules for permitting Router DstMac and VLAN. * * @param deviceId Switch ID to set the rules */ - public void populateTtpRules(DeviceId deviceId) { - rulePopulator.populateTableVlan(deviceId); - rulePopulator.populateTableTMac(deviceId); + public void populatePortAddressingRules(DeviceId deviceId) { + rulePopulator.populateRouterMacVlanFilters(deviceId); + rulePopulator.populateRouterIpPunts(deviceId); } /** 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 0bc155b8..828c51ce 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 @@ -15,6 +15,7 @@ */ package org.onosproject.segmentrouting; +import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import org.onlab.packet.Ip4Address; import org.onlab.packet.Ip4Prefix; @@ -38,20 +39,20 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; /** * Segment Routing configuration component that reads the * segment routing related configuration from Network Configuration Manager * component and organizes in more accessible formats. - * - * TODO: Merge multiple Segment Routing configuration wrapper classes into one. */ public class DeviceConfiguration implements DeviceProperties { private static final Logger log = LoggerFactory .getLogger(DeviceConfiguration.class); private final List allSegmentIds = new ArrayList<>(); - private final HashMap deviceConfigMap = new HashMap<>(); + private final ConcurrentHashMap deviceConfigMap + = new ConcurrentHashMap<>(); private class SegmentRouterInfo { int nodeSid; @@ -126,18 +127,17 @@ public class DeviceConfiguration implements DeviceProperties { } /** - * Returns the segment id of a segment router. + * Returns the Node segment id of a segment router. * * @param deviceId device identifier * @return segment id */ @Override public int getSegmentId(DeviceId deviceId) { - if (deviceConfigMap.get(deviceId) != null) { - log.trace("getSegmentId for device{} is {}", - deviceId, - deviceConfigMap.get(deviceId).nodeSid); - return deviceConfigMap.get(deviceId).nodeSid; + SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId); + if (srinfo != null) { + log.trace("getSegmentId for device{} is {}", deviceId, srinfo.nodeSid); + return srinfo.nodeSid; } else { log.warn("getSegmentId for device {} " + "throwing IllegalStateException " @@ -147,10 +147,10 @@ public class DeviceConfiguration implements DeviceProperties { } /** - * Returns the segment id of a segment router given its mac address. + * Returns the Node segment id of a segment router given its Router mac address. * * @param routerMac router mac address - * @return segment id + * @return node segment id, or -1 if not found in config */ public int getSegmentId(MacAddress routerMac) { for (Map.Entry entry: @@ -164,10 +164,10 @@ public class DeviceConfiguration implements DeviceProperties { } /** - * Returns the segment id of a segment router given its router ip address. + * Returns the Node segment id of a segment router given its Router ip address. * * @param routerAddress router ip address - * @return segment id + * @return node segment id, or -1 if not found in config */ public int getSegmentId(Ip4Address routerAddress) { for (Map.Entry entry: @@ -188,11 +188,10 @@ public class DeviceConfiguration implements DeviceProperties { */ @Override public MacAddress getDeviceMac(DeviceId deviceId) { - if (deviceConfigMap.get(deviceId) != null) { - log.trace("getDeviceMac for device{} is {}", - deviceId, - deviceConfigMap.get(deviceId).mac); - return deviceConfigMap.get(deviceId).mac; + SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId); + if (srinfo != null) { + log.trace("getDeviceMac for device{} is {}", deviceId, srinfo.mac); + return srinfo.mac; } else { log.warn("getDeviceMac for device {} " + "throwing IllegalStateException " @@ -208,11 +207,10 @@ public class DeviceConfiguration implements DeviceProperties { * @return router ip address */ public Ip4Address getRouterIp(DeviceId deviceId) { - if (deviceConfigMap.get(deviceId) != null) { - log.trace("getDeviceIp for device{} is {}", - deviceId, - deviceConfigMap.get(deviceId).ip); - return deviceConfigMap.get(deviceId).ip; + SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId); + if (srinfo != null) { + log.trace("getDeviceIp for device{} is {}", deviceId, srinfo.ip); + return srinfo.ip; } else { log.warn("getRouterIp for device {} " + "throwing IllegalStateException " @@ -223,18 +221,17 @@ public class DeviceConfiguration implements DeviceProperties { /** * Indicates if the segment router is a edge router or - * a transit/back bone router. + * a core/backbone router. * * @param deviceId device identifier * @return boolean */ @Override public boolean isEdgeDevice(DeviceId deviceId) { - if (deviceConfigMap.get(deviceId) != null) { - log.trace("isEdgeDevice for device{} is {}", - deviceId, - deviceConfigMap.get(deviceId).isEdge); - return deviceConfigMap.get(deviceId).isEdge; + SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId); + if (srinfo != null) { + log.trace("isEdgeDevice for device{} is {}", deviceId, srinfo.isEdge); + return srinfo.isEdge; } else { log.warn("isEdgeDevice for device {} " + "throwing IllegalStateException " @@ -244,15 +241,35 @@ public class DeviceConfiguration implements DeviceProperties { } /** - * Returns the segment ids of all configured segment routers. + * Returns the node segment ids of all configured segment routers. * - * @return list of segment ids + * @return list of node segment ids */ @Override public List getAllDeviceSegmentIds() { return allSegmentIds; } + @Override + public Map> getSubnetPortsMap(DeviceId deviceId) { + Map> subnetPortMap = new HashMap<>(); + + // Construct subnet-port mapping from port-subnet mapping + Map portSubnetMap = + this.deviceConfigMap.get(deviceId).subnets; + portSubnetMap.forEach((port, subnet) -> { + if (subnetPortMap.containsKey(subnet)) { + subnetPortMap.get(subnet).add(port); + } else { + ArrayList ports = new ArrayList<>(); + ports.add(port); + subnetPortMap.put(subnet, ports); + } + }); + + return subnetPortMap; + } + /** * Returns the device identifier or data plane identifier (dpid) * of a segment router given its segment id. @@ -290,37 +307,68 @@ public class DeviceConfiguration implements DeviceProperties { } /** - * Returns the configured subnet gateway ip addresses for a segment router. + * Returns the configured port ip addresses for a segment router. + * These addresses serve as gateway IP addresses for the subnets configured + * on those ports. * * @param deviceId device identifier - * @return list of ip addresses + * @return immutable set of ip addresses configured on the ports or null if not found */ - public List getSubnetGatewayIps(DeviceId deviceId) { - if (deviceConfigMap.get(deviceId) != null) { - log.trace("getSubnetGatewayIps for device{} is {}", - deviceId, - deviceConfigMap.get(deviceId).gatewayIps.values()); - return new ArrayList<>(deviceConfigMap.get(deviceId).gatewayIps.values()); - } else { - return null; + public Set getPortIPs(DeviceId deviceId) { + SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId); + if (srinfo != null) { + log.trace("getSubnetGatewayIps for device{} is {}", deviceId, + srinfo.gatewayIps.values()); + return ImmutableSet.copyOf(srinfo.gatewayIps.values()); + } + return null; + } + + /** + * Returns the configured IP addresses per port + * for a segment router. + * + * @param deviceId device identifier + * @return map of port to gateway IP addresses or null if not found + */ + public Map getPortIPMap(DeviceId deviceId) { + SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId); + if (srinfo != null) { + return srinfo.gatewayIps; } + return null; } /** * Returns the configured subnet prefixes for a segment router. * * @param deviceId device identifier - * @return list of ip prefixes + * @return list of ip prefixes or null if not found */ - public List getSubnets(DeviceId deviceId) { - if (deviceConfigMap.get(deviceId) != null) { - log.trace("getSubnets for device{} is {}", - deviceId, - deviceConfigMap.get(deviceId).subnets.values()); - return new ArrayList<>(deviceConfigMap.get(deviceId).subnets.values()); - } else { - return null; + public Set getSubnets(DeviceId deviceId) { + SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId); + if (srinfo != null) { + log.trace("getSubnets for device{} is {}", deviceId, + srinfo.subnets.values()); + return ImmutableSet.copyOf(srinfo.subnets.values()); } + return null; + } + + /** + * Returns the configured subnet on the given port, or null if no + * subnet has been configured on the port. + * + * @param deviceId device identifier + * @param pnum port identifier + * @return configured subnet on port, or null + */ + public Ip4Prefix getPortSubnet(DeviceId deviceId, PortNumber pnum) { + SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId); + if (srinfo != null) { + return srinfo.subnets.get(pnum); + } + return null; } /** @@ -349,7 +397,7 @@ public class DeviceConfiguration implements DeviceProperties { * specified ip address as one of its subnet gateway ip address. * * @param gatewayIpAddress router gateway ip address - * @return router mac address + * @return router mac address or null if not found */ public MacAddress getRouterMacForAGatewayIp(Ip4Address gatewayIpAddress) { for (Map.Entry entry: @@ -377,7 +425,7 @@ public class DeviceConfiguration implements DeviceProperties { */ public boolean inSameSubnet(DeviceId deviceId, Ip4Address hostIp) { - List subnets = getSubnets(deviceId); + Set subnets = getSubnets(deviceId); if (subnets == null) { return false; } @@ -399,8 +447,9 @@ public class DeviceConfiguration implements DeviceProperties { * @return list of port numbers */ public List getPortsForAdjacencySid(DeviceId deviceId, int sid) { - if (deviceConfigMap.get(deviceId) != null) { - for (AdjacencySid asid : deviceConfigMap.get(deviceId).adjacencySids) { + SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId); + if (srinfo != null) { + for (AdjacencySid asid : srinfo.adjacencySids) { if (asid.getAsid() == sid) { return asid.getPorts(); } @@ -419,12 +468,13 @@ public class DeviceConfiguration implements DeviceProperties { * otherwise false */ public boolean isAdjacencySid(DeviceId deviceId, int sid) { - if (deviceConfigMap.get(deviceId) != null) { - if (deviceConfigMap.get(deviceId).adjacencySids.isEmpty()) { + SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId); + if (srinfo != null) { + if (srinfo.adjacencySids.isEmpty()) { return false; } else { for (AdjacencySid asid: - deviceConfigMap.get(deviceId).adjacencySids) { + srinfo.adjacencySids) { if (asid.getAsid() == sid) { return true; } 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 f65f03e0..b3916b06 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 @@ -32,7 +32,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.nio.ByteBuffer; -import java.util.List; +import java.util.Set; import static com.google.common.base.Preconditions.checkNotNull; @@ -70,7 +70,7 @@ public class IcmpHandler { DeviceId deviceId = connectPoint.deviceId(); Ip4Address destinationAddress = Ip4Address.valueOf(ipv4.getDestinationAddress()); - List gatewayIpAddresses = config.getSubnetGatewayIps(deviceId); + Set gatewayIpAddresses = config.getPortIPs(deviceId); Ip4Address routerIp = config.getRouterIp(deviceId); IpPrefix routerIpPrefix = IpPrefix.valueOf(routerIp, IpPrefix.MAX_INET_MASK_LENGTH); Ip4Address routerIpAddress = routerIpPrefix.getIp4Prefix().address(); diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java index 7641571d..d46028e7 100644 --- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java +++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java @@ -25,6 +25,7 @@ import org.onlab.packet.VlanId; import org.onosproject.segmentrouting.grouphandler.NeighborSet; import org.onosproject.net.DeviceId; import org.onosproject.net.Link; +import org.onosproject.net.Port; import org.onosproject.net.PortNumber; import org.onosproject.net.flow.DefaultTrafficSelector; import org.onosproject.net.flow.DefaultTrafficTreatment; @@ -38,11 +39,13 @@ import org.onosproject.net.flowobjective.ForwardingObjective; import org.onosproject.net.flowobjective.Objective; import org.onosproject.net.flowobjective.ObjectiveError; import org.onosproject.net.flowobjective.ForwardingObjective.Builder; +import org.onosproject.net.flowobjective.ForwardingObjective.Flag; import org.onosproject.net.flowobjective.ObjectiveContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicLong; @@ -57,6 +60,11 @@ public class RoutingRulePopulator { private AtomicLong rulePopulationCounter; private SegmentRoutingManager srManager; private DeviceConfiguration config; + + private static final int HIGHEST_PRIORITY = 0xffff; + private static final long OFPP_MAX = 0xffffff00L; + + /** * Creates a RoutingRulePopulator object. * @@ -98,7 +106,7 @@ public class RoutingRulePopulator { TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder(); TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder(); - sbuilder.matchIPDst(IpPrefix.valueOf(hostIp, 32)); + sbuilder.matchIPDst(IpPrefix.valueOf(hostIp, IpPrefix.MAX_INET_MASK_LENGTH)); sbuilder.matchEthType(Ethernet.TYPE_IPV4); tbuilder.deferred() @@ -134,7 +142,7 @@ public class RoutingRulePopulator { * @return true if all rules are set successfully, false otherwise */ public boolean populateIpRuleForSubnet(DeviceId deviceId, - List subnets, + Set subnets, DeviceId destSw, Set nextHops) { @@ -350,40 +358,80 @@ public class RoutingRulePopulator { } /** - * Populates VLAN flows rules. All packets are forwarded to TMAC table. + * Creates a filtering objective to permit all untagged packets with a + * dstMac corresponding to the router's MAC address. For those pipelines + * that need to internally assign vlans to untagged packets, this method + * provides per-subnet vlan-ids as metadata. + *

+ * Note that the vlan assignment is only done by the master-instance for a switch. + * However we send the filtering objective from slave-instances as well, so + * that drivers can obtain other information (like Router MAC and IP). * - * @param deviceId switch ID to set the rules + * @param deviceId the switch dpid for the router */ - public void populateTableVlan(DeviceId deviceId) { - FilteringObjective.Builder fob = DefaultFilteringObjective.builder(); - fob.withKey(Criteria.matchInPort(PortNumber.ALL)) + public void populateRouterMacVlanFilters(DeviceId deviceId) { + log.debug("Installing per-port filtering objective for untagged " + + "packets in device {}", deviceId); + for (Port port : srManager.deviceService.getPorts(deviceId)) { + if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) { + Ip4Prefix portSubnet = config.getPortSubnet(deviceId, port.number()); + VlanId assignedVlan = (portSubnet == null) + ? VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET) + : srManager.getSubnetAssignedVlanId(deviceId, portSubnet); + FilteringObjective.Builder fob = DefaultFilteringObjective.builder(); + fob.withKey(Criteria.matchInPort(port.number())) + .addCondition(Criteria.matchEthDst(config.getDeviceMac(deviceId))) .addCondition(Criteria.matchVlanId(VlanId.NONE)); - fob.permit().fromApp(srManager.appId); - log.debug("populateTableVlan: Installing filtering objective for untagged packets"); - srManager.flowObjectiveService. - filter(deviceId, - fob.add(new SRObjectiveContext(deviceId, - SRObjectiveContext.ObjectiveType.FILTER))); + // vlan assignment is valid only if this instance is master + if (srManager.mastershipService.isLocalMaster(deviceId)) { + TrafficTreatment tt = DefaultTrafficTreatment.builder() + .pushVlan().setVlanId(assignedVlan).build(); + fob.setMeta(tt); + } + fob.permit().fromApp(srManager.appId); + srManager.flowObjectiveService. + filter(deviceId, fob.add(new SRObjectiveContext(deviceId, + SRObjectiveContext.ObjectiveType.FILTER))); + } + } } /** - * Populates TMAC table rules. IP packets are forwarded to IP table. MPLS - * packets are forwarded to MPLS table. + * Creates a forwarding objective to punt all IP packets, destined to the + * router's port IP addresses, to the controller. Note that the input + * port should not be matched on, as these packets can come from any input. + * Furthermore, these are applied only by the master instance. * - * @param deviceId switch ID to set the rules + * @param deviceId the switch dpid for the router */ - public void populateTableTMac(DeviceId deviceId) { - - FilteringObjective.Builder fob = DefaultFilteringObjective.builder(); - fob.withKey(Criteria.matchInPort(PortNumber.ALL)) - .addCondition(Criteria.matchEthDst(config - .getDeviceMac(deviceId))); - fob.permit().fromApp(srManager.appId); - log.debug("populateTableTMac: Installing filtering objective for router mac"); - srManager.flowObjectiveService. - filter(deviceId, - fob.add(new SRObjectiveContext(deviceId, - SRObjectiveContext.ObjectiveType.FILTER))); + public void populateRouterIpPunts(DeviceId deviceId) { + if (!srManager.mastershipService.isLocalMaster(deviceId)) { + log.debug("Not installing port-IP punts - not the master for dev:{} ", + deviceId); + return; + } + ForwardingObjective.Builder puntIp = DefaultForwardingObjective.builder(); + Set allIps = new HashSet(config.getPortIPs(deviceId)); + allIps.add(config.getRouterIp(deviceId)); + for (Ip4Address ipaddr : allIps) { + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); + selector.matchEthType(Ethernet.TYPE_IPV4); + selector.matchIPDst(IpPrefix.valueOf(ipaddr, + IpPrefix.MAX_INET_MASK_LENGTH)); + treatment.setOutput(PortNumber.CONTROLLER); + puntIp.withSelector(selector.build()); + puntIp.withTreatment(treatment.build()); + puntIp.withFlag(Flag.VERSATILE) + .withPriority(HIGHEST_PRIORITY) + .makePermanent() + .fromApp(srManager.appId); + log.debug("Installing forwarding objective to punt port IP addresses"); + srManager.flowObjectiveService. + forward(deviceId, + puntIp.add(new SRObjectiveContext(deviceId, + SRObjectiveContext.ObjectiveType.FORWARDING))); + } } private PortNumber selectOnePort(DeviceId srcId, Set destIds) { 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 eb2cf569..9d60b279 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 @@ -22,11 +22,17 @@ import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.ReferenceCardinality; import org.apache.felix.scr.annotations.Service; import org.onlab.packet.Ethernet; +import org.onlab.packet.VlanId; import org.onlab.packet.IPv4; +import org.onlab.packet.Ip4Address; +import org.onlab.packet.Ip4Prefix; +import org.onlab.packet.IpAddress; +import org.onlab.packet.IpPrefix; import org.onlab.util.KryoNamespace; import org.onosproject.core.ApplicationId; import org.onosproject.core.CoreService; import org.onosproject.event.Event; +import org.onosproject.net.ConnectPoint; import org.onosproject.net.config.ConfigFactory; import org.onosproject.net.config.NetworkConfigEvent; import org.onosproject.net.config.NetworkConfigRegistry; @@ -45,7 +51,6 @@ import org.onosproject.net.device.DeviceEvent; import org.onosproject.net.device.DeviceListener; import org.onosproject.net.device.DeviceService; import org.onosproject.net.flowobjective.FlowObjectiveService; -import org.onosproject.net.group.GroupKey; import org.onosproject.net.host.HostService; import org.onosproject.net.intent.IntentService; import org.onosproject.net.link.LinkEvent; @@ -56,6 +61,7 @@ import org.onosproject.net.packet.PacketContext; import org.onosproject.net.packet.PacketProcessor; import org.onosproject.net.packet.PacketService; import org.onosproject.net.topology.TopologyService; +import org.onosproject.segmentrouting.grouphandler.SubnetNextObjectiveStoreKey; import org.onosproject.store.service.EventuallyConsistentMap; import org.onosproject.store.service.EventuallyConsistentMapBuilder; import org.onosproject.store.service.StorageService; @@ -64,9 +70,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.net.URI; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.Executors; @@ -133,8 +141,13 @@ public class SegmentRoutingManager implements SegmentRoutingService { // Per device next objective ID store with (device id + neighbor set) as key private EventuallyConsistentMap nsNextObjStore = null; + private EventuallyConsistentMap subnetNextObjStore = null; private EventuallyConsistentMap tunnelStore = null; private EventuallyConsistentMap policyStore = null; + // Per device, per-subnet assigned-vlans store, with (device id + subnet + // IPv4 prefix) as key + private EventuallyConsistentMap + subnetVidStore = null; @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected StorageService storageService; @@ -163,6 +176,9 @@ public class SegmentRoutingManager implements SegmentRoutingService { private KryoNamespace.Builder kryoBuilder = null; + private static final short ASSIGNED_VLAN_START = 4093; + public static final short ASSIGNED_VLAN_NO_SUBNET = 4094; + @Activate protected void activate() { appId = coreService @@ -170,6 +186,8 @@ public class SegmentRoutingManager implements SegmentRoutingService { kryoBuilder = new KryoNamespace.Builder() .register(NeighborSetNextObjectiveStoreKey.class, + SubnetNextObjectiveStoreKey.class, + SubnetAssignedVidStoreKey.class, NeighborSet.class, DeviceId.class, URI.class, @@ -180,7 +198,12 @@ public class SegmentRoutingManager implements SegmentRoutingService { DefaultTunnel.class, Policy.class, TunnelPolicy.class, - Policy.Type.class + Policy.Type.class, + VlanId.class, + Ip4Address.class, + Ip4Prefix.class, + IpAddress.Version.class, + ConnectPoint.class ); log.debug("Creating EC map nsnextobjectivestore"); @@ -194,6 +217,16 @@ public class SegmentRoutingManager implements SegmentRoutingService { .build(); log.trace("Current size {}", nsNextObjStore.size()); + log.debug("Creating EC map subnetnextobjectivestore"); + EventuallyConsistentMapBuilder + subnetNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder(); + + subnetNextObjStore = subnetNextObjMapBuilder + .withName("subnetnextobjectivestore") + .withSerializer(kryoBuilder) + .withTimestampProvider((k, v) -> new WallClockTimestamp()) + .build(); + EventuallyConsistentMapBuilder tunnelMapBuilder = storageService.eventuallyConsistentMapBuilder(); @@ -212,6 +245,15 @@ public class SegmentRoutingManager implements SegmentRoutingService { .withTimestampProvider((k, v) -> new WallClockTimestamp()) .build(); + EventuallyConsistentMapBuilder + subnetVidStoreMapBuilder = storageService.eventuallyConsistentMapBuilder(); + + subnetVidStore = subnetVidStoreMapBuilder + .withName("subnetvidstore") + .withSerializer(kryoBuilder) + .withTimestampProvider((k, v) -> new WallClockTimestamp()) + .build(); + cfgService.addListener(cfgListener); cfgService.registerConfigFactory(cfgFactory); @@ -296,23 +338,72 @@ public class SegmentRoutingManager implements SegmentRoutingService { } /** - * Returns the GroupKey object for the device and the NeighborSet given. - * XXX is this called + * Returns the vlan-id assigned to the subnet configured for a device. + * If no vlan-id has been assigned, a new one is assigned out of a pool of ids, + * if and only if this controller instance is the master for the device. + *

+ * USAGE: The assigned vlans are meant to be applied to untagged packets on those + * switches/pipelines that need this functionality. These vids are meant + * to be used internally within a switch, and thus need to be unique only + * on a switch level. Note that packets never go out on the wire with these + * vlans. Currently, vlan ids are assigned from value 4093 down. + * Vlan id 4094 expected to be used for all ports that are not assigned subnets. + * Vlan id 4095 is reserved and unused. Only a single vlan id is assigned + * per subnet. + * XXX This method should avoid any vlans configured on the ports, but + * currently the app works only on untagged packets and as a result + * ignores any vlan configuration. * - * @param ns NeightborSet object for the GroupKey - * @return GroupKey object for the NeighborSet + * @param deviceId switch dpid + * @param subnet IPv4 prefix for which assigned vlan is desired + * @return VlanId assigned for the subnet on the device, or + * null if no vlan assignment was found and this instance is not + * the master for the device. */ - public GroupKey getGroupKey(NeighborSet ns) { - for (DefaultGroupHandler groupHandler : groupHandlerMap.values()) { - return groupHandler.getGroupKey(ns); + public VlanId getSubnetAssignedVlanId(DeviceId deviceId, Ip4Prefix subnet) { + VlanId assignedVid = subnetVidStore.get(new SubnetAssignedVidStoreKey( + deviceId, subnet)); + if (assignedVid != null) { + log.debug("Query for subnet:{} on device:{} returned assigned-vlan " + + "{}", subnet, deviceId, assignedVid); + return assignedVid; + } + //check mastership for the right to assign a vlan + if (!mastershipService.isLocalMaster(deviceId)) { + log.warn("This controller instance is not the master for device {}. " + + "Cannot assign vlan-id for subnet {}", deviceId, subnet); + return null; + } + // vlan assignment is expensive but done only once + Set configuredSubnets = deviceConfiguration.getSubnets(deviceId); + Set assignedVlans = new HashSet<>(); + Set unassignedSubnets = new HashSet<>(); + for (Ip4Prefix sub : configuredSubnets) { + VlanId v = subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId, + sub)); + if (v != null) { + assignedVlans.add(v.toShort()); + } else { + unassignedSubnets.add(sub); + } + } + short nextAssignedVlan = ASSIGNED_VLAN_START; + if (!assignedVlans.isEmpty()) { + nextAssignedVlan = (short) (Collections.min(assignedVlans) - 1); + } + for (Ip4Prefix unsub : unassignedSubnets) { + subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub), + VlanId.vlanId(nextAssignedVlan--)); + log.info("Assigned vlan: {} to subnet: {} on device: {}", + nextAssignedVlan + 1, unsub, deviceId); } - return null; + return subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId, subnet)); } /** - * Returns the next objective ID for the NeighborSet given. If the nextObjectiveID does not exist, - * a new one is created and returned. + * Returns the next objective ID for the given NeighborSet. + * If the nextObjectiveID does not exist, a new one is created and returned. * * @param deviceId Device ID * @param ns NegighborSet @@ -329,6 +420,25 @@ public class SegmentRoutingManager implements SegmentRoutingService { } } + /** + * Returns the next objective ID for the Subnet given. If the nextObjectiveID does not exist, + * a new one is created and returned. + * + * @param deviceId Device ID + * @param prefix Subnet + * @return next objective ID + */ + public int getSubnetNextObjectiveId(DeviceId deviceId, IpPrefix prefix) { + if (groupHandlerMap.get(deviceId) != null) { + log.trace("getSubnetNextObjectiveId query in device {}", deviceId); + return groupHandlerMap + .get(deviceId).getSubnetNextObjectiveId(prefix); + } else { + log.warn("getSubnetNextObjectiveId query in device {} not found", deviceId); + return -1; + } + } + private class InternalPacketProcessor implements PacketProcessor { @Override public void process(PacketContext context) { @@ -423,6 +533,8 @@ public class SegmentRoutingManager implements SegmentRoutingService { event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED || event.type() == DeviceEvent.Type.DEVICE_UPDATED) { if (deviceService.isAvailable(((Device) event.subject()).id())) { + log.info("Processing device event {} for available device {}", + event.type(), ((Device) event.subject()).id()); processDeviceAdded((Device) event.subject()); } } else if (event.type() == DeviceEvent.Type.PORT_REMOVED) { @@ -484,20 +596,31 @@ public class SegmentRoutingManager implements SegmentRoutingService { private void processDeviceAdded(Device device) { log.debug("A new device with ID {} was added", device.id()); - //Irrespective whether the local is a MASTER or not for this device, - //create group handler instance and push default TTP flow rules. - //Because in a multi-instance setup, instances can initiate - //groups for any devices. Also the default TTP rules are needed - //to be pushed before inserting any IP table entries for any device - DefaultGroupHandler dgh = DefaultGroupHandler. + // Irrespective of whether the local is a MASTER or not for this device, + // we need to create a SR-group-handler instance. This is because in a + // multi-instance setup, any instance can initiate forwarding/next-objectives + // for any switch (even if this instance is a SLAVE or not even connected + // to the switch). To handle this, a default-group-handler instance is necessary + // per switch. + DefaultGroupHandler groupHandler = DefaultGroupHandler. createGroupHandler(device.id(), appId, deviceConfiguration, linkService, flowObjectiveService, - nsNextObjStore); - groupHandlerMap.put(device.id(), dgh); - defaultRoutingHandler.populateTtpRules(device.id()); + nsNextObjStore, + subnetNextObjStore); + groupHandlerMap.put(device.id(), groupHandler); + + // Also, in some cases, drivers may need extra + // information to process rules (eg. Router IP/MAC); and so, we send + // port addressing rules to the driver as well irrespective of whether + // this instance is the master or not. + defaultRoutingHandler.populatePortAddressingRules(device.id()); + + if (mastershipService.isLocalMaster(device.id())) { + groupHandler.createGroupsFromSubnetConfig(); + } } private void processPortRemoved(Device device, Port port) { @@ -531,18 +654,29 @@ public class SegmentRoutingManager implements SegmentRoutingService { tunnelHandler, policyStore); for (Device device : deviceService.getDevices()) { - //Irrespective whether the local is a MASTER or not for this device, - //create group handler instance and push default TTP flow rules. - //Because in a multi-instance setup, instances can initiate - //groups for any devices. Also the default TTP rules are needed - //to be pushed before inserting any IP table entries for any device + // Irrespective of whether the local is a MASTER or not for this device, + // we need to create a SR-group-handler instance. This is because in a + // multi-instance setup, any instance can initiate forwarding/next-objectives + // for any switch (even if this instance is a SLAVE or not even connected + // to the switch). To handle this, a default-group-handler instance is necessary + // per switch. DefaultGroupHandler groupHandler = DefaultGroupHandler .createGroupHandler(device.id(), appId, deviceConfiguration, linkService, flowObjectiveService, - nsNextObjStore); + nsNextObjStore, + subnetNextObjStore); groupHandlerMap.put(device.id(), groupHandler); - defaultRoutingHandler.populateTtpRules(device.id()); + + // Also, in some cases, drivers may need extra + // information to process rules (eg. Router IP/MAC); and so, we send + // port addressing rules to the driver as well, irrespective of whether + // this instance is the master or not. + defaultRoutingHandler.populatePortAddressingRules(device.id()); + + if (mastershipService.isLocalMaster(device.id())) { + groupHandler.createGroupsFromSubnetConfig(); + } } defaultRoutingHandler.startPopulationProcess(); diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SubnetAssignedVidStoreKey.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SubnetAssignedVidStoreKey.java new file mode 100644 index 00000000..84b44c97 --- /dev/null +++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SubnetAssignedVidStoreKey.java @@ -0,0 +1,66 @@ +package org.onosproject.segmentrouting; + +import java.util.Objects; + +import org.onlab.packet.Ip4Prefix; +import org.onosproject.net.DeviceId; + +/** + * Class definition for key used to map per device subnets to assigned Vlan ids. + * + */ +public class SubnetAssignedVidStoreKey { + private final DeviceId deviceId; + private final Ip4Prefix subnet; + + public SubnetAssignedVidStoreKey(DeviceId deviceId, Ip4Prefix subnet) { + this.deviceId = deviceId; + this.subnet = subnet; + } + + /** + * Returns the device identification used to create this key. + * + * @return the device identifier + */ + public DeviceId deviceId() { + return deviceId; + } + + /** + * Returns the subnet information used to create this key. + * + * @return the subnet + */ + public Ip4Prefix subnet() { + return subnet; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof SubnetAssignedVidStoreKey)) { + return false; + } + SubnetAssignedVidStoreKey that = + (SubnetAssignedVidStoreKey) o; + return (Objects.equals(this.deviceId, that.deviceId) && + Objects.equals(this.subnet, that.subnet)); + } + + @Override + public int hashCode() { + int result = 17; + result = 31 * result + Objects.hashCode(deviceId) + + Objects.hashCode(subnet); + return result; + } + + @Override + public String toString() { + return "Device: " + deviceId + " Subnet: " + subnet; + } + +} diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultEdgeGroupHandler.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultEdgeGroupHandler.java index c960adca..a5c1090f 100644 --- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultEdgeGroupHandler.java +++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultEdgeGroupHandler.java @@ -52,9 +52,12 @@ public class DefaultEdgeGroupHandler extends DefaultGroupHandler { LinkService linkService, FlowObjectiveService flowObjService, EventuallyConsistentMap< - NeighborSetNextObjectiveStoreKey, - Integer> nsNextObjStore) { - super(deviceId, appId, config, linkService, flowObjService, nsNextObjStore); + NeighborSetNextObjectiveStoreKey, + Integer> nsNextObjStore, + EventuallyConsistentMap subnetNextObjStore) { + super(deviceId, appId, config, linkService, flowObjService, + nsNextObjStore, subnetNextObjStore); } @Override diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java index 9bbde2f3..69a0d86f 100644 --- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java +++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java @@ -25,10 +25,11 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Random; import java.util.Set; import java.util.stream.Collectors; +import org.onlab.packet.Ip4Prefix; +import org.onlab.packet.IpPrefix; import org.onlab.packet.MacAddress; import org.onlab.packet.MplsLabel; import org.onlab.util.KryoNamespace; @@ -74,7 +75,8 @@ public class DefaultGroupHandler { // new HashMap(); protected EventuallyConsistentMap< NeighborSetNextObjectiveStoreKey, Integer> nsNextObjStore = null; - protected Random rand = new Random(); + protected EventuallyConsistentMap< + SubnetNextObjectiveStoreKey, Integer> subnetNextObjStore = null; protected KryoNamespace.Builder kryo = new KryoNamespace.Builder() .register(URI.class).register(HashSet.class) @@ -89,8 +91,10 @@ public class DefaultGroupHandler { LinkService linkService, FlowObjectiveService flowObjService, EventuallyConsistentMap< - NeighborSetNextObjectiveStoreKey, - Integer> nsNextObjStore) { + NeighborSetNextObjectiveStoreKey, + Integer> nsNextObjStore, + EventuallyConsistentMap subnetNextObjStore) { this.deviceId = checkNotNull(deviceId); this.appId = checkNotNull(appId); this.deviceConfig = checkNotNull(config); @@ -101,6 +105,7 @@ public class DefaultGroupHandler { nodeMacAddr = checkNotNull(config.getDeviceMac(deviceId)); this.flowObjectiveService = flowObjService; this.nsNextObjStore = nsNextObjStore; + this.subnetNextObjStore = subnetNextObjStore; populateNeighborMaps(); } @@ -115,7 +120,8 @@ public class DefaultGroupHandler { * @param config interface to retrieve the device properties * @param linkService link service object * @param flowObjService flow objective service object - * @param nsNextObjStore next objective store map + * @param nsNextObjStore NeighborSet next objective store map + * @param subnetNextObjStore subnet next objective store map * @return default group handler type */ public static DefaultGroupHandler createGroupHandler(DeviceId deviceId, @@ -123,18 +129,23 @@ public class DefaultGroupHandler { DeviceProperties config, LinkService linkService, FlowObjectiveService flowObjService, - EventuallyConsistentMap nsNextObjStore) { + EventuallyConsistentMap< + NeighborSetNextObjectiveStoreKey, + Integer> nsNextObjStore, + EventuallyConsistentMap subnetNextObjStore) { if (config.isEdgeDevice(deviceId)) { return new DefaultEdgeGroupHandler(deviceId, appId, config, linkService, flowObjService, - nsNextObjStore); + nsNextObjStore, + subnetNextObjStore); } else { return new DefaultTransitGroupHandler(deviceId, appId, config, linkService, flowObjService, - nsNextObjStore); + nsNextObjStore, + subnetNextObjStore); } } @@ -322,6 +333,21 @@ public class DefaultGroupHandler { return nextId; } + /** + * Returns the next objective associated with the subnet. + * If there is no next objective for this subnet, this API + * would create a next objective and return. + * + * @param prefix subnet information + * @return int if found or -1 + */ + public int getSubnetNextObjectiveId(IpPrefix prefix) { + Integer nextId = subnetNextObjStore. + get(new SubnetNextObjectiveStoreKey(deviceId, prefix)); + + return (nextId != null) ? nextId : -1; + } + /** * Checks if the next objective ID (group) for the neighbor set exists or not. * @@ -486,6 +512,43 @@ public class DefaultGroupHandler { } } + public void createGroupsFromSubnetConfig() { + Map> subnetPortMap = + this.deviceConfig.getSubnetPortsMap(this.deviceId); + + // Construct a broadcast group for each subnet + subnetPortMap.forEach((subnet, ports) -> { + SubnetNextObjectiveStoreKey key = + new SubnetNextObjectiveStoreKey(deviceId, subnet); + + if (subnetNextObjStore.containsKey(key)) { + log.debug("Broadcast group for device {} and subnet {} exists", + deviceId, subnet); + return; + } + + int nextId = flowObjectiveService.allocateNextId(); + + NextObjective.Builder nextObjBuilder = DefaultNextObjective + .builder().withId(nextId) + .withType(NextObjective.Type.BROADCAST).fromApp(appId); + + ports.forEach(port -> { + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); + tBuilder.setOutput(port); + nextObjBuilder.addTreatment(tBuilder.build()); + }); + + NextObjective nextObj = nextObjBuilder.add(); + flowObjectiveService.next(deviceId, nextObj); + log.debug("createGroupFromSubnetConfig: Submited " + + "next objective {} in device {}", + nextId, deviceId); + + subnetNextObjStore.put(key, nextId); + }); + } + public GroupKey getGroupKey(Object obj) { return new DefaultGroupKey(kryo.build().serialize(obj)); } diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultTransitGroupHandler.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultTransitGroupHandler.java index 3cb73aba..b009e869 100644 --- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultTransitGroupHandler.java +++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultTransitGroupHandler.java @@ -45,9 +45,12 @@ public class DefaultTransitGroupHandler extends DefaultGroupHandler { LinkService linkService, FlowObjectiveService flowObjService, EventuallyConsistentMap< - NeighborSetNextObjectiveStoreKey, - Integer> nsNextObjStore) { - super(deviceId, appId, config, linkService, flowObjService, nsNextObjStore); + NeighborSetNextObjectiveStoreKey, + Integer> nsNextObjStore, + EventuallyConsistentMap subnetNextObjStore) { + super(deviceId, appId, config, linkService, flowObjService, + nsNextObjStore, subnetNextObjStore); } @Override 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 497f5256..d28d38d5 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 @@ -16,9 +16,12 @@ package org.onosproject.segmentrouting.grouphandler; import java.util.List; +import java.util.Map; +import org.onlab.packet.Ip4Prefix; import org.onlab.packet.MacAddress; import org.onosproject.net.DeviceId; +import org.onosproject.net.PortNumber; /** * Mechanism through which group handler module retrieves @@ -33,6 +36,7 @@ public interface DeviceProperties { * @return segment id of a device */ int getSegmentId(DeviceId deviceId); + /** * Returns the Mac address of a device to be used in group creation. * @@ -40,6 +44,7 @@ public interface DeviceProperties { * @return mac address of a device */ MacAddress getDeviceMac(DeviceId deviceId); + /** * Indicates whether a device is edge device or transit/core device. * @@ -47,6 +52,7 @@ public interface DeviceProperties { * @return boolean */ boolean isEdgeDevice(DeviceId deviceId); + /** * Returns all segment IDs to be considered in building auto * @@ -54,4 +60,16 @@ public interface DeviceProperties { * @return list of segment IDs */ List getAllDeviceSegmentIds(); + + /** + * Returns subnet-to-ports mapping of given device. + * + * For each entry of the map + * Key: a subnet + * Value: a list of ports, which are bound to the subnet + * + * @param deviceId device identifier + * @return a map that contains all subnet-to-ports mapping of given device + */ + Map> getSubnetPortsMap(DeviceId deviceId); } diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupHandler.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupHandler.java index e7e87839..e47a6625 100644 --- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupHandler.java +++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupHandler.java @@ -54,7 +54,8 @@ public class PolicyGroupHandler extends DefaultGroupHandler { * @param config interface to retrieve the device properties * @param linkService link service object * @param flowObjService flow objective service object - * @param nsNextObjStore next objective store map + * @param nsNextObjStore NeighborSet next objective store map + * @param subnetNextObjStore subnet next objective store map */ public PolicyGroupHandler(DeviceId deviceId, ApplicationId appId, @@ -62,8 +63,11 @@ public class PolicyGroupHandler extends DefaultGroupHandler { LinkService linkService, FlowObjectiveService flowObjService, EventuallyConsistentMap nsNextObjStore) { - super(deviceId, appId, config, linkService, flowObjService, nsNextObjStore); + Integer> nsNextObjStore, + EventuallyConsistentMap subnetNextObjStore) { + super(deviceId, appId, config, linkService, flowObjService, + nsNextObjStore, subnetNextObjStore); } public PolicyGroupIdentifier createPolicyGroupChain(String id, diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/SubnetNextObjectiveStoreKey.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/SubnetNextObjectiveStoreKey.java new file mode 100644 index 00000000..d6b16c7a --- /dev/null +++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/SubnetNextObjectiveStoreKey.java @@ -0,0 +1,78 @@ +/* + * Copyright 2014-2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.segmentrouting.grouphandler; + +import org.onlab.packet.IpPrefix; +import org.onosproject.net.DeviceId; + +import java.util.Objects; + +/** + * Class definition of Key for Subnet to NextObjective store. + */ +public class SubnetNextObjectiveStoreKey { + private final DeviceId deviceId; + private final IpPrefix prefix; + + public SubnetNextObjectiveStoreKey(DeviceId deviceId, + IpPrefix prefix) { + this.deviceId = deviceId; + this.prefix = prefix; + } + + /** + * Gets device id in this SubnetNextObjectiveStoreKey. + * + * @return device id + */ + public DeviceId deviceId() { + return this.deviceId; + } + + /** + * Gets subnet information in this SubnetNextObjectiveStoreKey. + * + * @return subnet information + */ + public IpPrefix prefix() { + return this.prefix; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof SubnetNextObjectiveStoreKey)) { + return false; + } + SubnetNextObjectiveStoreKey that = + (SubnetNextObjectiveStoreKey) o; + return (Objects.equals(this.deviceId, that.deviceId) && + Objects.equals(this.prefix, that.prefix)); + } + + @Override + public int hashCode() { + return Objects.hash(deviceId, prefix); + } + + @Override + public String toString() { + return "Device: " + deviceId + " Subnet: " + prefix; + } +} diff --git a/framework/src/onos/apps/test/distributed-primitives/src/main/java/org/onosproject/distributedprimitives/cli/SetTestAddCommand.java b/framework/src/onos/apps/test/distributed-primitives/src/main/java/org/onosproject/distributedprimitives/cli/SetTestAddCommand.java index 204471c2..2d1aa0b8 100644 --- a/framework/src/onos/apps/test/distributed-primitives/src/main/java/org/onosproject/distributedprimitives/cli/SetTestAddCommand.java +++ b/framework/src/onos/apps/test/distributed-primitives/src/main/java/org/onosproject/distributedprimitives/cli/SetTestAddCommand.java @@ -23,7 +23,7 @@ import org.onosproject.store.serializers.KryoNamespaces; import org.onosproject.store.service.Serializer; import org.onosproject.store.service.StorageService; -import java.util.HashSet; +import java.util.Arrays; import java.util.Set; /** @@ -44,7 +44,6 @@ public class SetTestAddCommand extends AbstractShellCommand { String[] values = null; Set set; - Set toAdd = new HashSet<>(); Serializer serializer = Serializer.using( @@ -68,13 +67,10 @@ public class SetTestAddCommand extends AbstractShellCommand { } } else if (values.length >= 1) { // Add multiple elements to a set - for (String value : values) { - toAdd.add(value); - } - if (set.addAll(toAdd)) { - print("%s was added to the set %s", toAdd, setName); + if (set.addAll(Arrays.asList(values))) { + print("%s was added to the set %s", Arrays.asList(values), setName); } else { - print("%s was already in set %s", toAdd, setName); + print("%s was already in set %s", Arrays.asList(values), setName); } } } diff --git a/framework/src/onos/apps/test/distributed-primitives/src/main/java/org/onosproject/distributedprimitives/cli/SetTestGetCommand.java b/framework/src/onos/apps/test/distributed-primitives/src/main/java/org/onosproject/distributedprimitives/cli/SetTestGetCommand.java index fb36a06a..74c52c16 100644 --- a/framework/src/onos/apps/test/distributed-primitives/src/main/java/org/onosproject/distributedprimitives/cli/SetTestGetCommand.java +++ b/framework/src/onos/apps/test/distributed-primitives/src/main/java/org/onosproject/distributedprimitives/cli/SetTestGetCommand.java @@ -24,7 +24,7 @@ import org.onosproject.store.serializers.KryoNamespaces; import org.onosproject.store.service.Serializer; import org.onosproject.store.service.StorageService; -import java.util.HashSet; +import java.util.Arrays; import java.util.Set; /** @@ -49,7 +49,6 @@ public class SetTestGetCommand extends AbstractShellCommand { String[] values = null; Set set; - Set toCheck = new HashSet<>(); String output = ""; Serializer serializer = Serializer.using( @@ -95,13 +94,10 @@ public class SetTestGetCommand extends AbstractShellCommand { } } else if (values.length > 1) { //containsAll - for (String value : values) { - toCheck.add(value); - } - if (set.containsAll(toCheck)) { - print("Set %s contains the the subset %s", setName, toCheck); + if (set.containsAll(Arrays.asList(values))) { + print("Set %s contains the the subset %s", setName, Arrays.asList(values)); } else { - print("Set %s did not contain the the subset %s", setName, toCheck); + print("Set %s did not contain the the subset %s", setName, Arrays.asList(values)); } } } diff --git a/framework/src/onos/apps/test/distributed-primitives/src/main/java/org/onosproject/distributedprimitives/cli/SetTestRemoveCommand.java b/framework/src/onos/apps/test/distributed-primitives/src/main/java/org/onosproject/distributedprimitives/cli/SetTestRemoveCommand.java index d1f81e42..1fa073f3 100644 --- a/framework/src/onos/apps/test/distributed-primitives/src/main/java/org/onosproject/distributedprimitives/cli/SetTestRemoveCommand.java +++ b/framework/src/onos/apps/test/distributed-primitives/src/main/java/org/onosproject/distributedprimitives/cli/SetTestRemoveCommand.java @@ -24,7 +24,7 @@ import org.onosproject.store.serializers.KryoNamespaces; import org.onosproject.store.service.Serializer; import org.onosproject.store.service.StorageService; -import java.util.HashSet; +import java.util.Arrays; import java.util.Set; /** @@ -54,7 +54,6 @@ public class SetTestRemoveCommand extends AbstractShellCommand { String[] values = null; Set set; - Set givenValues = new HashSet<>(); Serializer serializer = Serializer.using( new KryoNamespace.Builder().register(KryoNamespaces.BASIC).build()); @@ -79,13 +78,10 @@ public class SetTestRemoveCommand extends AbstractShellCommand { } if (retain) { // Keep only the given values - for (String value : values) { - givenValues.add(value); - } - if (set.retainAll(givenValues)) { - print("%s was pruned to contain only elements of set %s", setName, givenValues); + if (set.retainAll(Arrays.asList(values))) { + print("%s was pruned to contain only elements of set %s", setName, Arrays.asList(values)); } else { - print("%s was not changed by retaining only elements of the set %s", setName, givenValues); + print("%s was not changed by retaining only elements of the set %s", setName, Arrays.asList(values)); } } else if (values.length == 1) { // Remove a single element from the set @@ -94,15 +90,12 @@ public class SetTestRemoveCommand extends AbstractShellCommand { } else { print("[%s] was not in set %s", values[0], setName); } - } else if (values.length >= 1) { + } else if (values.length > 1) { // Remove multiple elements from a set - for (String value : values) { - givenValues.add(value); - } - if (set.removeAll(givenValues)) { - print("%s was removed from the set %s", givenValues, setName); + if (set.removeAll(Arrays.asList(values))) { + print("%s was removed from the set %s", Arrays.asList(values), setName); } else { - print("No element of %s was in set %s", givenValues, setName); + print("No element of %s was in set %s", Arrays.asList(values), setName); } } } diff --git a/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/ConnectPointConfiguration.java b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/ConnectPointConfiguration.java new file mode 100644 index 00000000..ff516d71 --- /dev/null +++ b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/ConnectPointConfiguration.java @@ -0,0 +1,55 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.virtualbng; + +import org.onosproject.net.ConnectPoint; + +/** + * Configuration for a connect point. + */ +public class ConnectPointConfiguration { + + private ConnectPoint connectPoint; + + /** + * Creats a new connect point from a string representation. + * + * @param string connect point string + */ + public ConnectPointConfiguration(String string) { + connectPoint = ConnectPoint.deviceConnectPoint(string); + } + + /** + * Creates a new connect point from a string representation. + * + * @param string connect point string + * @return new connect point configuration + */ + public static ConnectPointConfiguration of(String string) { + return new ConnectPointConfiguration(string); + } + + /** + * Gets the connect point. + * + * @return connect point + */ + public ConnectPoint connectPoint() { + return connectPoint; + } +} diff --git a/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfiguration.java b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfiguration.java index ee2cbeaa..1841675f 100644 --- a/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfiguration.java +++ b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfiguration.java @@ -17,13 +17,15 @@ package org.onosproject.virtualbng; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; - -import java.util.Collections; -import java.util.List; - import org.onlab.packet.IpAddress; import org.onlab.packet.IpPrefix; import org.onlab.packet.MacAddress; +import org.onosproject.net.ConnectPoint; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; /** * Contains the configuration data for virtual BNG that has been read from a @@ -36,6 +38,7 @@ public final class VbngConfiguration { private final MacAddress publicFacingMac; private final IpAddress xosIpAddress; private final int xosRestPort; + private final Map hosts; /** * Default constructor. @@ -46,6 +49,7 @@ public final class VbngConfiguration { publicFacingMac = null; xosIpAddress = null; xosRestPort = 0; + hosts = null; } /** @@ -57,6 +61,7 @@ public final class VbngConfiguration { * public IP addresses * @param xosIpAddress the XOS server IP address * @param xosRestPort the port of the XOS server for REST + * @param hosts map of hosts */ @JsonCreator public VbngConfiguration(@JsonProperty("localPublicIpPrefixes") @@ -68,12 +73,15 @@ public final class VbngConfiguration { @JsonProperty("xosIpAddress") IpAddress xosIpAddress, @JsonProperty("xosRestPort") - int xosRestPort) { + int xosRestPort, + @JsonProperty("hosts") + Map hosts) { localPublicIpPrefixes = prefixes; this.nextHopIpAddress = nextHopIpAddress; this.publicFacingMac = publicFacingMac; this.xosIpAddress = xosIpAddress; this.xosRestPort = xosRestPort; + this.hosts = hosts; } /** @@ -120,4 +128,13 @@ public final class VbngConfiguration { public int getXosRestPort() { return xosRestPort; } + + public Map getHosts() { + return hosts.entrySet() + .stream() + .collect(Collectors.toMap( + e -> e.getKey(), + e -> e.getValue().connectPoint() + )); + } } diff --git a/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationManager.java b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationManager.java index d27d6904..eb83e06c 100644 --- a/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationManager.java +++ b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationManager.java @@ -16,16 +16,6 @@ package org.onosproject.virtualbng; import com.fasterxml.jackson.databind.ObjectMapper; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.Collections; -import java.util.Iterator; -import java.util.Map; -import java.util.Map.Entry; -import java.util.concurrent.ConcurrentHashMap; - import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Deactivate; @@ -33,9 +23,19 @@ import org.apache.felix.scr.annotations.Service; import org.onlab.packet.IpAddress; import org.onlab.packet.IpPrefix; import org.onlab.packet.MacAddress; +import org.onosproject.net.ConnectPoint; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Collections; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.ConcurrentHashMap; + /** * Implementation of ConfigurationService which reads virtual BNG * configuration from a file. @@ -63,6 +63,7 @@ public class VbngConfigurationManager implements VbngConfigurationService { private MacAddress macOfPublicIpAddresses; private IpAddress xosIpAddress; private int xosRestPort; + private Map nodeToPort; @Activate public void activate() { @@ -104,6 +105,8 @@ public class VbngConfigurationManager implements VbngConfigurationService { macOfPublicIpAddresses = config.getPublicFacingMac(); xosIpAddress = config.getXosIpAddress(); xosRestPort = config.getXosRestPort(); + nodeToPort = config.getHosts(); + } catch (FileNotFoundException e) { log.warn("Configuration file not found: {}", configFileName); @@ -132,6 +135,11 @@ public class VbngConfigurationManager implements VbngConfigurationService { return xosRestPort; } + @Override + public Map getNodeToPort() { + return nodeToPort; + } + // TODO handle the case: the number of public IP addresses is not enough // for 1:1 mapping from public IP to private IP. @Override diff --git a/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationService.java b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationService.java index ef8698a0..68c048f4 100644 --- a/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationService.java +++ b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationService.java @@ -15,10 +15,11 @@ */ package org.onosproject.virtualbng; -import java.util.Map; - import org.onlab.packet.IpAddress; import org.onlab.packet.MacAddress; +import org.onosproject.net.ConnectPoint; + +import java.util.Map; /** * Provides information about the virtual BNG configuration. @@ -53,6 +54,13 @@ public interface VbngConfigurationService { */ int getXosRestPort(); + /** + * Gets the host to port map. + * + * @return host to port map + */ + Map getNodeToPort(); + /** * Evaluates whether an IP address is an assigned public IP address. * diff --git a/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngManager.java b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngManager.java index 5e82b7e8..e03b25e8 100644 --- a/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngManager.java +++ b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngManager.java @@ -15,18 +15,9 @@ */ package org.onosproject.virtualbng; -import static com.google.common.base.Preconditions.checkNotNull; - import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; -import com.google.common.collect.Maps; - -import java.util.Iterator; -import java.util.Map; -import java.util.Map.Entry; -import java.util.concurrent.ConcurrentHashMap; - import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Deactivate; @@ -42,7 +33,6 @@ import org.onosproject.core.CoreService; import org.onosproject.net.ConnectPoint; import org.onosproject.net.DeviceId; import org.onosproject.net.Host; -import org.onosproject.net.PortNumber; import org.onosproject.net.flow.DefaultTrafficSelector; import org.onosproject.net.flow.DefaultTrafficTreatment; import org.onosproject.net.flow.TrafficSelector; @@ -56,6 +46,13 @@ import org.onosproject.net.intent.PointToPointIntent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.ConcurrentHashMap; + +import static com.google.common.base.Preconditions.checkNotNull; + /** * This is a virtual Broadband Network Gateway (BNG) application. It mainly * has 3 functions: @@ -111,9 +108,8 @@ public class VbngManager implements VbngService { p2pIntentsToHost = new ConcurrentHashMap<>(); privateIpAddressMap = new ConcurrentHashMap<>(); - setupMap(); - nextHopIpAddress = vbngConfigurationService.getNextHopIpAddress(); + nodeToPort = vbngConfigurationService.getNodeToPort(); hostListener = new InternalHostListener(); hostService.addListener(hostListener); @@ -136,10 +132,16 @@ public class VbngManager implements VbngService { */ private void statusRecovery() { log.info("vBNG starts to recover from XOS record......"); - RestClient restClient = - new RestClient(vbngConfigurationService.getXosIpAddress(), - vbngConfigurationService.getXosRestPort()); - ObjectNode map = restClient.getRest(); + ObjectNode map; + try { + RestClient restClient = + new RestClient(vbngConfigurationService.getXosIpAddress(), + vbngConfigurationService.getXosRestPort()); + map = restClient.getRest(); + } catch (Exception e) { + log.error("Could not contact XOS", e); + return; + } if (map == null) { log.info("Stop to recover vBNG status due to the vBNG map " + "is null!"); @@ -167,21 +169,6 @@ public class VbngManager implements VbngService { } } - /** - * Sets up mapping from hostname to connect point. - */ - private void setupMap() { - nodeToPort = Maps.newHashMap(); - - nodeToPort.put("cordcompute01.onlab.us", - new ConnectPoint(FABRIC_DEVICE_ID, - PortNumber.portNumber(48))); - - nodeToPort.put("cordcompute02.onlab.us", - new ConnectPoint(FABRIC_DEVICE_ID, - PortNumber.portNumber(47))); - } - /** * Creates a new vBNG. * diff --git a/framework/src/onos/apps/vtn/pom.xml b/framework/src/onos/apps/vtn/pom.xml index c2cfe2be..e91b0c9b 100644 --- a/framework/src/onos/apps/vtn/pom.xml +++ b/framework/src/onos/apps/vtn/pom.xml @@ -37,4 +37,21 @@ vtnweb app + + + org.onosproject + onlab-junit + test + + + com.google.guava + guava-testlib + test + + + org.easymock + easymock + test + + diff --git a/framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/SfcService.java b/framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/SfcService.java new file mode 100644 index 00000000..a2748f5e --- /dev/null +++ b/framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/SfcService.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.sfc; + +import org.onosproject.vtnrsc.PortChain; + +/** + * SFC application that applies flows to the device. + */ +public interface SfcService { + /** + * Applies flow classification to OVS. + * + * @param portChain Port-Chain. + */ + void InstallFlowClassification(PortChain portChain); + + + /** + * Remove flow classification from OVS. + * + * @param portChain Port-Chain. + */ + void UnInstallFlowClassification(PortChain portChain); + + /** + * Applies Service Function chain to OVS. + * + * @param portChain Port-Chain. + */ + void InstallServiceFunctionChain(PortChain portChain); + + /** + * Remove Service Function chain from OVS. + * + * @param portChain Port-Chain. + */ + void UnInstallServiceFunctionChain(PortChain portChain); +} diff --git a/framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/impl/SfcManager.java b/framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/impl/SfcManager.java new file mode 100644 index 00000000..1872295f --- /dev/null +++ b/framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/impl/SfcManager.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.sfc.impl; + +import static org.slf4j.LoggerFactory.getLogger; + +import org.apache.felix.scr.annotations.Activate; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Deactivate; +import org.apache.felix.scr.annotations.Service; +import org.onosproject.vtnrsc.sfc.PortChain; +import org.slf4j.Logger; + +/** + * Provides implementation of SFC Service. + */ +@Component(immediate = true) +@Service +public class SfcManager implements SfcService { + + private final Logger log = getLogger(SfcManager.class); + + @Activate + public void activate() { + log.info("Started"); + } + + @Deactivate + public void deactivate() { + log.info("Stopped"); + } + + @Override + public void InstallFlowClassification(PortChain portChain) { + log.debug("InstallFlowClassification"); + //TODO: Installation of flow classification into OVS. + } + + @Override + public void UnInstallFlowClassification(PortChain portChain) { + log.debug("UnInstallFlowClassification"); + //TODO: Un-installation flow classification from OVS + } + + @Override + public void InstallServiceFunctionChain(PortChain portChain) { + log.debug("InstallServiceFunctionChain"); + //TODO: Installation of Service Function chain into OVS. + } + + @Override + public void UnInstallServiceFunctionChain(PortChain portChain) { + log.debug("UnInstallServiceFunctionChain"); + //TODO: Un-installation of Service Function chain from OVS. + } +} diff --git a/framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/impl/package-info.java b/framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/impl/package-info.java new file mode 100644 index 00000000..0dba868c --- /dev/null +++ b/framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/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. + */ + +/** + * SFC Service manager for interacting with SFC. + */ +package org.onosproject.sfc.impl; diff --git a/framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/package-info.java b/framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/package-info.java new file mode 100644 index 00000000..1dcb9929 --- /dev/null +++ b/framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/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 SFC. + */ +package org.onosproject.sfc; diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultFlowClassifier.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultFlowClassifier.java new file mode 100644 index 00000000..39df2cff --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultFlowClassifier.java @@ -0,0 +1,413 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.vtnrsc; + +import java.util.Objects; +import org.onlab.packet.IpPrefix; + +import com.google.common.base.MoreObjects; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Provides Default flow classifier. + */ +public final class DefaultFlowClassifier implements FlowClassifier { + + private final FlowClassifierId flowClassifierId; + private final TenantId tenantId; + private final String name; + private final String description; + private final String etherType; + private final String protocol; + private final int minSrcPortRange; + private final int maxSrcPortRange; + private final int minDstPortRange; + private final int maxDstPortRange; + private final IpPrefix srcIpPrefix; + private final IpPrefix dstIpPrefix; + private final VirtualPortId srcPort; + private final VirtualPortId dstPort; + private static final int NULL_PORT = 0; + private static final String FLOW_CLASSIFIER_ID_NOT_NULL = "FlowClassifier id can not be null."; + private static final String TENANT_ID_NOT_NULL = "Tenant id can not be null."; + + /** + * Constructor to create default flow classifier. + * + * @param flowClassifierId flow classifier Id + * @param tenantId Tenant ID + * @param name flow classifier name + * @param description flow classifier description + * @param etherType etherType + * @param protocol IP protocol + * @param minSrcPortRange Minimum Source port range + * @param maxSrcPortRange Maximum Source port range + * @param minDstPortRange Minimum destination port range + * @param maxDstPortRange Maximum destination port range + * @param srcIpPrefix Source IP prefix + * @param dstIpPrefix destination IP prefix + * @param srcPort Source VirtualPort + * @param dstPort destination VirtualPort + */ + private DefaultFlowClassifier(FlowClassifierId flowClassifierId, TenantId tenantId, String name, + String description, String etherType, String protocol, int minSrcPortRange, int maxSrcPortRange, + int minDstPortRange, int maxDstPortRange, IpPrefix srcIpPrefix, IpPrefix dstIpPrefix, + VirtualPortId srcPort, VirtualPortId dstPort) { + this.flowClassifierId = flowClassifierId; + this.tenantId = tenantId; + this.name = name; + this.description = description; + this.etherType = etherType; + this.protocol = protocol; + this.minSrcPortRange = minSrcPortRange; + this.maxSrcPortRange = maxSrcPortRange; + this.minDstPortRange = minDstPortRange; + this.maxDstPortRange = maxDstPortRange; + this.srcIpPrefix = srcIpPrefix; + this.dstIpPrefix = dstIpPrefix; + this.srcPort = srcPort; + this.dstPort = dstPort; + } + + @Override + public FlowClassifierId flowClassifierId() { + return flowClassifierId; + } + + @Override + public TenantId tenantId() { + return tenantId; + } + + @Override + public String name() { + return name; + } + + @Override + public String description() { + return description; + } + + @Override + public String etherType() { + return etherType; + } + + @Override + public String protocol() { + return protocol; + } + + @Override + public int minSrcPortRange() { + return minSrcPortRange; + } + + @Override + public int maxSrcPortRange() { + return maxSrcPortRange; + } + + @Override + public int minDstPortRange() { + return minDstPortRange; + } + + @Override + public int maxDstPortRange() { + return maxDstPortRange; + } + + @Override + public IpPrefix srcIpPrefix() { + return srcIpPrefix; + } + + @Override + public IpPrefix dstIpPrefix() { + return dstIpPrefix; + } + + @Override + public VirtualPortId srcPort() { + return srcPort; + } + + @Override + public VirtualPortId dstPort() { + return dstPort; + } + + /** + * Builder class for constructing Flow classifier. + */ + public static class Builder implements FlowClassifier.Builder { + + private FlowClassifierId flowClassifierId; + private TenantId tenantId; + private String name; + private boolean isFlowClassifierNameSet = false; + private String description; + private boolean isFlowClassifierDescriptionSet = false; + private String etherType; + private boolean isEtherTypeSet = false; + private String protocol; + private boolean isProtocolSet = false; + private int minSrcPortRange; + private boolean isMinSrcPortRangeSet = false; + private int maxSrcPortRange; + private boolean isMaxSrcPortRangeSet = false; + private int minDstPortRange; + private boolean isMinDstPortRangeSet = false; + private int maxDstPortRange; + private boolean isMaxDstPortRangeSet = false; + private IpPrefix srcIpPrefix; + private boolean isSrcIpPrefixSet = false; + private IpPrefix dstIpPrefix; + private boolean isDstIpPrefixSet = false; + private VirtualPortId srcPort; + private boolean isSrcPortSet = false; + private VirtualPortId dstPort; + private boolean isDstPortSet = false; + + @Override + public FlowClassifier build() { + + checkNotNull(flowClassifierId, FLOW_CLASSIFIER_ID_NOT_NULL); + checkNotNull(tenantId, TENANT_ID_NOT_NULL); + String name = null; + String description = null; + String etherType = null; + String protocol = null; + int minSrcPortRange = NULL_PORT; + int maxSrcPortRange = NULL_PORT; + int minDstPortRange = NULL_PORT; + int maxDstPortRange = NULL_PORT; + IpPrefix srcIpPrefix = null; + IpPrefix dstIpPrefix = null; + VirtualPortId srcPort = null; + VirtualPortId dstPort = null; + + if (isFlowClassifierNameSet) { + name = this.name; + } + if (isFlowClassifierDescriptionSet) { + description = this.description; + } + if (isEtherTypeSet) { + etherType = this.etherType; + } + if (isProtocolSet) { + protocol = this.protocol; + } + if (isMinSrcPortRangeSet) { + minSrcPortRange = this.minSrcPortRange; + } + if (isMaxSrcPortRangeSet) { + maxSrcPortRange = this.maxSrcPortRange; + } + if (isMinDstPortRangeSet) { + minDstPortRange = this.minDstPortRange; + } + if (isMaxDstPortRangeSet) { + maxDstPortRange = this.maxDstPortRange; + } + if (isSrcIpPrefixSet) { + srcIpPrefix = this.srcIpPrefix; + } + if (isDstIpPrefixSet) { + dstIpPrefix = this.dstIpPrefix; + } + if (isSrcPortSet) { + srcPort = this.srcPort; + } + if (isDstPortSet) { + dstPort = this.dstPort; + } + + return new DefaultFlowClassifier(flowClassifierId, tenantId, name, description, etherType, protocol, + minSrcPortRange, maxSrcPortRange, minDstPortRange, maxDstPortRange, srcIpPrefix, dstIpPrefix, + srcPort, dstPort); + } + + @Override + public Builder setFlowClassifierId(FlowClassifierId flowClassifierId) { + this.flowClassifierId = flowClassifierId; + return this; + } + + @Override + public Builder setTenantId(TenantId tenantId) { + this.tenantId = tenantId; + return this; + } + + @Override + public Builder setName(String name) { + this.name = name; + this.isFlowClassifierNameSet = true; + return this; + } + + @Override + public Builder setDescription(String description) { + this.description = description; + this.isFlowClassifierDescriptionSet = true; + return this; + } + + @Override + public Builder setEtherType(String etherType) { + this.etherType = etherType; + this.isEtherTypeSet = true; + return this; + } + + @Override + public Builder setProtocol(String protocol) { + this.protocol = protocol; + this.isProtocolSet = true; + return this; + } + + @Override + public Builder setMinSrcPortRange(int minSrcPortRange) { + this.minSrcPortRange = minSrcPortRange; + this.isMinSrcPortRangeSet = true; + return this; + } + + @Override + public Builder setMaxSrcPortRange(int maxSrcPortRange) { + this.maxSrcPortRange = maxSrcPortRange; + this.isMaxSrcPortRangeSet = true; + return this; + } + + @Override + public Builder setMinDstPortRange(int minDstPortRange) { + this.minDstPortRange = minDstPortRange; + this.isMinDstPortRangeSet = true; + return this; + } + + @Override + public Builder setMaxDstPortRange(int maxDstPortRange) { + this.maxDstPortRange = maxDstPortRange; + this.isMaxDstPortRangeSet = true; + return this; + } + + @Override + public Builder setSrcIpPrefix(IpPrefix srcIpPrefix) { + this.srcIpPrefix = srcIpPrefix; + this.isSrcIpPrefixSet = true; + return this; + } + + @Override + public Builder setDstIpPrefix(IpPrefix dstIpPrefix) { + this.dstIpPrefix = dstIpPrefix; + this.isDstIpPrefixSet = true; + return this; + } + + @Override + public Builder setSrcPort(VirtualPortId srcPort) { + this.srcPort = srcPort; + this.isSrcPortSet = true; + return this; + } + + @Override + public Builder setDstPort(VirtualPortId dstPort) { + this.dstPort = dstPort; + this.isDstPortSet = true; + return this; + } + } + + @Override + public int hashCode() { + return Objects.hash(flowClassifierId, tenantId, name, description, etherType, protocol, minSrcPortRange, + maxSrcPortRange, minDstPortRange, maxDstPortRange, srcIpPrefix, dstIpPrefix, srcPort, dstPort); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DefaultFlowClassifier) { + DefaultFlowClassifier other = (DefaultFlowClassifier) obj; + return Objects.equals(this.flowClassifierId, other.flowClassifierId) + && Objects.equals(this.tenantId, other.tenantId) + && Objects.equals(this.name, other.name) + && Objects.equals(this.description, other.description) + && Objects.equals(this.etherType, other.etherType) + && Objects.equals(this.protocol, other.protocol) + && Objects.equals(this.minSrcPortRange, other.minSrcPortRange) + && Objects.equals(this.maxSrcPortRange, other.maxSrcPortRange) + && Objects.equals(this.minDstPortRange, other.minDstPortRange) + && Objects.equals(this.maxDstPortRange, other.maxDstPortRange) + && Objects.equals(this.srcIpPrefix, other.srcIpPrefix) + && Objects.equals(this.dstIpPrefix, other.dstIpPrefix) + && Objects.equals(this.srcPort, other.srcPort) + && Objects.equals(this.dstPort, other.dstPort); + } + return false; + } + + @Override + public boolean exactMatch(FlowClassifier flowClassifier) { + return this.equals(flowClassifier) + && Objects.equals(this.flowClassifierId, flowClassifier.flowClassifierId()) + && Objects.equals(this.tenantId, flowClassifier.tenantId()) + && Objects.equals(this.name, flowClassifier.name()) + && Objects.equals(this.description, flowClassifier.description()) + && Objects.equals(this.etherType, flowClassifier.etherType()) + && Objects.equals(this.protocol, flowClassifier.protocol()) + && Objects.equals(this.minSrcPortRange, flowClassifier.minSrcPortRange()) + && Objects.equals(this.maxSrcPortRange, flowClassifier.maxSrcPortRange()) + && Objects.equals(this.minDstPortRange, flowClassifier.minDstPortRange()) + && Objects.equals(this.maxDstPortRange, flowClassifier.maxDstPortRange()) + && Objects.equals(this.srcIpPrefix, flowClassifier.srcIpPrefix()) + && Objects.equals(this.dstIpPrefix, flowClassifier.dstIpPrefix()) + && Objects.equals(this.srcPort, flowClassifier.srcPort()) + && Objects.equals(this.dstPort, flowClassifier.dstPort()); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("FlowClassifierId", flowClassifierId) + .add("TenantId", tenantId) + .add("Name", name) + .add("Description", description) + .add("String", etherType) + .add("Protocol", protocol) + .add("MinSrcPortRange", minSrcPortRange) + .add("MaxSrcPortRange", maxSrcPortRange) + .add("MinDstPortRange", minDstPortRange) + .add("MaxDstPortRange", maxDstPortRange) + .add("SrcIpPrefix", srcIpPrefix) + .add("DstIpPrefix", dstIpPrefix) + .add("SrcPort", srcPort) + .add("DstPort", dstPort) + .toString(); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultPortChain.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultPortChain.java new file mode 100644 index 00000000..89b94b3e --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultPortChain.java @@ -0,0 +1,201 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.vtnrsc; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.List; +import java.util.Objects; + +import com.google.common.collect.ImmutableList; + +/** + * Implementation of port chain. + */ +public final class DefaultPortChain implements PortChain { + + private final PortChainId portChainId; + private final TenantId tenantId; + private final String name; + private final String description; + private final List portPairGroupList; + private final List flowClassifierList; + + /** + * Default constructor to create port chain. + * + * @param portChainId port chain id + * @param tenantId tenant id + * @param name name of port chain + * @param description description of port chain + * @param portPairGroupList port pair group list + * @param flowClassifierList flow classifier list + */ + private DefaultPortChain(PortChainId portChainId, TenantId tenantId, + String name, String description, + List portPairGroupList, + List flowClassifierList) { + + this.portChainId = portChainId; + this.tenantId = tenantId; + this.name = name; + this.description = description; + this.portPairGroupList = portPairGroupList; + this.flowClassifierList = flowClassifierList; + } + + @Override + public PortChainId portChainId() { + return portChainId; + } + + @Override + public TenantId tenantId() { + return tenantId; + } + + @Override + public String name() { + return name; + } + + @Override + public String description() { + return description; + } + + @Override + public List portPairGroups() { + return ImmutableList.copyOf(portPairGroupList); + } + + @Override + public List flowClassifiers() { + return ImmutableList.copyOf(flowClassifierList); + } + + @Override + public int hashCode() { + return Objects.hash(portChainId, tenantId, name, description, + portPairGroupList, flowClassifierList); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DefaultPortChain) { + DefaultPortChain that = (DefaultPortChain) obj; + return Objects.equals(portChainId, that.portChainId) && + Objects.equals(tenantId, that.tenantId) && + Objects.equals(name, that.name) && + Objects.equals(description, that.description) && + Objects.equals(portPairGroupList, that.portPairGroupList) && + Objects.equals(flowClassifierList, that.flowClassifierList); + } + return false; + } + + @Override + public boolean exactMatch(PortChain portChain) { + return this.equals(portChain) && + Objects.equals(this.portChainId, portChain.portChainId()) && + Objects.equals(this.tenantId, portChain.tenantId()); + } + + @Override + public String toString() { + return toStringHelper(this) + .add("id", portChainId.toString()) + .add("tenantId", tenantId.toString()) + .add("name", name) + .add("description", description) + .add("portPairGroupList", portPairGroupList) + .add("flowClassifier", flowClassifierList) + .toString(); + } + + /** + * To create an instance of the builder. + * + * @return instance of builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder class for Port chain. + */ + public static final class Builder implements PortChain.Builder { + + private PortChainId portChainId; + private TenantId tenantId; + private String name; + private String description; + private List portPairGroupList; + private List flowClassifierList; + + @Override + public Builder setId(PortChainId portChainId) { + this.portChainId = portChainId; + return this; + } + + @Override + public Builder setTenantId(TenantId tenantId) { + this.tenantId = tenantId; + return this; + } + + @Override + public Builder setName(String name) { + this.name = name; + return this; + } + + @Override + public Builder setDescription(String description) { + this.description = description; + return this; + } + + @Override + public Builder setPortPairGroups(List portPairGroups) { + this.portPairGroupList = portPairGroups; + return this; + } + + @Override + public Builder setFlowClassifiers(List flowClassifiers) { + this.flowClassifierList = flowClassifiers; + return this; + } + + @Override + public PortChain build() { + + checkNotNull(portChainId, "Port chain id cannot be null"); + checkNotNull(tenantId, "Tenant id cannot be null"); + checkNotNull(portPairGroupList, "Port pair groups cannot be null"); + + return new DefaultPortChain(portChainId, tenantId, name, description, + portPairGroupList, flowClassifierList); + } + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultPortPair.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultPortPair.java new file mode 100644 index 00000000..4b3b7cf3 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultPortPair.java @@ -0,0 +1,198 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.vtnrsc; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.Objects; + +/** + * Implementation of port pair. + */ +public final class DefaultPortPair implements PortPair { + + private final PortPairId portPairId; + private final TenantId tenantId; + private final String name; + private final String description; + private final String ingress; + private final String egress; + + /** + * Default constructor to create Port Pair. + * + * @param portPairId port pair id + * @param tenantId tenant id + * @param name name of port pair + * @param description description of port pair + * @param ingress ingress port + * @param egress egress port + */ + private DefaultPortPair(PortPairId portPairId, TenantId tenantId, + String name, String description, + String ingress, String egress) { + + this.portPairId = portPairId; + this.tenantId = tenantId; + this.name = name; + this.description = description; + this.ingress = ingress; + this.egress = egress; + } + + @Override + public PortPairId portPairId() { + return portPairId; + } + + @Override + public TenantId tenantId() { + return tenantId; + } + + @Override + public String name() { + return name; + } + + @Override + public String description() { + return description; + } + + @Override + public String ingress() { + return ingress; + } + + @Override + public String egress() { + return egress; + } + + @Override + public int hashCode() { + return Objects.hash(portPairId, tenantId, name, description, + ingress, egress); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DefaultPortPair) { + DefaultPortPair that = (DefaultPortPair) obj; + return Objects.equals(portPairId, that.portPairId) && + Objects.equals(tenantId, that.tenantId) && + Objects.equals(name, that.name) && + Objects.equals(description, that.description) && + Objects.equals(ingress, that.ingress) && + Objects.equals(egress, that.egress); + } + return false; + } + + @Override + public boolean exactMatch(PortPair portPair) { + return this.equals(portPair) && + Objects.equals(this.portPairId, portPair.portPairId()) && + Objects.equals(this.tenantId, portPair.tenantId()); + } + + @Override + public String toString() { + return toStringHelper(this) + .add("id", portPairId.toString()) + .add("tenantId", tenantId.tenantId()) + .add("name", name) + .add("description", description) + .add("ingress", ingress) + .add("egress", egress) + .toString(); + } + + /** + * To create an instance of the builder. + * + * @return instance of builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder class for Port pair. + */ + public static final class Builder implements PortPair.Builder { + + private PortPairId portPairId; + private TenantId tenantId; + private String name; + private String description; + private String ingress; + private String egress; + + @Override + public Builder setId(PortPairId portPairId) { + this.portPairId = portPairId; + return this; + } + + @Override + public Builder setTenantId(TenantId tenantId) { + this.tenantId = tenantId; + return this; + } + + @Override + public Builder setName(String name) { + this.name = name; + return this; + } + + @Override + public Builder setDescription(String description) { + this.description = description; + return this; + } + + @Override + public Builder setIngress(String ingress) { + this.ingress = ingress; + return this; + } + + @Override + public Builder setEgress(String egress) { + this.egress = egress; + return this; + } + + @Override + public PortPair build() { + + checkNotNull(portPairId, "Port pair id cannot be null"); + checkNotNull(tenantId, "Tenant id cannot be null"); + checkNotNull(ingress, "Ingress of a port pair cannot be null"); + checkNotNull(egress, "Egress of a port pair cannot be null"); + + return new DefaultPortPair(portPairId, tenantId, name, description, + ingress, egress); + } + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultPortPairGroup.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultPortPairGroup.java new file mode 100644 index 00000000..877cc6c9 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultPortPairGroup.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 static com.google.common.base.Preconditions.checkNotNull; + +import java.util.List; +import java.util.Objects; + +import com.google.common.collect.ImmutableList; + +/** + * Implementation of port pair group. + */ +public final class DefaultPortPairGroup implements PortPairGroup { + + private final PortPairGroupId portPairGroupId; + private final TenantId tenantId; + private final String name; + private final String description; + private final List portPairList; + + /** + * Default constructor to create Port Pair Group. + * + * @param portPairGroupId port pair group id + * @param tenantId tenant id + * @param name name of port pair group + * @param description description of port pair group + * @param portPairList list of port pairs + */ + private DefaultPortPairGroup(PortPairGroupId portPairGroupId, TenantId tenantId, + String name, String description, + List portPairList) { + + this.portPairGroupId = portPairGroupId; + this.tenantId = tenantId; + this.name = name; + this.description = description; + this.portPairList = portPairList; + } + + @Override + public PortPairGroupId portPairGroupId() { + return portPairGroupId; + } + + @Override + public TenantId tenantId() { + return tenantId; + } + + @Override + public String name() { + return name; + } + + @Override + public String description() { + return description; + } + + @Override + public List portPairs() { + return ImmutableList.copyOf(portPairList); + } + + @Override + public int hashCode() { + return Objects.hash(portPairGroupId, tenantId, name, description, + portPairList); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DefaultPortPairGroup) { + DefaultPortPairGroup that = (DefaultPortPairGroup) obj; + return Objects.equals(portPairGroupId, that.portPairGroupId) && + Objects.equals(tenantId, that.tenantId) && + Objects.equals(name, that.name) && + Objects.equals(description, that.description) && + Objects.equals(portPairList, that.portPairList); + } + return false; + } + + @Override + public boolean exactMatch(PortPairGroup portPairGroup) { + return this.equals(portPairGroup) && + Objects.equals(this.portPairGroupId, portPairGroup.portPairGroupId()) && + Objects.equals(this.tenantId, portPairGroup.tenantId()); + } + + @Override + public String toString() { + return toStringHelper(this) + .add("id", portPairGroupId.toString()) + .add("tenantId", tenantId.toString()) + .add("name", name) + .add("description", description) + .add("portPairGroupList", portPairList) + .toString(); + } + + /** + * To create an instance of the builder. + * + * @return instance of builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder class for Port pair group. + */ + public static final class Builder implements PortPairGroup.Builder { + + private PortPairGroupId portPairGroupId; + private TenantId tenantId; + private String name; + private String description; + private List portPairList; + + @Override + public Builder setId(PortPairGroupId portPairGroupId) { + this.portPairGroupId = portPairGroupId; + return this; + } + + @Override + public Builder setTenantId(TenantId tenantId) { + this.tenantId = tenantId; + return this; + } + + @Override + public Builder setName(String name) { + this.name = name; + return this; + } + + @Override + public Builder setDescription(String description) { + this.description = description; + return this; + } + + @Override + public Builder setPortPairs(List portPairs) { + this.portPairList = portPairs; + return this; + } + + @Override + public PortPairGroup build() { + + checkNotNull(portPairGroupId, "Port pair group id cannot be null"); + checkNotNull(tenantId, "Tenant id cannot be null"); + checkNotNull(portPairList, "Port pairs cannot be null"); + + return new DefaultPortPairGroup(portPairGroupId, tenantId, name, description, + portPairList); + } + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/FlowClassifier.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/FlowClassifier.java new file mode 100644 index 00000000..7b4108dc --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/FlowClassifier.java @@ -0,0 +1,259 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.vtnrsc; + +import org.onlab.packet.IpPrefix; + +/** + * Abstraction of an entity which provides flow classifier for service function chain. + * FlowClassifier classify the traffic based on the criteria defined in the request. + * The classification can be based on port range or source and destination IP address or + * other flow classifier elements. + */ +public interface FlowClassifier { + + /** + * Returns flow classifier ID. + * + * @return flow classifier id + */ + FlowClassifierId flowClassifierId(); + + /** + * Returns Tenant ID. + * + * @return tenant Id + */ + TenantId tenantId(); + + /** + * Returns flow classifier name. + * + * @return flow classifier name + */ + String name(); + + /** + * Returns flow classifier description. + * + * @return flow classifier description + */ + String description(); + + /** + * Returns EtherType. + * + * @return EtherType + */ + String etherType(); + + /** + * Returns IP Protocol. + * + * @return IP protocol + */ + String protocol(); + + /** + * Returns minimum source port range. + * + * @return minimum source port range + */ + int minSrcPortRange(); + + /** + * Returns maximum source port range. + * + * @return maximum source port range + */ + int maxSrcPortRange(); + + /** + * Returns minimum destination port range. + * + * @return minimum destination port range + */ + int minDstPortRange(); + + /** + * Returns maximum destination port range. + * + * @return maximum destination port range. + */ + int maxDstPortRange(); + + /** + * Returns Source IP prefix. + * + * @return Source IP prefix + */ + IpPrefix srcIpPrefix(); + + /** + * Returns Destination IP prefix. + * + * @return Destination IP prefix + */ + IpPrefix dstIpPrefix(); + + /** + * Returns Source virtual port. + * + * @return Source virtual port + */ + VirtualPortId srcPort(); + + /** + * Returns Destination virtual port. + * + * @return Destination virtual port + */ + VirtualPortId dstPort(); + + /** + * Returns whether this Flow classifier is an exact match to the + * Flow classifier given in the argument. + * + * @param flowClassifier other flowClassifier to match against + * @return true if the flowClassifiers are an exact match, otherwise false + */ + boolean exactMatch(FlowClassifier flowClassifier); + + /** + * Builder for flow Classifier. + */ + interface Builder { + + /** + * Returns Flow Classifier. + * + * @return flow classifier. + */ + FlowClassifier build(); + + /** + * Sets Flow Classifier ID. + * + * @param flowClassifierId flow classifier id. + * @return Builder object by setting flow classifier Id. + */ + Builder setFlowClassifierId(FlowClassifierId flowClassifierId); + + /** + * Sets Tenant ID. + * + * @param tenantId tenant id. + * @return Builder object by setting Tenant ID. + */ + Builder setTenantId(TenantId tenantId); + + /** + * Sets Flow classifier name. + * + * @param name flow classifier name + * @return builder object by setting flow classifier name + */ + Builder setName(String name); + + /** + * Sets flow classifier description. + * + * @param description flow classifier description + * @return flow classifier description + */ + Builder setDescription(String description); + + /** + * Sets EtherType. + * + * @param etherType EtherType + * @return EtherType + */ + Builder setEtherType(String etherType); + + /** + * Sets IP protocol. + * + * @param protocol IP protocol + * @return builder object by setting IP protocol + */ + Builder setProtocol(String protocol); + + /** + * Set minimum source port range. + * + * @param minRange minimum source port range + * @return builder object by setting minimum source port range + */ + Builder setMinSrcPortRange(int minRange); + + /** + * Sets maximum source port range. + * + * @param maxRange maximum source port range + * @return builder object by setting maximum source port range + */ + Builder setMaxSrcPortRange(int maxRange); + + /** + * Sets minimum destination port range. + * + * @param minRange minimum destination port range + * @return builder object by setting minimum destination port range + */ + Builder setMinDstPortRange(int minRange); + + /** + * Sets maximum destination port range. + * + * @param maxRange maximum destination port range. + * @return builder object by setting maximum destination port range. + */ + Builder setMaxDstPortRange(int maxRange); + + /** + * Sets Source IP prefix. + * + * @param srcIpPrefix Source IP prefix + * @return builder object by setting Source IP prefix + */ + Builder setSrcIpPrefix(IpPrefix srcIpPrefix); + + /** + * Sets Destination IP prefix. + * + * @param dstIpPrefix Destination IP prefix + * @return builder object by setting Destination IP prefix + */ + Builder setDstIpPrefix(IpPrefix dstIpPrefix); + + /** + * Sets Source virtual port. + * + * @param srcPort Source virtual port + * @return builder object by setting Source virtual port + */ + Builder setSrcPort(VirtualPortId srcPort); + + /** + * Sets Destination virtual port. + * + * @param dstPort Destination virtual port + * @return builder object by setting Destination virtual port + */ + Builder setDstPort(VirtualPortId dstPort); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/FlowClassifierId.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/FlowClassifierId.java new file mode 100644 index 00000000..b789abe3 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/FlowClassifierId.java @@ -0,0 +1,91 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.vtnrsc; + +import com.google.common.base.MoreObjects; + +import java.util.UUID; +import java.util.Objects; + +/** + * Flow classification identifier. + */ +public final class FlowClassifierId { + + private final UUID flowClassifierId; + + /** + * Constructor to create flow classifier id. + * + * @param flowClassifierId flow classifier id. + */ + private FlowClassifierId(final UUID flowClassifierId) { + this.flowClassifierId = flowClassifierId; + } + + /** + * Returns new flow classifier id. + * + * @param flowClassifierId flow classifier id + * @return new flow classifier id + */ + public static FlowClassifierId flowClassifierId(final UUID flowClassifierId) { + return new FlowClassifierId(flowClassifierId); + } + + /** + * Returns new flow classifier id. + * + * @param flowClassifierId flow classifier id + * @return new flow classifier id + */ + public static FlowClassifierId flowClassifierId(final String flowClassifierId) { + return new FlowClassifierId(UUID.fromString(flowClassifierId)); + } + + /** + * Returns the value of flow classifier id. + * + * @return flow classifier id. + */ + public UUID value() { + return flowClassifierId; + } + + @Override + public int hashCode() { + return Objects.hashCode(this.flowClassifierId); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof FlowClassifierId) { + final FlowClassifierId other = (FlowClassifierId) obj; + return Objects.equals(this.flowClassifierId, other.flowClassifierId); + } + return false; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("FlowClassifierId", flowClassifierId) + .toString(); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortChain.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortChain.java new file mode 100644 index 00000000..d147eaaa --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortChain.java @@ -0,0 +1,148 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.vtnrsc; + +import java.util.List; + +/** + * Abstraction of an entity providing Port Chain information. + * A Port Chain (Service Function Path) consists of + * a set of Neutron ports, to define the sequence of service functions + * a set of flow classifiers, to specify the classified traffic flows to enter the chain + */ +public interface PortChain { + + /** + * Returns the ID of this port chain. + * + * @return the port chain id + */ + PortChainId portChainId(); + + /** + * Returns the tenant id of this port chain. + * + * @return the tenant id + */ + TenantId tenantId(); + + /** + * Returns the name of this port chain. + * + * @return name of port chain + */ + String name(); + + /** + * Returns the description of this port chain. + * + * @return description of port chain + */ + String description(); + + /** + * Returns the list of port pair groups associated with + * this port chain. + * + * @return list of port pair groups + */ + List portPairGroups(); + + /** + * Returns the list of flow classifiers associated with + * this port chain. + * + * @return list of flow classifiers + */ + List flowClassifiers(); + + /** + * Returns whether this port chain is an exact match to the port chain given + * in the argument. + *

+ * Exact match means the port pair groups and flow classifiers match + * with the given port chain. It does not consider the port chain id, name + * and description. + *

+ * + * @param portChain other port chain to match against + * @return true if the port chains are an exact match, otherwise false + */ + boolean exactMatch(PortChain portChain); + + /** + * A port chain builder.. + */ + interface Builder { + + /** + * Assigns the port chain id to this object. + * + * @param portChainId the port chain id + * @return this the builder object + */ + Builder setId(PortChainId portChainId); + + /** + * Assigns tenant id to this object. + * + * @param tenantId tenant id of the port chain + * @return this the builder object + */ + Builder setTenantId(TenantId tenantId); + + /** + * Assigns the name to this object. + * + * @param name name of the port chain + * @return this the builder object + */ + Builder setName(String name); + + /** + * Assigns the description to this object. + * + * @param description description of the port chain + * @return this the builder object + */ + Builder setDescription(String description); + + /** + * Assigns the port pair groups associated with the port chain + * to this object. + * + * @param portPairGroups list of port pair groups + * @return this the builder object + */ + Builder setPortPairGroups(List portPairGroups); + + /** + * Assigns the flow classifiers associated with the port chain + * to this object. + * + * @param flowClassifiers list of flow classifiers + * @return this the builder object + */ + Builder setFlowClassifiers(List flowClassifiers); + + /** + * Builds a port chain object. + * + * @return a port chain. + */ + PortChain build(); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortChainId.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortChainId.java new file mode 100644 index 00000000..66edbdcc --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortChainId.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.vtnrsc; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.UUID; + +import com.google.common.base.Objects; + +/** + * Representation of a Port Chain ID. + */ +public final class PortChainId { + + private final UUID portChainId; + + /** + * Private constructor for port chain id. + * + * @param id UUID id of port chain + */ + private PortChainId(UUID id) { + checkNotNull(id, "Port chain id can not be null"); + this.portChainId = id; + } + + /** + * Constructor to create port chain id from UUID. + * + * @param id UUID of port chain + * @return object of port chain id + */ + public static PortChainId portChainId(UUID id) { + return new PortChainId(id); + } + + /** + * Constructor to create port chain id from string. + * + * @param id port chain id in string + * @return object of port chain id + */ + public static PortChainId portChainId(String id) { + return new PortChainId(UUID.fromString(id)); + } + + /** + * Returns the value of port chain id. + * + * @return port chain id + */ + public UUID value() { + return portChainId; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj.getClass() == this.getClass()) { + PortChainId that = (PortChainId) obj; + return Objects.equal(this.portChainId, that.portChainId); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hashCode(this.portChainId); + } + + @Override + public String toString() { + return toStringHelper(this) + .add("portChainId", portChainId.toString()) + .toString(); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPair.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPair.java new file mode 100644 index 00000000..f6285e61 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPair.java @@ -0,0 +1,139 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.vtnrsc; + + +/** + * Abstraction of an entity providing Port Pair information. + * A port pair represents a service function instance. + */ +public interface PortPair { + + /** + * Returns the ID of this port Pair. + * + * @return the port pair id + */ + PortPairId portPairId(); + + /** + * Returns the tenant id of this port pair. + * + * @return an tenant id + */ + TenantId tenantId(); + + /** + * Returns the description of this port pair. + * + * @return description of port pair + */ + String name(); + + /** + * Returns the description of this port pair. + * + * @return description of port pair + */ + String description(); + + /** + * Returns the ingress port of this port pair. + * + * @return ingress of port pair + */ + String ingress(); + + /** + * Returns the egress port of this port pair. + * + * @return egress of port pair + */ + String egress(); + + /** + * Returns whether this port pair is an exact match to the port pair given + * in the argument. + *

+ * Exact match means the Port port pairs match with the given port pair. + * It does not consider the port pair id, name and description. + *

+ * @param portPair other port pair to match against + * @return true if the port pairs are an exact match, otherwise false + */ + boolean exactMatch(PortPair portPair); + + /** + * A port pair builder.. + */ + interface Builder { + + /** + * Assigns the port pair id to this object. + * + * @param portPairId the port pair id + * @return this the builder object + */ + Builder setId(PortPairId portPairId); + + /** + * Assigns tenant id to this object. + * + * @param tenantId tenant id of the port pair + * @return this the builder object + */ + Builder setTenantId(TenantId tenantId); + + /** + * Assigns the name to this object. + * + * @param name name of the port pair + * @return this the builder object + */ + Builder setName(String name); + + /** + * Assigns the description to this object. + * + * @param description description of the port pair + * @return this the builder object + */ + Builder setDescription(String description); + + /** + * Assigns the ingress port to this object. + * + * @param port ingress port of the port pair + * @return this the builder object + */ + Builder setIngress(String port); + + /** + * Assigns the egress port to this object. + * + * @param port egress port of the port pair + * @return this the builder object + */ + Builder setEgress(String port); + + /** + * Builds a port pair object. + * + * @return a port pair. + */ + PortPair build(); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPairGroup.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPairGroup.java new file mode 100644 index 00000000..f647b57f --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPairGroup.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.vtnrsc; + +import java.util.List; + +/** + * Abstraction of an entity providing Port Pair Group information. + * A port pair group consists of one or more port pairs. + */ +public interface PortPairGroup { + + /** + * Returns the ID of this port pair group. + * + * @return the port pair group id + */ + PortPairGroupId portPairGroupId(); + + /** + * Returns the tenant id of this port pair group. + * + * @return the tenant id + */ + TenantId tenantId(); + + /** + * Returns the name of this port pair group. + * + * @return name of port pair group + */ + String name(); + + /** + * Returns the description of this port pair group. + * + * @return description of port pair group + */ + String description(); + + /** + * Returns the list of port pairs associated with this port pair group. + * + * @return list of port pairs + */ + List portPairs(); + + /** + * Returns whether this port pair group is an exact match to the + * port pair group given in the argument. + *

+ * Exact match means the Port pairs match with the given port pair group. + * It does not consider the port pair group id, name and description. + *

+ * @param portPairGroup other port pair group to match against + * @return true if the port pairs are an exact match, otherwise false + */ + boolean exactMatch(PortPairGroup portPairGroup); + + /** + * A port pair group builder.. + */ + interface Builder { + + /** + * Assigns the port pair group id to this object. + * + * @param portPairGroupId the port pair group id + * @return this the builder object + */ + Builder setId(PortPairGroupId portPairGroupId); + + /** + * Assigns tenant id to this object. + * + * @param tenantId tenant id of port pair group + * @return this the builder object + */ + Builder setTenantId(TenantId tenantId); + + /** + * Assigns the name to this object. + * + * @param name name of the port pair group + * @return this the builder object + */ + Builder setName(String name); + + /** + * Assigns the description to this object. + * + * @param description description of the port pair group + * @return this the builder object + */ + Builder setDescription(String description); + + /** + * Assigns the port pairs associated with the port pair group + * to this object. + * + * @param portPairs list of port pairs + * @return this the builder object + */ + Builder setPortPairs(List portPairs); + + /** + * Builds a port pair group object. + * + * @return a port pair group object. + */ + PortPairGroup build(); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPairGroupId.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPairGroupId.java new file mode 100644 index 00000000..0474901c --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPairGroupId.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.vtnrsc; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.UUID; + +import com.google.common.base.Objects; + +/** + * Representation of a Port Pair Group ID. + */ +public final class PortPairGroupId { + + private final UUID portPairGroupId; + + /** + * Private constructor for port pair group id. + * + * @param id UUID id of port pair group + */ + private PortPairGroupId(UUID id) { + checkNotNull(id, "Port pair group id can not be null"); + this.portPairGroupId = id; + } + + /** + * Constructor to create port pair group id from UUID. + * + * @param id UUID of port pair group id + * @return object of port pair group id + */ + public static PortPairGroupId portPairGroupId(UUID id) { + return new PortPairGroupId(id); + } + + /** + * Constructor to create port pair group id from string. + * + * @param id port pair group id in string + * @return object of port pair group id + */ + public static PortPairGroupId portPairGroupId(String id) { + return new PortPairGroupId(UUID.fromString(id)); + } + + /** + * Returns the value of port pair group id. + * + * @return port pair group id + */ + public UUID value() { + return portPairGroupId; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj.getClass() == this.getClass()) { + PortPairGroupId that = (PortPairGroupId) obj; + return Objects.equal(this.portPairGroupId, that.portPairGroupId); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hashCode(this.portPairGroupId); + } + + @Override + public String toString() { + return toStringHelper(this) + .add("portPairGroupId", portPairGroupId.toString()) + .toString(); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPairId.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPairId.java new file mode 100644 index 00000000..05c31aac --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPairId.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.vtnrsc; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.UUID; + +import com.google.common.base.Objects; + +/** + * Representation of a Port Pair ID. + */ +public final class PortPairId { + + private final UUID portPairId; + + /** + * Private constructor for port pair id. + * + * @param id UUID id of port pair + */ + private PortPairId(UUID id) { + checkNotNull(id, "Port chain id can not be null"); + this.portPairId = id; + } + + /** + * Constructor to create port pair id from UUID. + * + * @param id UUID of port pair id + * @return object of port pair id + */ + public static PortPairId portPairId(UUID id) { + return new PortPairId(id); + } + + /** + * Constructor to create port pair id from string. + * + * @param id port pair id in string + * @return object of port pair id + */ + public static PortPairId portPairId(String id) { + return new PortPairId(UUID.fromString(id)); + } + + /** + * Returns teh value of port pair id. + * + * @return port pair id + */ + public UUID value() { + return portPairId; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj.getClass() == this.getClass()) { + PortPairId that = (PortPairId) obj; + return Objects.equal(this.portPairId, that.portPairId); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hashCode(this.portPairId); + } + + @Override + public String toString() { + return toStringHelper(this) + .add("portPairId", portPairId.toString()) + .toString(); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/FlowClassifierService.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/FlowClassifierService.java new file mode 100644 index 00000000..e379be81 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/FlowClassifierService.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.flowClassifier; + +import org.onosproject.vtnrsc.FlowClassifier; +import org.onosproject.vtnrsc.FlowClassifierId; + +/** + * Provides Services for Flow Classifier. + */ +public interface FlowClassifierService { + + /** + * Store Flow Classifier. + * + * @param flowClassifier Flow Classifier + * @return true if adding Flow Classifier into store is success otherwise return false. + */ + boolean createFlowClassifier(FlowClassifier flowClassifier); + + /** + * Return the existing collection of Flow Classifier. + * + * @return Flow Classifier collections. + */ + Iterable getFlowClassifiers(); + + /** + * Check whether Flow Classifier is present based on given Flow Classifier Id. + * + * @param id Flow Classifier. + * @return true if Flow Classifier is present otherwise return false. + */ + boolean hasFlowClassifier(FlowClassifierId id); + + /** + * Retrieve the Flow Classifier based on given Flow Classifier id. + * + * @param id Flow Classifier Id. + * @return Flow Classifier if present otherwise returns null. + */ + FlowClassifier getFlowClassifier(FlowClassifierId id); + + /** + * Update Flow Classifier based on given Flow Classifier Id. + * + * @param flowClassifier Flow Classifier. + * @return true if update is success otherwise return false. + */ + boolean updateFlowClassifier(FlowClassifier flowClassifier); + + /** + * Remove Flow Classifier from store based on given Flow Classifier Id. + * + * @param id Flow Classifier Id. + * @return true if Flow Classifier removal is success otherwise return false. + */ + boolean removeFlowClassifier(FlowClassifierId id); +} \ No newline at end of file diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/impl/FlowClassifierManager.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/impl/FlowClassifierManager.java new file mode 100644 index 00000000..7238558a --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/impl/FlowClassifierManager.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.vtnrsc.flowClassifier.impl; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.apache.felix.scr.annotations.Activate; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Deactivate; +import org.apache.felix.scr.annotations.Service; +import org.onosproject.vtnrsc.FlowClassifierId; +import org.onosproject.vtnrsc.FlowClassifier; +import org.onosproject.vtnrsc.flowClassifier.FlowClassifierService; + +import org.slf4j.Logger; +import static org.slf4j.LoggerFactory.getLogger; + +import static com.google.common.base.Preconditions.checkNotNull; +import com.google.common.collect.ImmutableList; + +/** + * Provides implementation of the Flow Classifier Service. + */ +@Component(immediate = true) +@Service +public class FlowClassifierManager implements FlowClassifierService { + + private final Logger log = getLogger(FlowClassifierManager.class); + + private static final String FLOW_CLASSIFIER_NOT_NULL = "Flow Classifier cannot be null"; + private static final String FLOW_CLASSIFIER_ID_NOT_NULL = "Flow Classifier Id cannot be null"; + + private ConcurrentMap flowClassifierStore + = new ConcurrentHashMap(); + + @Activate + private void activate() { + log.info("Flow Classifier service activated"); + } + + @Deactivate + private void deactivate() { + log.info("Flow Classifier service deactivated"); + } + + @Override + public boolean createFlowClassifier(FlowClassifier flowClassifier) { + log.debug("createFlowClassifier"); + checkNotNull(flowClassifier, FLOW_CLASSIFIER_NOT_NULL); + FlowClassifierId id = flowClassifier.flowClassifierId(); + + flowClassifierStore.put(id, flowClassifier); + if (!flowClassifierStore.containsKey(id)) { + log.debug("Flow Classifier creation is failed whose identifier is {}.", id.toString()); + return false; + } + return true; + } + + @Override + public Iterable getFlowClassifiers() { + return ImmutableList.copyOf(flowClassifierStore.values()); + } + + @Override + public boolean hasFlowClassifier(FlowClassifierId id) { + checkNotNull(id, FLOW_CLASSIFIER_ID_NOT_NULL); + return flowClassifierStore.containsKey(id); + } + + @Override + public FlowClassifier getFlowClassifier(FlowClassifierId id) { + checkNotNull(id, FLOW_CLASSIFIER_ID_NOT_NULL); + return flowClassifierStore.get(id); + } + + @Override + public boolean updateFlowClassifier(FlowClassifier flowClassifier) { + checkNotNull(flowClassifier, FLOW_CLASSIFIER_NOT_NULL); + FlowClassifierId id = flowClassifier.flowClassifierId(); + return flowClassifierStore.replace(id, flowClassifierStore.get(id), flowClassifier); + } + + @Override + public boolean removeFlowClassifier(FlowClassifierId id) { + checkNotNull(id, FLOW_CLASSIFIER_ID_NOT_NULL); + flowClassifierStore.remove(id); + if (flowClassifierStore.containsKey(id)) { + log.debug("The Flow Classifier removal is failed whose identifier is {}", id.toString()); + return false; + } + return true; + } +} \ No newline at end of file diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/impl/package-info.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/impl/package-info.java new file mode 100644 index 00000000..4ea050b3 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/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 flow Classifier service. + */ +package org.onosproject.vtnrsc.flowClassifier.impl; diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/package-info.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/package-info.java new file mode 100644 index 00000000..07584170 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/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 flow Classifier of SFC. + */ +package org.onosproject.vtnrsc.flowClassifier; diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portchain/PortChainService.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portchain/PortChainService.java new file mode 100644 index 00000000..b4ff917e --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portchain/PortChainService.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.portchain; + +import org.onosproject.vtnrsc.PortChain; +import org.onosproject.vtnrsc.PortChainId; + +/** + * Service for interacting with the inventory of port chains. + */ +public interface PortChainService { + + /** + * Returns if the port chain is existed. + * + * @param portChainId port chain identifier + * @return true or false if one with the given identifier exists. + */ + boolean exists(PortChainId portChainId); + + /** + * Returns the number of port chains known to the system. + * + * @return number of port chains. + */ + int getPortChainCount(); + + /** + * Returns an iterable collection of the currently known port chains. + * + * @return collection of port chains. + */ + Iterable getPortChains(); + + /** + * Returns the portChain with the given identifier. + * + * @param portChainId port chain identifier + * @return PortChain or null if port chain with the given identifier is not + * known. + */ + PortChain getPortChain(PortChainId portChainId); + + /** + * Creates a PortChain in the store. + * + * @param portChain the port chain to create + * @return true if given port chain is created successfully. + */ + boolean createPortChain(PortChain portChain); + + /** + * Updates the portChain in the store. + * + * @param portChain the port chain to update + * @return true if given port chain is updated successfully. + */ + boolean updatePortChain(PortChain portChain); + + /** + * Deletes portChain by given portChainId. + * + * @param portChainId id of port chain to remove + * @return true if the give port chain is deleted successfully. + */ + boolean removePortChain(PortChainId portChainId); +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portchain/package-info.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portchain/package-info.java new file mode 100644 index 00000000..74642bc3 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portchain/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 port chains. + */ +package org.onosproject.vtnrsc.portchain; diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portpairgroup/PortPairGroupService.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portpairgroup/PortPairGroupService.java new file mode 100644 index 00000000..77f483fc --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portpairgroup/PortPairGroupService.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.portpairgroup; + +import org.onosproject.vtnrsc.PortPairGroup; +import org.onosproject.vtnrsc.PortPairGroupId; + +/** + * Service for interacting with the inventory of port pair groups. + */ +public interface PortPairGroupService { + + /** + * Returns if the port pair group is existed. + * + * @param portPairGroupId port pair group identifier + * @return true or false if one with the given identifier exists. + */ + boolean exists(PortPairGroupId portPairGroupId); + + /** + * Returns the number of port pair groups known to the system. + * + * @return number of port pair groups. + */ + int getPortPairGroupCount(); + + /** + * Returns an iterable collection of the currently known port pair groups. + * + * @return collection of port pair groups. + */ + Iterable getPortPairGroups(); + + /** + * Returns the portPairGroup with the given identifier. + * + * @param portPairGroupId port pair group identifier + * @return PortPairGroup or null if port pair group with the given identifier is not + * known. + */ + PortPairGroup getPortPairGroup(PortPairGroupId portPairGroupId); + + /** + * Creates a PortPairGroup in the store. + * + * @param portPairGroup the port pair group to create + * @return true if given port pair group is created successfully. + */ + boolean createPortPairGroup(PortPairGroup portPairGroup); + + /** + * Updates the portPairGroup in the store. + * + * @param portPairGroup the port pair group to update + * @return true if given port pair group is updated successfully. + */ + boolean updatePortPairGroup(PortPairGroup portPairGroup); + + /** + * Deletes portPairGroup by given portPairGroupId. + * + * @param portPairGroupId id of port pair group to remove + * @return true if the give port pair group is deleted successfully. + */ + boolean removePortPairGroup(PortPairGroupId portPairGroupId); +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portpairgroup/package-info.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portpairgroup/package-info.java new file mode 100644 index 00000000..8a79fe97 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portpairgroup/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 port pair groups. + */ +package org.onosproject.vtnrsc.portpairgroup; diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/tunnel/TunnelConfigService.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/tunnel/TunnelConfigService.java deleted file mode 100644 index 6f3cf653..00000000 --- a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/tunnel/TunnelConfigService.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.onosproject.vtnrsc.tunnel; - -import org.onosproject.vtnrsc.Subnet; -import org.onosproject.vtnrsc.SubnetId; - - -/** - * Service for interacting with the inventory of subnets. - */ -public interface TunnelConfigService { - /** - * Returns the subnet with the specified identifier. - * - * @param subnetId subnet identifier - * @return true or false - */ - boolean exists(SubnetId subnetId); - /** - * Returns a collection of the currently known subnets. - * - * @return iterable collection of subnets - */ - Iterable 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 subnets); - - /** - * Updates existing subnets. - * - * @param subnets the iterable collection of subnets - * @return true if all subnets were updated successfully - */ - boolean updateSubnets(Iterable 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 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 deleted file mode 100644 index 3a84e6e3..00000000 --- a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/tunnel/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * 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/impl/VirtualPortManager.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/impl/VirtualPortManager.java index c45373b9..daec7839 100644 --- 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 @@ -191,22 +191,20 @@ public class VirtualPortManager implements VirtualPortService { @Override public boolean updatePorts(Iterable vPorts) { checkNotNull(vPorts, VIRTUALPORT_NOT_NULL); - if (vPorts != null) { - for (VirtualPort vPort : vPorts) { - vPortStore.put(vPort.portId(), vPort); - if (!vPortStore.containsKey(vPort.portId())) { - log.debug("The virtualPort is not exist whose identifier is {}", - vPort.portId().toString()); - return false; - } + for (VirtualPort vPort : vPorts) { + vPortStore.put(vPort.portId(), vPort); + if (!vPortStore.containsKey(vPort.portId())) { + log.debug("The virtualPort is not exist whose identifier is {}", + vPort.portId().toString()); + return false; + } - vPortStore.put(vPort.portId(), vPort); + vPortStore.put(vPort.portId(), vPort); - if (!vPort.equals(vPortStore.get(vPort.portId()))) { - log.debug("The virtualPort is updated failed whose identifier is {}", - vPort.portId().toString()); - return false; - } + if (!vPort.equals(vPortStore.get(vPort.portId()))) { + log.debug("The virtualPort is updated failed whose identifier is {}", + vPort.portId().toString()); + return false; } } return true; @@ -215,14 +213,12 @@ public class VirtualPortManager implements VirtualPortService { @Override public boolean removePorts(Iterable vPortIds) { checkNotNull(vPortIds, VIRTUALPORT_ID_NULL); - if (vPortIds != null) { - for (VirtualPortId vPortId : vPortIds) { - vPortStore.remove(vPortId); - if (vPortStore.containsKey(vPortId)) { - log.debug("The virtualPort is removed failed whose identifier is {}", - vPortId.toString()); - return false; - } + for (VirtualPortId vPortId : vPortIds) { + vPortStore.remove(vPortId); + if (vPortStore.containsKey(vPortId)) { + log.debug("The virtualPort is removed failed whose identifier is {}", + vPortId.toString()); + return false; } } return true; diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/AllocationPoolsCodec.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/AllocationPoolsCodec.java deleted file mode 100644 index 57c97c1c..00000000 --- a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/AllocationPoolsCodec.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.onosproject.vtnrsc.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 { - - @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 deleted file mode 100644 index 7960808f..00000000 --- a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/AllowedAddressPairCodec.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.onosproject.vtnrsc.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 { - - @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 deleted file mode 100644 index 96c9bb4e..00000000 --- a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/FixedIpCodec.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.onosproject.vtnrsc.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 { - - @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/FlowClassifierCodec.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/FlowClassifierCodec.java new file mode 100644 index 00000000..fd5b1ee4 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/FlowClassifierCodec.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.web; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onlab.util.Tools.nullIsIllegal; + +import java.util.UUID; + +import org.onlab.packet.IpPrefix; +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; +import org.onosproject.vtnrsc.DefaultFlowClassifier; +import org.onosproject.vtnrsc.FlowClassifier; +import org.onosproject.vtnrsc.FlowClassifierId; +import org.onosproject.vtnrsc.VirtualPortId; +import org.onosproject.vtnrsc.TenantId; + +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * Flow Classifier JSON codec. + */ +public final class FlowClassifierCodec extends JsonCodec { + + private static final String FLOW_CLASSIFIER_ID = "id"; + private static final String TENANT_ID = "tenant_id"; + private static final String NAME = "name"; + private static final String DESCRIPTION = "description"; + private static final String ETHER_TYPE = "etherType"; + private static final String PROTOCOL = "protocol"; + private static final String MIN_SRC_PORT_RANGE = "source_port_range_min"; + private static final String MAX_SRC_PORT_RANGE = "source_port_range_max"; + private static final String MIN_DST_PORT_RANGE = "destination_port_range_min"; + private static final String MAX_DST_PORT_RANGE = "destination_port_range_max"; + private static final String SRC_IP_PREFIX = "source_ip_prefix"; + private static final String DST_IP_PREFIX = "destination_ip_prefix"; + private static final String SRC_PORT = "logical_source_port"; + private static final String DST_PORT = "logical_destination_port"; + private static final String MISSING_MEMBER_MESSAGE = " member is required in Flow Classifier."; + + @Override + public FlowClassifier decode(ObjectNode json, CodecContext context) { + if (json == null || !json.isObject()) { + return null; + } + + FlowClassifier.Builder resultBuilder = new DefaultFlowClassifier.Builder(); + + String flowClassifierId = nullIsIllegal(json.get(FLOW_CLASSIFIER_ID), + FLOW_CLASSIFIER_ID + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setFlowClassifierId(FlowClassifierId.flowClassifierId(UUID.fromString(flowClassifierId))); + + String tenantId = nullIsIllegal(json.get(TENANT_ID), TENANT_ID + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setTenantId(TenantId.tenantId(tenantId)); + + String flowClassiferName = nullIsIllegal(json.get(NAME), NAME + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setName(flowClassiferName); + + String flowClassiferDescription = nullIsIllegal(json.get(DESCRIPTION), DESCRIPTION + MISSING_MEMBER_MESSAGE) + .asText(); + resultBuilder.setDescription(flowClassiferDescription); + + String etherType = nullIsIllegal(json.get(ETHER_TYPE), ETHER_TYPE + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setEtherType(etherType); + + String protocol = nullIsIllegal(json.get(PROTOCOL), PROTOCOL + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setProtocol(protocol); + + int minSrcPortRange = nullIsIllegal(json.get(MIN_SRC_PORT_RANGE), MIN_SRC_PORT_RANGE + MISSING_MEMBER_MESSAGE) + .asInt(); + resultBuilder.setMinSrcPortRange(minSrcPortRange); + + int maxSrcPortRange = nullIsIllegal(json.get(MAX_SRC_PORT_RANGE), MAX_SRC_PORT_RANGE + MISSING_MEMBER_MESSAGE) + .asInt(); + resultBuilder.setMaxSrcPortRange(maxSrcPortRange); + + int minDstPortRange = nullIsIllegal(json.get(MIN_DST_PORT_RANGE), MIN_DST_PORT_RANGE + MISSING_MEMBER_MESSAGE) + .asInt(); + resultBuilder.setMinDstPortRange(minDstPortRange); + + int maxDstPortRange = nullIsIllegal(json.get(MAX_DST_PORT_RANGE), MAX_DST_PORT_RANGE + MISSING_MEMBER_MESSAGE) + .asInt(); + resultBuilder.setMaxDstPortRange(maxDstPortRange); + + String srcIpPrefix = nullIsIllegal(json.get(SRC_IP_PREFIX), SRC_IP_PREFIX + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setSrcIpPrefix(IpPrefix.valueOf(srcIpPrefix)); + + String dstIpPrefix = nullIsIllegal(json.get(DST_IP_PREFIX), DST_IP_PREFIX + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setDstIpPrefix(IpPrefix.valueOf(dstIpPrefix)); + + String srcPort = nullIsIllegal(json.get(SRC_PORT), SRC_PORT + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setSrcPort(VirtualPortId.portId(srcPort)); + + String dstPort = nullIsIllegal(json.get(DST_PORT), DST_PORT + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setDstPort(VirtualPortId.portId(dstPort)); + + return resultBuilder.build(); + } + + @Override + public ObjectNode encode(FlowClassifier flowClassifier, CodecContext context) { + checkNotNull(flowClassifier, "flowClassifier cannot be null"); + ObjectNode result = context.mapper().createObjectNode() + .put("FLOW_CLASSIFIER_ID", flowClassifier.flowClassifierId().toString()) + .put("TENANT_ID", flowClassifier.tenantId().toString()) + .put("NAME", flowClassifier.name()) + .put("DESCRIPTION", flowClassifier.description()) + .put("ETHER_TYPE", flowClassifier.etherType()) + .put("PROTOCOL", flowClassifier.protocol()) + .put("MIN_SRC_PORT_RANGE", flowClassifier.minSrcPortRange()) + .put("MAX_SRC_PORT_RANGE", flowClassifier.maxSrcPortRange()) + .put("MIN_DST_PORT_RANGE", flowClassifier.minDstPortRange()) + .put("MAX_DST_PORT_RANGE", flowClassifier.maxDstPortRange()) + .put("SRC_IP_PREFIX", flowClassifier.srcIpPrefix().toString()) + .put("DST_IP_PREFIX", flowClassifier.dstIpPrefix().toString()) + .put("SRC_PORT", flowClassifier.srcPort().toString()) + .put("DST_PORT", flowClassifier.dstPort().toString()); + return result; + } +} \ No newline at end of file diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/HostRoutesCodec.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/HostRoutesCodec.java deleted file mode 100644 index 69ca6b3f..00000000 --- a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/HostRoutesCodec.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.onosproject.vtnrsc.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 { - - @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 deleted file mode 100644 index c2ded196..00000000 --- a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/SecurityGroupCodec.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.onosproject.vtnrsc.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 { - - @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 deleted file mode 100644 index 122b75a9..00000000 --- a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/SubnetCodec.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.onosproject.vtnrsc.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 { - @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 deleted file mode 100644 index 48ba3b97..00000000 --- a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/TenantNetworkCodec.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.onosproject.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 { - - @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 deleted file mode 100644 index e57d56bc..00000000 --- a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/VirtualPortCodec.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.onosproject.vtnrsc.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 { - @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/test/java/org/onosproject/vtnrsc/flowclassifier/FlowClassifierIdTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/flowclassifier/FlowClassifierIdTest.java new file mode 100644 index 00000000..b2fed347 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/flowclassifier/FlowClassifierIdTest.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.vtnrsc.flowclassifier; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +import org.junit.Test; +import org.onosproject.vtnrsc.FlowClassifierId; + +import com.google.common.testing.EqualsTester; +import java.util.UUID; + +/** + * Unit tests for FlowClassifierId class. + */ +public class FlowClassifierIdTest { + + final FlowClassifierId flowClassifierId1 = FlowClassifierId + .flowClassifierId("78dcd363-fc23-aeb6-f44b-56dc5e2fb3ae"); + final FlowClassifierId sameAsFlowClassifierId1 = FlowClassifierId + .flowClassifierId("78dcd363-fc23-aeb6-f44b-56dc5e2fb3ae"); + final FlowClassifierId flowClassifierId2 = FlowClassifierId + .flowClassifierId("dace4513-24fc-4fae-af4b-321c5e2eb3d1"); + + /** + * Checks that the FlowClassifierId class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(FlowClassifierId.class); + } + + /** + * Checks the operation of equals() methods. + */ + @Test + public void testEquals() { + new EqualsTester().addEqualityGroup(flowClassifierId1, sameAsFlowClassifierId1) + .addEqualityGroup(flowClassifierId2).testEquals(); + } + + /** + * Checks the construction of a FlowClassifierId object. + */ + @Test + public void testConstruction() { + final String flowClassifierIdValue = "dace4513-24fc-4fae-af4b-321c5e2eb3d1"; + final FlowClassifierId flowClassifierId = FlowClassifierId.flowClassifierId(flowClassifierIdValue); + assertThat(flowClassifierId, is(notNullValue())); + assertThat(flowClassifierId.value(), is(UUID.fromString(flowClassifierIdValue))); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/subnet/DefaultAllocationPoolTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/subnet/DefaultAllocationPoolTest.java new file mode 100644 index 00000000..4ce4def2 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/subnet/DefaultAllocationPoolTest.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.vtnrsc.subnet; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +import org.junit.Test; +import org.onlab.packet.IpAddress; +import org.onosproject.vtnrsc.AllocationPool; +import org.onosproject.vtnrsc.DefaultAllocationPool; + +import com.google.common.testing.EqualsTester; + +/** + * Unit tests for DefaultAllocationPool class. + */ +public class DefaultAllocationPoolTest { + + final IpAddress startIP1 = IpAddress.valueOf("192.168.1.1"); + final IpAddress startIP2 = IpAddress.valueOf("192.168.1.2"); + final IpAddress endIP1 = IpAddress.valueOf("192.168.1.1"); + final IpAddress endIP2 = IpAddress.valueOf("192.168.1.2"); + + /** + * Checks that the DefaultAllocationPool class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(DefaultAllocationPool.class); + } + + /** + * Checks the operation of equals() methods. + */ + @Test + public void testEquals() { + AllocationPool pool1 = new DefaultAllocationPool(startIP1, endIP1); + AllocationPool pool2 = new DefaultAllocationPool(startIP1, endIP1); + AllocationPool pool3 = new DefaultAllocationPool(startIP2, endIP2); + new EqualsTester().addEqualityGroup(pool1, pool2) + .addEqualityGroup(pool3).testEquals(); + } + + /** + * Checks the construction of a DefaultAllocationPool object. + */ + @Test + public void testConstruction() { + final AllocationPool apool = new DefaultAllocationPool(startIP1, endIP1); + assertThat(startIP1, is(apool.startIp())); + assertThat(endIP1, is(apool.endIp())); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/subnet/DefaultHostRouteTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/subnet/DefaultHostRouteTest.java new file mode 100644 index 00000000..2f751742 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/subnet/DefaultHostRouteTest.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.vtnrsc.subnet; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +import org.junit.Test; +import org.onlab.packet.IpAddress; +import org.onlab.packet.IpPrefix; +import org.onosproject.vtnrsc.DefaultHostRoute; +import org.onosproject.vtnrsc.HostRoute; + +import com.google.common.testing.EqualsTester; + +/** + * Unit tests for DefaultHostRoute class. + */ +public class DefaultHostRouteTest { + final IpAddress nexthop1 = IpAddress.valueOf("192.168.1.1"); + final IpAddress nexthop2 = IpAddress.valueOf("192.168.1.2"); + final IpPrefix destination1 = IpPrefix.valueOf("1.1.1.1/1"); + final IpPrefix destination2 = IpPrefix.valueOf("1.1.1.1/2"); + + /** + * Checks that the DefaultHostRoute class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(DefaultHostRoute.class); + } + + /** + * Checks the operation of equals() methods. + */ + @Test + public void testEquals() { + HostRoute route1 = new DefaultHostRoute(nexthop1, destination1); + HostRoute route2 = new DefaultHostRoute(nexthop1, destination1); + HostRoute route3 = new DefaultHostRoute(nexthop2, destination2); + new EqualsTester().addEqualityGroup(route1, route2) + .addEqualityGroup(route3).testEquals(); + } + + /** + * Checks the construction of a DefaultHostRoute object. + */ + @Test + public void testConstruction() { + final HostRoute host = new DefaultHostRoute(nexthop1, destination1); + assertThat(nexthop1, is(host.nexthop())); + assertThat(destination1, is(host.destination())); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/subnet/SubnetIdTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/subnet/SubnetIdTest.java new file mode 100644 index 00000000..d18dd41a --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/subnet/SubnetIdTest.java @@ -0,0 +1,64 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.vtnrsc.subnet; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +import org.junit.Test; +import org.onosproject.vtnrsc.SubnetId; + +import com.google.common.testing.EqualsTester; + +/** + * Unit tests for SubnetId class. + */ +public class SubnetIdTest { + + final SubnetId subnetId1 = SubnetId.subnetId("1"); + final SubnetId sameAsSubnetId1 = SubnetId.subnetId("1"); + final SubnetId subnetId2 = SubnetId.subnetId("2"); + + /** + * Checks that the SubnetId class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(SubnetId.class); + } + + /** + * Checks the operation of equals() methods. + */ + @Test + public void testEquals() { + new EqualsTester().addEqualityGroup(subnetId1, sameAsSubnetId1).addEqualityGroup(subnetId2) + .testEquals(); + } + + /** + * Checks the construction of a SubnetId object. + */ + @Test + public void testConstruction() { + final String subnetIdValue = "s"; + final SubnetId subnetId = SubnetId.subnetId(subnetIdValue); + assertThat(subnetId, is(notNullValue())); + assertThat(subnetId.subnetId(), is(subnetIdValue)); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/DefaultNeutronNetworkTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/DefaultNeutronNetworkTest.java new file mode 100644 index 00000000..742d5933 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/DefaultNeutronNetworkTest.java @@ -0,0 +1,83 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.vtnrsc.tenantnetwork; + +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +import org.junit.Test; +import org.onosproject.vtnrsc.DefaultTenantNetwork; +import org.onosproject.vtnrsc.PhysicalNetwork; +import org.onosproject.vtnrsc.SegmentationId; +import org.onosproject.vtnrsc.TenantId; +import org.onosproject.vtnrsc.TenantNetwork; +import org.onosproject.vtnrsc.TenantNetworkId; + +import com.google.common.testing.EqualsTester; + +/** + * Unit tests for DefaultNeutronNetwork class. + */ +public class DefaultNeutronNetworkTest { + + private String networkIdStr1 = "123"; + private String networkIdStr2 = "234"; + private String physicalNetworkStr = "1234"; + private String tenantIdStr = "345"; + private String segmentationIdStr = "1"; + private String name = "456"; + + /** + * Checks that the DefaultNeutronNetwork class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(DefaultTenantNetwork.class); + } + + /** + * Checks the operation of equals() methods. + */ + @Test + public void testEquality() { + TenantNetworkId networkid1 = TenantNetworkId.networkId(networkIdStr1); + TenantNetworkId networkid2 = TenantNetworkId.networkId(networkIdStr2); + PhysicalNetwork physicalNetwork = PhysicalNetwork + .physicalNetwork(physicalNetworkStr); + TenantId tenantId = TenantId.tenantId(tenantIdStr); + SegmentationId segmentationID = SegmentationId + .segmentationId(segmentationIdStr); + TenantNetwork p1 = new DefaultTenantNetwork(networkid1, name, false, + TenantNetwork.State.ACTIVE, + false, tenantId, false, + TenantNetwork.Type.LOCAL, + physicalNetwork, + segmentationID); + TenantNetwork p2 = new DefaultTenantNetwork(networkid1, name, false, + TenantNetwork.State.ACTIVE, + false, tenantId, false, + TenantNetwork.Type.LOCAL, + physicalNetwork, + segmentationID); + TenantNetwork p3 = new DefaultTenantNetwork(networkid2, name, false, + TenantNetwork.State.ACTIVE, + false, tenantId, false, + TenantNetwork.Type.LOCAL, + physicalNetwork, + segmentationID); + new EqualsTester().addEqualityGroup(p1, p2).addEqualityGroup(p3) + .testEquals(); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/PhysicalNetworkTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/PhysicalNetworkTest.java new file mode 100644 index 00000000..e101795e --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/PhysicalNetworkTest.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.vtnrsc.tenantnetwork; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +import org.junit.Test; +import org.onosproject.vtnrsc.PhysicalNetwork; + +import com.google.common.testing.EqualsTester; + +/** + * Unit tests for PhysicalNetwork class. + */ +public class PhysicalNetworkTest { + + final PhysicalNetwork physicalNetwork1 = PhysicalNetwork.physicalNetwork("1"); + final PhysicalNetwork sameAsPhysicalNetwork1 = PhysicalNetwork.physicalNetwork("1"); + final PhysicalNetwork physicalNetwork2 = PhysicalNetwork.physicalNetwork("2"); + + /** + * Checks that the PhysicalNetwork class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(PhysicalNetwork.class); + } + + /** + * Checks the operation of equals() methods. + */ + @Test + public void testEquals() { + new EqualsTester().addEqualityGroup(physicalNetwork1, sameAsPhysicalNetwork1) + .addEqualityGroup(physicalNetwork2).testEquals(); + } + + /** + * Checks the construction of a PhysicalNetwork object. + */ + @Test + public void testConstruction() { + final String physicalNetworkValue = "s"; + final PhysicalNetwork physicalNetwork = PhysicalNetwork + .physicalNetwork(physicalNetworkValue); + assertThat(physicalNetwork, is(notNullValue())); + assertThat(physicalNetwork.physicalNetwork(), is(physicalNetworkValue)); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/SegmentationIdTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/SegmentationIdTest.java new file mode 100644 index 00000000..dea7baf6 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/SegmentationIdTest.java @@ -0,0 +1,64 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.vtnrsc.tenantnetwork; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +import org.junit.Test; +import org.onosproject.vtnrsc.SegmentationId; + +import com.google.common.testing.EqualsTester; + +/** + * Unit tests for SegmentationId class. + */ +public class SegmentationIdTest { + + final SegmentationId segmentationID1 = SegmentationId.segmentationId("1"); + final SegmentationId sameAsSegmentationID1 = SegmentationId.segmentationId("1"); + final SegmentationId segmentationID2 = SegmentationId.segmentationId("2"); + + /** + * Checks that the SegmentationId class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(SegmentationId.class); + } + + /** + * Checks the operation of equals() methods. + */ + @Test + public void testEquals() { + new EqualsTester().addEqualityGroup(segmentationID1, sameAsSegmentationID1) + .addEqualityGroup(segmentationID2).testEquals(); + } + + /** + * Checks the construction of a segmentationId object. + */ + @Test + public void testConstruction() { + final String segmentationIdValue = "s"; + final SegmentationId segmentationId = SegmentationId.segmentationId(segmentationIdValue); + assertThat(segmentationId, is(notNullValue())); + assertThat(segmentationId.segmentationId(), is(segmentationIdValue)); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/TenantIdTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/TenantIdTest.java new file mode 100644 index 00000000..e9216383 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/TenantIdTest.java @@ -0,0 +1,64 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.vtnrsc.tenantnetwork; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +import org.junit.Test; +import org.onosproject.vtnrsc.TenantId; + +import com.google.common.testing.EqualsTester; + +/** + * Unit tests for TenantId class. + */ +public class TenantIdTest { + + final TenantId tenantId1 = TenantId.tenantId("1"); + final TenantId sameAsTenantId1 = TenantId.tenantId("1"); + final TenantId tenantId2 = TenantId.tenantId("2"); + + /** + * Checks that the TenantId class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(TenantId.class); + } + + /** + * Checks the operation of equals() methods. + */ + @Test + public void testEquals() { + new EqualsTester().addEqualityGroup(tenantId1, sameAsTenantId1).addEqualityGroup(tenantId2) + .testEquals(); + } + + /** + * Checks the construction of a TenantId object. + */ + @Test + public void testConstruction() { + final String tenantIdValue = "s"; + final TenantId tenantId = TenantId.tenantId(tenantIdValue); + assertThat(tenantId, is(notNullValue())); + assertThat(tenantId.tenantId(), is(tenantIdValue)); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/TenantNetworkIdTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/TenantNetworkIdTest.java new file mode 100644 index 00000000..8271b51c --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/TenantNetworkIdTest.java @@ -0,0 +1,64 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.vtnrsc.tenantnetwork; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +import org.junit.Test; +import org.onosproject.vtnrsc.TenantNetworkId; + +import com.google.common.testing.EqualsTester; + +/** + * Unit tests for TenantNetworkId class. + */ +public class TenantNetworkIdTest { + + final TenantNetworkId networkId1 = TenantNetworkId.networkId("1"); + final TenantNetworkId sameAsnetworkId1 = TenantNetworkId.networkId("1"); + final TenantNetworkId networkId2 = TenantNetworkId.networkId("2"); + + /** + * Checks that the TenantNetworkId class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(TenantNetworkId.class); + } + + /** + * Checks the operation of equals() methods. + */ + @Test + public void testEquals() { + new EqualsTester().addEqualityGroup(networkId1, sameAsnetworkId1) + .addEqualityGroup(networkId2).testEquals(); + } + + /** + * Checks the construction of a TenantNetworkId object. + */ + @Test + public void testConstruction() { + final String networkIdValue = "s"; + final TenantNetworkId networkId = TenantNetworkId.networkId(networkIdValue); + assertThat(networkId, is(notNullValue())); + assertThat(networkId.networkId(), is(networkIdValue)); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/AllowedAddressPairTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/AllowedAddressPairTest.java new file mode 100644 index 00000000..dabe5896 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/AllowedAddressPairTest.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.virtualport; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +import org.junit.Test; +import org.onlab.packet.IpAddress; +import org.onlab.packet.MacAddress; +import org.onosproject.vtnrsc.AllowedAddressPair; + +import com.google.common.testing.EqualsTester; + +/** + * Unit tests for AllowedAddressPair class. + */ +public class AllowedAddressPairTest { + + final IpAddress ip1 = IpAddress.valueOf("192.168.0.1"); + final IpAddress ip2 = IpAddress.valueOf("192.168.0.2"); + final MacAddress mac1 = MacAddress.valueOf("fa:16:3e:76:83:88"); + final MacAddress mac2 = MacAddress.valueOf("aa:16:3e:76:83:88"); + + /** + * Checks that the AllowedAddressPair class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(AllowedAddressPair.class); + } + + /** + * Checks the operation of equals(). + */ + @Test + public void testEquals() { + AllowedAddressPair p1 = AllowedAddressPair + .allowedAddressPair(ip1, mac1); + AllowedAddressPair p2 = AllowedAddressPair + .allowedAddressPair(ip1, mac1); + AllowedAddressPair p3 = AllowedAddressPair + .allowedAddressPair(ip2, mac2); + new EqualsTester().addEqualityGroup(p1, p2).addEqualityGroup(p3) + .testEquals(); + } + + /** + * Checks the construction of a AllowedAddressPair object. + */ + @Test + public void testConstruction() { + AllowedAddressPair allowedAddressPair = AllowedAddressPair + .allowedAddressPair(ip1, mac1); + assertThat(ip1, is(notNullValue())); + assertThat(ip1, is(allowedAddressPair.ip())); + assertThat(mac1, is(notNullValue())); + assertThat(mac1, is(allowedAddressPair.mac())); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/DefaultVirtualPortTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/DefaultVirtualPortTest.java new file mode 100644 index 00000000..8a0c8004 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/DefaultVirtualPortTest.java @@ -0,0 +1,142 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.vtnrsc.virtualport; + +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +import java.util.Map; +import java.util.Set; + +import org.junit.Test; +import org.onlab.packet.IpAddress; +import org.onlab.packet.MacAddress; +import org.onosproject.net.DeviceId; +import org.onosproject.vtnrsc.AllowedAddressPair; +import org.onosproject.vtnrsc.BindingHostId; +import org.onosproject.vtnrsc.DefaultVirtualPort; +import org.onosproject.vtnrsc.FixedIp; +import org.onosproject.vtnrsc.SecurityGroup; +import org.onosproject.vtnrsc.SubnetId; +import org.onosproject.vtnrsc.TenantId; +import org.onosproject.vtnrsc.TenantNetworkId; +import org.onosproject.vtnrsc.VirtualPort; +import org.onosproject.vtnrsc.VirtualPortId; + +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.google.common.testing.EqualsTester; + +/** + * Unit tests for DefaultVirtualPort class. + */ +public class DefaultVirtualPortTest { + + private Set fixedIps; + private Map propertyMap; + private Set allowedAddressPairs; + private Set securityGroups; + private VirtualPortId id1; + private VirtualPortId id2; + private String macAddressStr = "fa:12:3e:56:ee:a2"; + private String ipAddress = "10.1.1.1"; + private String deviceStr = "of:000000000000001"; + private String tenantIdStr = "123"; + private String portId1 = "1241"; + private String portId2 = "1242"; + private String tenantNetworkId = "1234567"; + private String subnet = "1212"; + private String hostIdStr = "fa:e2:3e:56:ee:a2"; + + private void initVirtualPortId() { + id1 = VirtualPortId.portId(portId1); + id2 = VirtualPortId.portId(portId2); + } + + private void initFixedIpSet() { + FixedIp fixedIp = FixedIp.fixedIp(SubnetId.subnetId(subnet), + IpAddress.valueOf(ipAddress)); + fixedIps = Sets.newHashSet(); + fixedIps.add(fixedIp); + } + + private void initPropertyMap() { + String deviceOwner = "james"; + propertyMap = Maps.newHashMap(); + propertyMap.putIfAbsent("deviceOwner", deviceOwner); + } + + private void initAddressPairSet() { + allowedAddressPairs = Sets.newHashSet(); + AllowedAddressPair allowedAddressPair = AllowedAddressPair + .allowedAddressPair(IpAddress.valueOf(ipAddress), + MacAddress.valueOf(macAddressStr)); + allowedAddressPairs.add(allowedAddressPair); + } + + private void initSecurityGroupSet() { + securityGroups = Sets.newHashSet(); + } + + /** + * Checks that the DefaultVirtualPort class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(SecurityGroup.class); + } + + /** + * Checks the operation of equals(). + */ + @Test + public void testEquals() { + initVirtualPortId(); + initFixedIpSet(); + initPropertyMap(); + initAddressPairSet(); + initSecurityGroupSet(); + TenantNetworkId networkId = TenantNetworkId.networkId(tenantNetworkId); + MacAddress macAddress = MacAddress.valueOf(macAddressStr); + TenantId tenantId = TenantId.tenantId(tenantIdStr); + DeviceId deviceId = DeviceId.deviceId(deviceStr); + BindingHostId bindingHostId = BindingHostId.bindingHostId(hostIdStr); + + VirtualPort d1 = new DefaultVirtualPort(id1, networkId, true, + propertyMap, + VirtualPort.State.ACTIVE, + macAddress, tenantId, deviceId, + fixedIps, bindingHostId, + allowedAddressPairs, + securityGroups); + VirtualPort d2 = new DefaultVirtualPort(id1, networkId, true, + propertyMap, + VirtualPort.State.ACTIVE, + macAddress, tenantId, deviceId, + fixedIps, bindingHostId, + allowedAddressPairs, + securityGroups); + VirtualPort d3 = new DefaultVirtualPort(id2, networkId, true, + propertyMap, + VirtualPort.State.ACTIVE, + macAddress, tenantId, deviceId, + fixedIps, bindingHostId, + allowedAddressPairs, + securityGroups); + new EqualsTester().addEqualityGroup(d1, d2).addEqualityGroup(d3) + .testEquals(); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/FixedIpTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/FixedIpTest.java new file mode 100644 index 00000000..1e33da09 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/FixedIpTest.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.virtualport; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +import org.junit.Test; +import org.onlab.packet.IpAddress; +import org.onosproject.vtnrsc.FixedIp; +import org.onosproject.vtnrsc.SubnetId; + +import com.google.common.testing.EqualsTester; + +/** + * Unit tests for FixedIp class. + */ +public class FixedIpTest { + + final SubnetId subnetId1 = SubnetId.subnetId("lef11-95w-4er-9c9c"); + final SubnetId subnetId2 = SubnetId.subnetId("lefaa-95w-4er-9c9c"); + final IpAddress ip1 = IpAddress.valueOf("192.168.0.1"); + final IpAddress ip2 = IpAddress.valueOf("192.168.1.1"); + + /** + * Checks that the FixedIp class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(FixedIp.class); + } + + /** + * Checks the operation of equals(). + */ + @Test + public void testEquals() { + FixedIp fixedIp1 = FixedIp.fixedIp(subnetId1, ip1); + FixedIp fixedIp2 = FixedIp.fixedIp(subnetId1, ip1); + FixedIp fixedIp3 = FixedIp.fixedIp(subnetId2, ip2); + new EqualsTester().addEqualityGroup(fixedIp1, fixedIp2) + .addEqualityGroup(fixedIp3).testEquals(); + } + + /** + * Checks the construction of a FixedIp object. + */ + @Test + public void testConstruction() { + FixedIp fixedIp = FixedIp.fixedIp(subnetId1, ip1); + assertThat(ip1, is(notNullValue())); + assertThat(ip1, is(fixedIp.ip())); + assertThat(subnetId1, is(notNullValue())); + assertThat(subnetId1, is(fixedIp.subnetId())); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/SecurityGroupTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/SecurityGroupTest.java new file mode 100644 index 00000000..8c04e499 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/SecurityGroupTest.java @@ -0,0 +1,66 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.vtnrsc.virtualport; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +import org.junit.Test; +import org.onosproject.vtnrsc.SecurityGroup; + +import com.google.common.testing.EqualsTester; + +/** + * Unit tests for SecurityGroup class. + */ +public class SecurityGroupTest { + + final SecurityGroup securityGroup1 = SecurityGroup.securityGroup("1"); + final SecurityGroup sameAssecurityGroup = SecurityGroup.securityGroup("1"); + final SecurityGroup securityGroup2 = SecurityGroup.securityGroup("2"); + + /** + * Checks that the SecurityGroup class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(SecurityGroup.class); + } + + /** + * Checks the operation of equals(). + */ + @Test + public void testEquals() { + new EqualsTester().addEqualityGroup(securityGroup1, sameAssecurityGroup) + .addEqualityGroup(securityGroup2).testEquals(); + } + + /** + * Checks the construction of a SecurityGroup object. + */ + @Test + public void testConstruction() { + final String securityGroupValue = "1"; + final SecurityGroup securityGroup = SecurityGroup.securityGroup(securityGroupValue); + assertThat(securityGroup, is(notNullValue())); + assertThat(securityGroup.securityGroup(), is(securityGroupValue)); + + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/VirtualPortIdTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/VirtualPortIdTest.java new file mode 100644 index 00000000..2d63e91c --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/VirtualPortIdTest.java @@ -0,0 +1,66 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.vtnrsc.virtualport; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +import org.junit.Test; +import org.onosproject.vtnrsc.VirtualPortId; + +import com.google.common.testing.EqualsTester; + +/** + * Unit tests for VirtualPortId class. + */ +public class VirtualPortIdTest { + + final VirtualPortId virtualPortId1 = VirtualPortId.portId("1"); + final VirtualPortId sameAsVirtualPortId1 = VirtualPortId.portId("1"); + final VirtualPortId virtualPortId2 = VirtualPortId.portId("2"); + + /** + * Checks that the VirtualPortId class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(VirtualPortId.class); + } + + /** + * Checks the operation of equals(). + */ + @Test + public void testEquals() { + new EqualsTester().addEqualityGroup(virtualPortId1, sameAsVirtualPortId1) + .addEqualityGroup(virtualPortId2).testEquals(); + } + + /** + * Checks the construction of a VirtualPortId object. + */ + @Test + public void testConstruction() { + final String vPortIdValue = "aaa"; + final VirtualPortId virtualPortId = VirtualPortId.portId(vPortIdValue); + assertThat(virtualPortId, is(notNullValue())); + assertThat(virtualPortId.portId(), is(vPortIdValue)); + + } +} diff --git a/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/FlowClassifierWebResource.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/FlowClassifierWebResource.java new file mode 100644 index 00000000..1450e4ef --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/FlowClassifierWebResource.java @@ -0,0 +1,192 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.vtnweb.resources; + +import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR; +import static org.onlab.util.Tools.nullIsNotFound; +import static javax.ws.rs.core.Response.Status.NOT_FOUND; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.UUID; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.onosproject.vtnrsc.FlowClassifier; +import org.onosproject.vtnrsc.FlowClassifierId; +import org.onosproject.rest.AbstractWebResource; +import org.onosproject.vtnrsc.flowClassifier.FlowClassifierService; +import org.onosproject.vtnrsc.web.FlowClassifierCodec; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * Query and program flow classifier. + */ +@Path("flow_classifiers") +public class FlowClassifierWebResource extends AbstractWebResource { + + final FlowClassifierService service = get(FlowClassifierService.class); + final ObjectNode root = mapper().createObjectNode(); + public static final String FLOW_CLASSIFIER_NOT_FOUND = "Flow classifier not found"; + + /** + * Get all flow classifiers created. Returns list of all flow classifiers + * created. + * + * @return 200 OK + */ + @GET + @Produces(MediaType.APPLICATION_JSON) + public Response getFlowClassifiers() { + Iterable flowClassifiers = service.getFlowClassifiers(); + ObjectNode result = new ObjectMapper().createObjectNode(); + result.set("flow_classifiers", new FlowClassifierCodec().encode(flowClassifiers, this)); + return ok(result.toString()).build(); + } + + /** + * Get details of a flow classifier. Returns details of a specified flow + * classifier id. + * + * @param id flow classifier id + * @return 200 OK + */ + @GET + @Path("{flow_id}") + @Produces(MediaType.APPLICATION_JSON) + public Response getFlowClassifier(@PathParam("flow_id") String id) { + + if (!service.hasFlowClassifier(FlowClassifierId.flowClassifierId(UUID.fromString(id)))) { + return Response.status(NOT_FOUND).entity(FLOW_CLASSIFIER_NOT_FOUND).build(); + } + FlowClassifier flowClassifier = nullIsNotFound( + service.getFlowClassifier(FlowClassifierId.flowClassifierId(UUID.fromString(id))), + FLOW_CLASSIFIER_NOT_FOUND); + + ObjectNode result = new ObjectMapper().createObjectNode(); + result.set("flow_classifier", new FlowClassifierCodec().encode(flowClassifier, this)); + return ok(result.toString()).build(); + } + + /** + * Creates and stores a new flow classifier. + * + * @param flowClassifierId flow classifier identifier + * @param stream flow classifier from JSON + * @return status of the request - CREATED if the JSON is correct, + * BAD_REQUEST if the JSON is invalid + */ + @POST + @Path("{flow_id}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response createFlowClassifier(@PathParam("flow_id") String flowClassifierId, InputStream stream) { + URI location; + try { + ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream); + + FlowClassifier flowClassifier = codec(FlowClassifier.class).decode(jsonTree, this); + service.createFlowClassifier(flowClassifier); + location = new URI(flowClassifierId); + } catch (IOException | URISyntaxException ex) { + throw new IllegalArgumentException(ex); + } + return Response.created(location).build(); + } + + /** + * Creates and stores a new flow classifier. + * + * @param stream flow classifier from JSON + * @return status of the request - CREATED if the JSON is correct, + * BAD_REQUEST if the JSON is invalid + */ + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response createFlowClassifier(InputStream stream) { + URI location; + try { + ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream); + + FlowClassifier flowClassifier = codec(FlowClassifier.class).decode(jsonTree, this); + service.createFlowClassifier(flowClassifier); + location = new URI(flowClassifier.flowClassifierId().toString()); + } catch (IOException | URISyntaxException ex) { + throw new IllegalArgumentException(ex); + } + return Response.created(location).build(); + } + + /** + * Update details of a flow classifier. Update details of a specified flow + * classifier id. + * + * @param id flow classifier id + * @param stream InputStream + * @return 200 OK + */ + @PUT + @Path("{flow_id}") + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + public Response updateFlowClassifier(@PathParam("flow_id") String id, final InputStream stream) { + try { + ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream); + FlowClassifier flowClassifier = codec(FlowClassifier.class).decode(jsonTree, this); + Boolean result = nullIsNotFound(service.updateFlowClassifier(flowClassifier), FLOW_CLASSIFIER_NOT_FOUND); + if (!result) { + return Response.status(204).entity(FLOW_CLASSIFIER_NOT_FOUND).build(); + } + return Response.status(203).entity(result.toString()).build(); + } catch (Exception e) { + return Response.status(INTERNAL_SERVER_ERROR).entity(e.toString()).build(); + } + } + + /** + * Delete details of a flow classifier. Delete details of a specified flow + * classifier id. + * + * @param id flow classifier id + * @return 200 OK + * @throws IOException when input doesn't match. + */ + @Path("{flow_id}") + @DELETE + public Response deleteFlowClassifier(@PathParam("flow_id") String id) throws IOException { + try { + FlowClassifierId flowClassifierId = FlowClassifierId.flowClassifierId(UUID.fromString(id)); + service.removeFlowClassifier(flowClassifierId); + return Response.status(201).entity("SUCCESS").build(); + } catch (Exception e) { + return Response.status(INTERNAL_SERVER_ERROR).entity(e.toString()).build(); + } + } +} 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 index 251dcffc..0cc59a4e 100644 --- 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 @@ -56,7 +56,7 @@ import org.onosproject.vtnrsc.TenantId; import org.onosproject.vtnrsc.TenantNetworkId; import org.onosproject.vtnrsc.Subnet.Mode; import org.onosproject.vtnrsc.subnet.SubnetService; -import org.onosproject.vtnrsc.web.SubnetCodec; +import org.onosproject.vtnweb.web.SubnetCodec; import org.slf4j.Logger; import org.slf4j.LoggerFactory; 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 index 0b877822..2dd931ea 100644 --- 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 @@ -51,7 +51,7 @@ import org.onosproject.vtnrsc.TenantNetworkId; import org.onosproject.vtnrsc.TenantNetwork.State; import org.onosproject.vtnrsc.TenantNetwork.Type; import org.onosproject.vtnrsc.tenantnetwork.TenantNetworkService; -import org.onosproject.vtnrsc.web.TenantNetworkCodec; +import org.onosproject.vtnweb.web.TenantNetworkCodec; import org.slf4j.Logger; import org.slf4j.LoggerFactory; 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 index 03d3a653..e47a57df 100644 --- 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 @@ -58,7 +58,7 @@ import org.onosproject.vtnrsc.VirtualPort; import org.onosproject.vtnrsc.VirtualPort.State; import org.onosproject.vtnrsc.VirtualPortId; import org.onosproject.vtnrsc.virtualport.VirtualPortService; -import org.onosproject.vtnrsc.web.VirtualPortCodec; +import org.onosproject.vtnweb.web.VirtualPortCodec; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/AllocationPoolsCodec.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/AllocationPoolsCodec.java new file mode 100644 index 00000000..4b6b662f --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/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.vtnweb.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 { + + @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/vtnweb/src/main/java/org/onosproject/vtnweb/web/AllowedAddressPairCodec.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/AllowedAddressPairCodec.java new file mode 100644 index 00000000..8ffc4e91 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/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.vtnweb.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 { + + @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/vtnweb/src/main/java/org/onosproject/vtnweb/web/FixedIpCodec.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/FixedIpCodec.java new file mode 100644 index 00000000..559de685 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/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.vtnweb.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 { + + @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/vtnweb/src/main/java/org/onosproject/vtnweb/web/HostRoutesCodec.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/HostRoutesCodec.java new file mode 100644 index 00000000..815a0d02 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/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.vtnweb.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 { + + @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/vtnweb/src/main/java/org/onosproject/vtnweb/web/PortChainCodec.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/PortChainCodec.java new file mode 100644 index 00000000..28da5cd1 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/PortChainCodec.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.vtnweb.web; + + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onlab.util.Tools.nullIsIllegal; + +import java.util.List; +import java.util.UUID; + +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; +import org.onosproject.vtnrsc.TenantId; +import org.onosproject.vtnrsc.DefaultPortChain; +import org.onosproject.vtnrsc.FlowClassifierId; +import org.onosproject.vtnrsc.PortChain; +import org.onosproject.vtnrsc.PortChainId; +import org.onosproject.vtnrsc.PortPairGroupId; + +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.collect.Lists; + +/** + * Port chain JSON codec. + */ +public final class PortChainCodec extends JsonCodec { + + private static final String ID = "id"; + private static final String TENANT_ID = "tenant_id"; + private static final String NAME = "name"; + private static final String DESCRIPTION = "description"; + private static final String PORT_PAIR_GROUPS = "port_pair_groups"; + private static final String FLOW_CLASSIFIERS = "flow_classifiers"; + private static final String MISSING_MEMBER_MESSAGE = + " member is required in PortChain"; + + @Override + public PortChain decode(ObjectNode json, CodecContext context) { + if (json == null || !json.isObject()) { + return null; + } + + PortChain.Builder resultBuilder = new DefaultPortChain.Builder(); + + String id = nullIsIllegal(json.get(ID), + ID + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setId(PortChainId.portChainId(id)); + + String tenantId = nullIsIllegal(json.get(TENANT_ID), + TENANT_ID + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setTenantId(TenantId.tenantId(tenantId)); + + String name = nullIsIllegal(json.get(NAME), + NAME + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setName(name); + + String description = nullIsIllegal(json.get(DESCRIPTION), + DESCRIPTION + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setDescription(description); + + ArrayNode arrayNode = (ArrayNode) json.path(PORT_PAIR_GROUPS); + if (arrayNode != null) { + List list = Lists.newArrayList(); + arrayNode.forEach(i -> list.add(PortPairGroupId.portPairGroupId(i.asText()))); + resultBuilder.setPortPairGroups(list); + } + + arrayNode = (ArrayNode) json.path(FLOW_CLASSIFIERS); + if (arrayNode != null) { + List list = Lists.newArrayList(); + arrayNode.forEach(i -> list.add(FlowClassifierId.flowClassifierId(UUID.fromString(i.asText())))); + resultBuilder.setFlowClassifiers(list); + } + + return resultBuilder.build(); + } + + @Override + public ObjectNode encode(PortChain portChain, CodecContext context) { + checkNotNull(portChain, "port pair cannot be null"); + ObjectNode result = context.mapper().createObjectNode() + .put(ID, portChain.portChainId().toString()) + .put(TENANT_ID, portChain.tenantId().toString()) + .put(NAME, portChain.name()) + .put(DESCRIPTION, portChain.description()) + .put(PORT_PAIR_GROUPS, portChain.portPairGroups().toString()) + .put(FLOW_CLASSIFIERS, portChain.flowClassifiers().toString()); + return result; + } +} diff --git a/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/SecurityGroupCodec.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/SecurityGroupCodec.java new file mode 100644 index 00000000..18ed61ba --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/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.vtnweb.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 { + + @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/vtnweb/src/main/java/org/onosproject/vtnweb/web/SubnetCodec.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/SubnetCodec.java new file mode 100644 index 00000000..e3d92fea --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/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.vtnweb.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 { + @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/vtnweb/src/main/java/org/onosproject/vtnweb/web/TenantNetworkCodec.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/TenantNetworkCodec.java new file mode 100644 index 00000000..8adba034 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/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.vtnweb.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 { + + @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/vtnweb/src/main/java/org/onosproject/vtnweb/web/VirtualPortCodec.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/VirtualPortCodec.java new file mode 100644 index 00000000..5cea5327 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/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.vtnweb.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 { + @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/vtnweb/src/main/java/org/onosproject/vtnweb/web/package-info.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/package-info.java new file mode 100644 index 00000000..3a609435 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/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.vtnweb.web; diff --git a/framework/src/onos/bgp/api/src/main/java/org/onosproject/bgp/controller/BgpPeerManager.java b/framework/src/onos/bgp/api/src/main/java/org/onosproject/bgp/controller/BgpPeerManager.java new file mode 100755 index 00000000..d2230967 --- /dev/null +++ b/framework/src/onos/bgp/api/src/main/java/org/onosproject/bgp/controller/BgpPeerManager.java @@ -0,0 +1,54 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.onosproject.bgp.controller; + +/** + * Responsible for keeping track of the current set BGPLS peers connected to the system. + * + */ +public interface BgpPeerManager { + + /** + * Add connected peer. + * + * @param bgpId BGP ID to add + * @param bgpPeer BGp peer instance + * + * @return false if peer already exist, otherwise true + */ + public boolean addConnectedPeer(BGPId bgpId, BGPPeer bgpPeer); + + /** + * Validate wheather peer is connected. + * + * @param bgpId BGP ID to validate + * + * @return true if peer exist, otherwise false + */ + public boolean isPeerConnected(BGPId bgpId); + + /** + * Remove connected peer. + * + * @param bgpId BGP ID + */ + public void removeConnectedPeer(BGPId bgpId); + + /** + * Gets connected peer. + * + * @param bgpId BGP ID + * @return BGPPeer the connected peer, otherwise null + */ + public BGPPeer getPeer(BGPId bgpId); +} diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPFactories.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPFactories.java new file mode 100755 index 00000000..71b9cbff --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPFactories.java @@ -0,0 +1,82 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.protocol.ver4.BGPFactoryVer4; +import org.onosproject.bgpio.types.BGPHeader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Abstraction to provide the version for BGP. + */ +public final class BGPFactories { + + protected static final Logger log = LoggerFactory.getLogger(BGPFactories.class); + + private static final GenericReader GENERIC_READER = new GenericReader(); + + private BGPFactories() { + } + + /** + * Returns the instance of BGP Version. + * + * @param version BGP version + * @return BGP version + */ + public static BGPFactory getFactory(BGPVersion version) { + switch (version) { + case BGP_4: + return BGPFactoryVer4.INSTANCE; + default: + throw new IllegalArgumentException("[BGPFactory:]Unknown version: " + version); + } + } + + /** + * Reader class for reading BGP messages from channel buffer. + * + */ + private static class GenericReader implements BGPMessageReader { + + @Override + public BGPMessage readFrom(ChannelBuffer bb, BGPHeader bgpHeader) + throws BGPParseException { + BGPFactory factory; + + if (!bb.readable()) { + log.error("Empty message received"); + throw new BGPParseException("Empty message received"); + } + // TODO: Currently only BGP version 4 is supported + factory = org.onosproject.bgpio.protocol.ver4.BGPFactoryVer4.INSTANCE; + return factory.getReader().readFrom(bb, bgpHeader); + } + } + + /** + * Returns BGP messsage generic reader. + * + * @return bgp message generic reader + */ + public static BGPMessageReader getGenericReader() { + return GENERIC_READER; + } +} diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPFactory.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPFactory.java new file mode 100755 index 00000000..cf6bf008 --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPFactory.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.bgpio.protocol; + +/** + * Abstraction of an message factory providing builder functions to BGP messages + * and objects. + * + */ +public interface BGPFactory { + + /** + * Gets the builder object for a open message. + * + * @return builder object for open message + */ + BGPOpenMsg.Builder openMessageBuilder(); + + /** + * Gets the builder object for a keepalive message. + * + * @return builder object for keepalive message + */ + BGPKeepaliveMsg.Builder keepaliveMessageBuilder(); + + /** + * Gets the builder object for a notification message. + * + * @return builder object for notification message. + */ + BGPNotificationMsg.Builder notificationMessageBuilder(); + + /** + * Gets the BGP message reader. + * + * @return BGP message reader + */ + BGPMessageReader getReader(); + + /** + * Returns BGP version. + * + * @return BGP version + */ + BGPVersion getVersion(); +} diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPNotificationMsg.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPNotificationMsg.java index 56540dd3..a1d9d578 100644 --- a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPNotificationMsg.java +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPNotificationMsg.java @@ -16,63 +16,53 @@ package org.onosproject.bgpio.protocol; import org.onosproject.bgpio.exceptions.BGPParseException; -import org.onosproject.bgpio.types.BGPHeader; /** - * Abstraction of an entity providing BGP Notification Message. + * Abstraction of an entity providing BGP notification message. */ public interface BGPNotificationMsg extends BGPMessage { /** - * Returns errorCode in Notification message. + * Returns errorCode in notification message. * - * @return errorCode in Notification message + * @return errorCode in notification message */ byte getErrorCode(); /** - * Returns error SubCode in Notification message. + * Returns error subCode in notification message. * - * @return error SubCode in Notification message + * @return error subCode in notification message */ byte getErrorSubCode(); /** - * Returns error data in Notification message. + * Returns error data in notification message. * - * @return error data in Notification message + * @return error data in notification message */ byte[] getData(); /** - * Builder interface with get and set functions to build Notification - * message. + * Builder interface with get and set functions to build notification message. */ public interface Builder extends BGPMessage.Builder { @Override BGPNotificationMsg build() throws BGPParseException; - /** - * Sets notification message header and returns its builder. - * - * @param header of notification message - * @return Builder by setting notification message header - */ - Builder setNotificationMsgHeader(BGPHeader header); - /** * Sets errorCode in notification message and return its builder. * * @param errorCode in notification message - * @return builder by setting ErrorCode in notification message + * @return builder by setting errorCode in notification message */ Builder setErrorCode(byte errorCode); /** - * Sets error SubCode in notification message and return its builder. + * Sets error subCode in notification message and return its builder. * - * @param errorSubCode in notification Message - * @return builder by setting ErrorSubCode in notification Message + * @param errorSubCode in notification message + * @return builder by setting error subCode in notification message */ Builder setErrorSubCode(byte errorSubCode); diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPFactoryVer4.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPFactoryVer4.java new file mode 100755 index 00000000..32af3854 --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPFactoryVer4.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.ver4; + +import org.onosproject.bgpio.protocol.BGPFactory; +import org.onosproject.bgpio.protocol.BGPKeepaliveMsg; +import org.onosproject.bgpio.protocol.BGPMessage; +import org.onosproject.bgpio.protocol.BGPMessageReader; +import org.onosproject.bgpio.protocol.BGPNotificationMsg; +import org.onosproject.bgpio.protocol.BGPOpenMsg; +import org.onosproject.bgpio.protocol.BGPVersion; + +/** + * Provides BGP Factory and returns builder classes for all objects and messages. + */ +public class BGPFactoryVer4 implements BGPFactory { + + public static final BGPFactoryVer4 INSTANCE = new BGPFactoryVer4(); + + @Override + public BGPOpenMsg.Builder openMessageBuilder() { + return new BGPOpenMsgVer4.Builder(); + } + + @Override + public BGPKeepaliveMsg.Builder keepaliveMessageBuilder() { + return new BGPKeepaliveMsgVer4.Builder(); + } + + @Override + public BGPNotificationMsg.Builder notificationMessageBuilder() { + return new BGPNotificationMsgVer4.Builder(); + } + + @Override + public BGPMessageReader getReader() { + return BGPMessageVer4.READER; + } + + @Override + public BGPVersion getVersion() { + return BGPVersion.BGP_4; + } +} \ No newline at end of file diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPMessageVer4.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPMessageVer4.java new file mode 100755 index 00000000..d45e3de1 --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPMessageVer4.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.bgpio.protocol.ver4; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.onosproject.bgpio.exceptions.BGPParseException; +import org.onosproject.bgpio.protocol.BGPFactories; +import org.onosproject.bgpio.protocol.BGPMessage; +import org.onosproject.bgpio.protocol.BGPMessageReader; +import org.onosproject.bgpio.types.BGPErrorType; +import org.onosproject.bgpio.types.BGPHeader; +import org.onosproject.bgpio.util.Validation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Provides BGP messages. + */ +public abstract class BGPMessageVer4 { + + protected static final Logger log = LoggerFactory.getLogger(BGPFactories.class); + + static final byte OPEN_MSG_TYPE = 0x1; + static final byte KEEPALIVE_MSG_TYPE = 0x4; + static final byte UPDATE_MSG_TYPE = 0x2; + static final byte NOTIFICATION_MSG_TYPE = 0x3; + static final int MINIMUM_COMMON_HEADER_LENGTH = 19; + static final int HEADER_AND_MSG_LEN = 18; + static final int MAXIMUM_PACKET_LENGTH = 4096; + + public static final BGPMessageVer4.Reader READER = new Reader(); + + /** + * Reader class for reading BGP messages from channel buffer. + * + */ + static class Reader implements BGPMessageReader { + @Override + public BGPMessage readFrom(ChannelBuffer cb, BGPHeader bgpHeader) + throws BGPParseException { + + if (cb.readableBytes() < MINIMUM_COMMON_HEADER_LENGTH) { + log.error("Packet should have minimum length."); + Validation.validateLen(BGPErrorType.MESSAGE_HEADER_ERROR, BGPErrorType.BAD_MESSAGE_LENGTH, + cb.readableBytes()); + } + if (cb.readableBytes() > MAXIMUM_PACKET_LENGTH) { + log.error("Packet length should not exceed {}.", MAXIMUM_PACKET_LENGTH); + Validation.validateLen(BGPErrorType.MESSAGE_HEADER_ERROR, BGPErrorType.BAD_MESSAGE_LENGTH, + cb.readableBytes()); + } + try { + // fixed value property version == 4 + byte[] marker = new byte[BGPHeader.MARKER_LENGTH]; + cb.readBytes(marker, 0, BGPHeader.MARKER_LENGTH); + bgpHeader.setMarker(marker); + for (int i = 0; i < BGPHeader.MARKER_LENGTH; i++) { + if (marker[i] != (byte) 0xff) { + throw new BGPParseException(BGPErrorType.MESSAGE_HEADER_ERROR, + BGPErrorType.CONNECTION_NOT_SYNCHRONIZED, null); + } + } + short length = cb.readShort(); + if (length != (cb.readableBytes() + HEADER_AND_MSG_LEN)) { + Validation.validateLen(BGPErrorType.MESSAGE_HEADER_ERROR, BGPErrorType.BAD_MESSAGE_LENGTH, length); + } + bgpHeader.setLength(length); + byte type = cb.readByte(); + bgpHeader.setType(type); + log.debug("Reading update message of type " + type); + + int len = length - MINIMUM_COMMON_HEADER_LENGTH; + switch (type) { + case OPEN_MSG_TYPE: + log.debug("OPEN MESSAGE is received"); + return BGPOpenMsgVer4.READER.readFrom(cb.readBytes(len), bgpHeader); + case KEEPALIVE_MSG_TYPE: + log.debug("KEEPALIVE MESSAGE is received"); + return BGPKeepaliveMsgVer4.READER.readFrom(cb.readBytes(len), bgpHeader); + case UPDATE_MSG_TYPE: + log.debug("UPDATE MESSAGE is received"); + // TODO: Update message version 4 + case NOTIFICATION_MSG_TYPE: + log.debug("NOTIFICATION MESSAGE is received"); + return BGPNotificationMsgVer4.READER.readFrom(cb.readBytes(len), bgpHeader); + default: + Validation.validateType(BGPErrorType.MESSAGE_HEADER_ERROR, BGPErrorType.BAD_MESSAGE_TYPE, type); + return null; + } + } catch (IndexOutOfBoundsException e) { + throw new BGPParseException(BGPErrorType.MESSAGE_HEADER_ERROR, BGPErrorType.BAD_MESSAGE_LENGTH, null); + } + } + } +} \ No newline at end of file diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPNotificationMsgVer4.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPNotificationMsgVer4.java index 064deada..3bddd375 100644 --- a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPNotificationMsgVer4.java +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPNotificationMsgVer4.java @@ -44,7 +44,7 @@ class BGPNotificationMsgVer4 implements BGPNotificationMsg { REFERENCE : RFC 4271 */ - protected static final Logger log = LoggerFactory.getLogger(BGPNotificationMsgVer4.class); + private static final Logger log = LoggerFactory.getLogger(BGPNotificationMsgVer4.class); static final byte PACKET_VERSION = 4; //BGPHeader(19) + Error code(1) + Error subcode(1) @@ -52,8 +52,10 @@ class BGPNotificationMsgVer4 implements BGPNotificationMsg { static final int PACKET_MINIMUM_LENGTH = 2; static final BGPType MSG_TYPE = BGPType.NOTIFICATION; static final byte DEFAULT_ERRORSUBCODE = 0; - static final byte[] MARKER = {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01}; + static final byte[] MARKER = {(byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xff }; static final byte MESSAGE_TYPE = 3; static final BGPHeader DEFAULT_MESSAGE_HEADER = new BGPHeader(MARKER, BGPHeader.DEFAULT_HEADER_LENGTH, MESSAGE_TYPE); @@ -65,7 +67,7 @@ class BGPNotificationMsgVer4 implements BGPNotificationMsg { public static final BGPNotificationMsgVer4.Reader READER = new Reader(); /** - * Resets fields. + * Initialize fields. */ public BGPNotificationMsgVer4() { this.bgpHeader = null; @@ -153,13 +155,6 @@ class BGPNotificationMsgVer4 implements BGPNotificationMsg { return this; } - @Override - public Builder setNotificationMsgHeader(BGPHeader header) { - this.bgpHeader = header; - this.isBGPHeaderSet = true; - return this; - } - @Override public Builder setHeader(BGPHeader bgpMsgHeader) { this.bgpHeader = bgpMsgHeader; diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BgpPathAttributes.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BgpPathAttributes.java new file mode 100644 index 00000000..08fea4c6 --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BgpPathAttributes.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.bgpio.protocol.ver4; + +import java.util.LinkedList; +import java.util.List; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.onosproject.bgpio.exceptions.BGPParseException; +import org.onosproject.bgpio.types.As4Path; +import org.onosproject.bgpio.types.AsPath; +import org.onosproject.bgpio.types.BGPErrorType; +import org.onosproject.bgpio.types.BGPValueType; +import org.onosproject.bgpio.types.LocalPref; +import org.onosproject.bgpio.types.Med; +import org.onosproject.bgpio.types.NextHop; +import org.onosproject.bgpio.types.Origin; +import org.onosproject.bgpio.util.UnSupportedAttribute; +import org.onosproject.bgpio.util.Validation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.MoreObjects; + +/** + * Provides Implementation of BGP Path Attribute. + */ +public class BgpPathAttributes { + + /* Path attribute: + + + 0 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Attr. Flags |Attr. Type Code| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + REFERENCE : RFC 4271 + */ + protected static final Logger log = LoggerFactory.getLogger(BgpPathAttributes.class); + + public static final int LINK_STATE_ATTRIBUTE_TYPE = 50; + public static final int MPREACHNLRI_TYPE = 14; + public static final int MPUNREACHNLRI_TYPE = 15; + + private final List pathAttribute; + + /** + * Initialize parameter. + */ + public BgpPathAttributes() { + this.pathAttribute = null; + } + + /** + * Constructor to initialize parameters for BGP path attributes. + * + * @param pathAttribute list of path attributes + */ + public BgpPathAttributes(List pathAttribute) { + this.pathAttribute = pathAttribute; + } + + /** + * Returns list of path attributes. + * + * @return list of path attributes + */ + public List pathAttributes() { + return this.pathAttribute; + } + + /** + * Reads from channelBuffer and parses BGP path attributes. + * + * @param cb channelBuffer + * @return object of BgpPathAttributes + * @throws BGPParseException while parsing BGP path attributes + */ + public static BgpPathAttributes read(ChannelBuffer cb) + throws BGPParseException { + + BGPValueType pathAttribute = null; + List pathAttributeList = new LinkedList<>(); + boolean isOrigin = false; + boolean isAsPath = false; + boolean isNextHop = false; + boolean isMpReach = false; + boolean isMpUnReach = false; + while (cb.readableBytes() > 0) { + cb.markReaderIndex(); + byte flags = cb.readByte(); + byte typeCode = cb.readByte(); + cb.resetReaderIndex(); + switch (typeCode) { + case Origin.ORIGIN_TYPE: + pathAttribute = Origin.read(cb); + isOrigin = ((Origin) pathAttribute).isOriginSet(); + break; + case AsPath.ASPATH_TYPE: + pathAttribute = AsPath.read(cb); + isAsPath = ((AsPath) pathAttribute).isaspathSet(); + break; + case As4Path.AS4PATH_TYPE: + pathAttribute = As4Path.read(cb); + break; + case NextHop.NEXTHOP_TYPE: + pathAttribute = NextHop.read(cb); + isNextHop = ((NextHop) pathAttribute).isNextHopSet(); + break; + case Med.MED_TYPE: + pathAttribute = Med.read(cb); + break; + case LocalPref.LOCAL_PREF_TYPE: + pathAttribute = LocalPref.read(cb); + break; + case MPREACHNLRI_TYPE: + //TODO: To be merged later + break; + case MPUNREACHNLRI_TYPE: + //TODO: To be merged later + break; + case LINK_STATE_ATTRIBUTE_TYPE: + //TODO: To be merged later + break; + default: + //skip bytes for unsupported attribute types + UnSupportedAttribute.read(cb); + } + pathAttributeList.add(pathAttribute); + } + + checkMandatoryAttr(isOrigin, isAsPath, isNextHop, isMpReach, isMpUnReach); + //TODO:if mp_reach or mp_unreach not present ignore the packet + return new BgpPathAttributes(pathAttributeList); + } + + /** + * Checks mandatory attributes are presents, if not present throws exception. + * + * @param isOrigin say whether origin attribute is present + * @param isAsPath say whether aspath attribute is present + * @param isNextHop say whether nexthop attribute is present + * @param isMpReach say whether mpreach attribute is present + * @param isMpUnReach say whether mpunreach attribute is present + * @throws BGPParseException if mandatory path attribute is not present + */ + public static void checkMandatoryAttr(boolean isOrigin, boolean isAsPath, + boolean isNextHop, boolean isMpReach, boolean isMpUnReach) + throws BGPParseException { + if (!isOrigin) { + log.debug("Mandatory Attributes not Present"); + Validation.validateType(BGPErrorType.UPDATE_MESSAGE_ERROR, + BGPErrorType.MISSING_WELLKNOWN_ATTRIBUTE, + Origin.ORIGIN_TYPE); + } + if (!isAsPath) { + log.debug("Mandatory Attributes not Present"); + Validation.validateType(BGPErrorType.UPDATE_MESSAGE_ERROR, + BGPErrorType.MISSING_WELLKNOWN_ATTRIBUTE, + AsPath.ASPATH_TYPE); + } + if (!isMpUnReach && !isMpReach && !isNextHop) { + log.debug("Mandatory Attributes not Present"); + Validation.validateType(BGPErrorType.UPDATE_MESSAGE_ERROR, + BGPErrorType.MISSING_WELLKNOWN_ATTRIBUTE, + NextHop.NEXTHOP_TYPE); + } + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("pathAttribute", pathAttribute) + .toString(); + } +} diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/As4Path.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/As4Path.java new file mode 100644 index 00000000..90e94e88 --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/As4Path.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.bgpio.types; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.onosproject.bgpio.exceptions.BGPParseException; +import org.onosproject.bgpio.util.Validation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.MoreObjects; + +/** + * Provides Implementation of As4Path BGP Path Attribute. + */ +public class As4Path implements BGPValueType { + private static final Logger log = LoggerFactory.getLogger(AsPath.class); + public static final byte AS4PATH_TYPE = 17; + public static final byte ASNUM_SIZE = 4; + public static final int TYPE_AND_LEN_AS_SHORT = 4; + public static final int TYPE_AND_LEN_AS_BYTE = 3; + + private List as4pathSet; + private List as4pathSeq; + + /** + * Initialize fields. + */ + public As4Path() { + this.as4pathSeq = null; + this.as4pathSet = null; + } + + /** + * Constructor to initialize parameters. + * + * @param as4pathSet AS4path Set + * @param as4pathSeq AS4path Sequence + */ + public As4Path(List as4pathSet, List as4pathSeq) { + this.as4pathSeq = as4pathSeq; + this.as4pathSet = as4pathSet; + } + + /** + * Reads from the channel buffer and parses As4Path. + * + * @param cb ChannelBuffer + * @return object of As4Path + * @throws BGPParseException while parsing As4Path + */ + public static As4Path read(ChannelBuffer cb) throws BGPParseException { + List as4pathSet = new ArrayList<>(); + List as4pathSeq = new ArrayList<>(); + ChannelBuffer tempCb = cb.copy(); + Validation validation = Validation.parseAttributeHeader(cb); + + if (cb.readableBytes() < validation.getLength()) { + Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_LENGTH_ERROR, + validation.getLength()); + } + //if fourth bit is set length is read as short otherwise as byte , len includes type, length and value + int len = validation.isShort() ? validation.getLength() + TYPE_AND_LEN_AS_SHORT : validation + .getLength() + TYPE_AND_LEN_AS_BYTE; + ChannelBuffer data = tempCb.readBytes(len); + if (validation.getFirstBit() && !validation.getSecondBit() && validation.getThirdBit()) { + throw new BGPParseException(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_FLAGS_ERROR, data); + } + + ChannelBuffer tempBuf = cb.readBytes(validation.getLength()); + while (tempBuf.readableBytes() > 0) { + byte pathSegType = tempBuf.readByte(); + //no of ASes + byte pathSegLen = tempBuf.readByte(); + //length = no of Ases * ASnum size (4 bytes) + int length = pathSegLen * ASNUM_SIZE; + if (tempBuf.readableBytes() < length) { + Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, + BGPErrorType.ATTRIBUTE_LENGTH_ERROR, length); + } + ChannelBuffer aspathBuf = tempBuf.readBytes(length); + while (aspathBuf.readableBytes() > 0) { + int asNum; + asNum = aspathBuf.readInt(); + switch (pathSegType) { + case AsPath.ASPATH_SET_TYPE: + as4pathSet.add(asNum); + break; + case AsPath.ASPATH_SEQ_TYPE: + as4pathSeq.add(asNum); + break; + default: log.debug("Other type Not Supported:" + pathSegType); + } + } + } + return new As4Path(as4pathSet, as4pathSeq); + } + + @Override + public short getType() { + return AS4PATH_TYPE; + } + + /** + * Returns list of ASNum in AS4path Sequence. + * + * @return list of ASNum in AS4path Sequence + */ + public List as4PathSEQ() { + return this.as4pathSeq; + } + + /** + * Returns list of ASNum in AS4path Set. + * + * @return list of ASNum in AS4path Set + */ + public List as4PathSET() { + return this.as4pathSet; + } + + @Override + public int hashCode() { + return Objects.hash(as4pathSet, as4pathSeq); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof As4Path) { + As4Path other = (As4Path) obj; + return Objects.equals(as4pathSet, other.as4pathSet) && Objects.equals(as4pathSeq, other.as4pathSeq); + } + return false; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .omitNullValues() + .add("as4pathSet", as4pathSet) + .add("as4pathSeq", as4pathSeq) + .toString(); + } + + @Override + public int write(ChannelBuffer cb) { + //Not required to Implement as of now + return 0; + } +} \ No newline at end of file diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/AsPath.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/AsPath.java new file mode 100644 index 00000000..100e14d7 --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/AsPath.java @@ -0,0 +1,209 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.bgpio.types; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.onosproject.bgpio.exceptions.BGPParseException; +import org.onosproject.bgpio.util.Validation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.MoreObjects; + +/** + * Provides Implementation of AsPath mandatory BGP Path Attribute. + */ +public class AsPath implements BGPValueType { + /** + * Enum to provide AS types. + */ + public enum ASTYPE { + AS_SET(1), AS_SEQUENCE(2), AS_CONFED_SEQUENCE(3), AS_CONFED_SET(4); + int value; + + /** + * Assign val with the value as the AS type. + * + * @param val AS type + */ + ASTYPE(int val) { + value = val; + } + + /** + * Returns value of AS type. + * + * @return AS type + */ + public byte getType() { + return (byte) value; + } + } + + private static final Logger log = LoggerFactory.getLogger(AsPath.class); + public static final byte ASPATH_TYPE = 2; + public static final byte ASPATH_SET_TYPE = 1; + public static final byte ASPATH_SEQ_TYPE = 2; + public static final byte ASNUM_SIZE = 2; + public static final int TYPE_AND_LEN_AS_SHORT = 4; + public static final int TYPE_AND_LEN_AS_BYTE = 3; + + private boolean isAsPath = false; + private List aspathSet; + private List aspathSeq; + + /** + * Initialize Fields. + */ + public AsPath() { + this.aspathSeq = null; + this.aspathSet = null; + } + + /** + * Constructor to initialize parameters. + * + * @param aspathSet ASpath Set type + * @param aspathSeq ASpath Sequence type + */ + public AsPath(List aspathSet, List aspathSeq) { + this.aspathSeq = aspathSeq; + this.aspathSet = aspathSet; + this.isAsPath = true; + } + + /** + * Reads from the channel buffer and parses AsPath. + * + * @param cb ChannelBuffer + * @return object of AsPath + * @throws BGPParseException while parsing AsPath + */ + public static AsPath read(ChannelBuffer cb) throws BGPParseException { + List aspathSet = new ArrayList<>(); + List aspathSeq = new ArrayList<>(); + ChannelBuffer tempCb = cb.copy(); + Validation validation = Validation.parseAttributeHeader(cb); + + if (cb.readableBytes() < validation.getLength()) { + Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_LENGTH_ERROR, + validation.getLength()); + } + //if fourth bit is set, length is read as short otherwise as byte , len includes type, length and value + int len = validation.isShort() ? validation.getLength() + TYPE_AND_LEN_AS_SHORT : validation + .getLength() + TYPE_AND_LEN_AS_BYTE; + ChannelBuffer data = tempCb.readBytes(len); + if (validation.getFirstBit() && !validation.getSecondBit() && validation.getThirdBit()) { + throw new BGPParseException(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_FLAGS_ERROR, data); + } + + ChannelBuffer tempBuf = cb.readBytes(validation.getLength()); + while (tempBuf.readableBytes() > 0) { + byte pathSegType = tempBuf.readByte(); + //no of ASes + byte pathSegLen = tempBuf.readByte(); + int length = pathSegLen * ASNUM_SIZE; + if (tempBuf.readableBytes() < length) { + Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, + BGPErrorType.ATTRIBUTE_LENGTH_ERROR, length); + } + ChannelBuffer aspathBuf = tempBuf.readBytes(length); + while (aspathBuf.readableBytes() > 0) { + short asNum; + asNum = aspathBuf.readShort(); + switch (pathSegType) { + case ASPATH_SET_TYPE: + aspathSet.add(asNum); + break; + case ASPATH_SEQ_TYPE: + aspathSeq.add(asNum); + break; + default: log.debug("Other type Not Supported:" + pathSegType); + } + } + } + return new AsPath(aspathSet, aspathSeq); + } + + @Override + public short getType() { + return ASPATH_TYPE; + } + + /** + * Returns whether ASpath path attribute is present. + * + * @return whether ASpath path attribute is present + */ + public boolean isaspathSet() { + return this.isAsPath; + } + + /** + * Returns list of ASNum in ASpath Sequence. + * + * @return list of ASNum in ASpath Sequence + */ + public List asPathSeq() { + return this.aspathSeq; + } + + /** + * Returns list of ASNum in ASpath SET. + * + * @return list of ASNum in ASpath SET + */ + public List asPathSet() { + return this.aspathSet; + } + + @Override + public int hashCode() { + return Objects.hash(aspathSet, aspathSeq); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof AsPath) { + AsPath other = (AsPath) obj; + return Objects.equals(aspathSet, other.aspathSet) && Objects.equals(aspathSeq, other.aspathSeq); + } + return false; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .omitNullValues() + .add("aspathSet", aspathSet) + .add("aspathSeq", aspathSeq) + .toString(); + } + + @Override + public int write(ChannelBuffer cb) { + //Not required to Implement as of now + return 0; + } +} \ No newline at end of file diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/LocalPref.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/LocalPref.java new file mode 100644 index 00000000..048d81ee --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/LocalPref.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.bgpio.types; + +import java.util.Objects; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.onosproject.bgpio.exceptions.BGPParseException; +import org.onosproject.bgpio.util.Validation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.MoreObjects; + +/** + * Provides implementation of LocalPref BGP Path Attribute. + */ +public class LocalPref implements BGPValueType { + + private static final Logger log = LoggerFactory.getLogger(LocalPref.class); + public static final byte LOCAL_PREF_TYPE = 5; + public static final int TYPE_AND_LEN_AS_SHORT = 4; + public static final int TYPE_AND_LEN_AS_BYTE = 3; + public static final byte LOCAL_PREF_MAX_LEN = 4; + + private int localPref; + + /** + * Constructor to initialize LocalPref. + * + * @param localPref local preference + */ + public LocalPref(int localPref) { + this.localPref = localPref; + } + + /** + * Returns local preference value. + * + * @return local preference value + */ + public int localPref() { + return this.localPref; + } + + /** + * Reads the channel buffer and returns object of LocalPref. + * + * @param cb channelBuffer + * @return object of LocalPref + * @throws BGPParseException while parsing localPref attribute + */ + public static LocalPref read(ChannelBuffer cb) throws BGPParseException { + int localPref; + ChannelBuffer tempCb = cb.copy(); + Validation parseFlags = Validation.parseAttributeHeader(cb); + if ((parseFlags.getLength() > LOCAL_PREF_MAX_LEN) || cb.readableBytes() < parseFlags.getLength()) { + Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_LENGTH_ERROR, + parseFlags.getLength()); + } + + int len = parseFlags.isShort() ? parseFlags.getLength() + TYPE_AND_LEN_AS_SHORT : parseFlags.getLength() + + TYPE_AND_LEN_AS_BYTE; + ChannelBuffer data = tempCb.readBytes(len); + if (parseFlags.getFirstBit()) { + throw new BGPParseException(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_FLAGS_ERROR, data); + } + + localPref = cb.readInt(); + return new LocalPref(localPref); + } + + @Override + public short getType() { + return LOCAL_PREF_TYPE; + } + + @Override + public int hashCode() { + return Objects.hash(localPref); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof LocalPref) { + LocalPref other = (LocalPref) obj; + return Objects.equals(localPref, other.localPref); + } + return false; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("localPref", localPref) + .toString(); + } + + @Override + public int write(ChannelBuffer cb) { + //Not to implement as of now + return 0; + } +} \ No newline at end of file diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/Med.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/Med.java new file mode 100644 index 00000000..49e1fc5a --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/Med.java @@ -0,0 +1,119 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.bgpio.types; + +import java.util.Objects; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.onosproject.bgpio.exceptions.BGPParseException; +import org.onosproject.bgpio.util.Validation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.MoreObjects; + +/** + * Provides Implementation of Med BGP Path Attribute. + */ +public class Med implements BGPValueType { + private static final Logger log = LoggerFactory.getLogger(Med.class); + public static final byte MED_TYPE = 4; + public static final int TYPE_AND_LEN_AS_SHORT = 4; + public static final int TYPE_AND_LEN_AS_BYTE = 3; + public static final byte MED_MAX_LEN = 4; + + private int med; + + /** + * Constructor to initialize med. + * + * @param med MULTI_EXIT_DISC value + */ + public Med(int med) { + this.med = med; + } + + /** + * Returns Med value. + * + * @return Med value + */ + public int med() { + return this.med; + } + + /** + * Reads the channel buffer and returns object of Med. + * + * @param cb ChannelBuffer + * @return object of Med + * @throws BGPParseException while parsing Med path attribute + */ + public static Med read(ChannelBuffer cb) throws BGPParseException { + int med; + ChannelBuffer tempCb = cb.copy(); + Validation parseFlags = Validation.parseAttributeHeader(cb); + + if ((parseFlags.getLength() > MED_MAX_LEN) || cb.readableBytes() < parseFlags.getLength()) { + Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_LENGTH_ERROR, + parseFlags.getLength()); + } + int len = parseFlags.isShort() ? parseFlags.getLength() + TYPE_AND_LEN_AS_SHORT : parseFlags + .getLength() + TYPE_AND_LEN_AS_BYTE; + ChannelBuffer data = tempCb.readBytes(len); + if (!parseFlags.getFirstBit() && parseFlags.getSecondBit() && parseFlags.getThirdBit()) { + throw new BGPParseException(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_FLAGS_ERROR, data); + } + + med = cb.readInt(); + return new Med(med); + } + + @Override + public short getType() { + return MED_TYPE; + } + + @Override + public int hashCode() { + return Objects.hash(med); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof Med) { + Med other = (Med) obj; + return Objects.equals(med, other.med); + } + return false; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("med", med) + .toString(); + } + + @Override + public int write(ChannelBuffer cb) { + //Not to implement as of now + return 0; + } +} \ No newline at end of file diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/NextHop.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/NextHop.java new file mode 100644 index 00000000..353ec3d5 --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/NextHop.java @@ -0,0 +1,138 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.bgpio.types; + +import java.net.InetAddress; +import java.util.Objects; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.onlab.packet.Ip4Address; +import org.onosproject.bgpio.exceptions.BGPParseException; +import org.onosproject.bgpio.util.Validation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.MoreObjects; +import com.google.common.base.Preconditions; + +/** + * Implementation of NextHop BGP Path Attribute. + */ +public class NextHop implements BGPValueType { + private static final Logger log = LoggerFactory.getLogger(NextHop.class); + public static final byte NEXTHOP_TYPE = 3; + public static final int TYPE_AND_LEN_AS_SHORT = 4; + public static final int TYPE_AND_LEN_AS_BYTE = 3; + + private boolean isNextHop = false; + private Ip4Address nextHop; + + /** + * Constructor to initialize parameters. + * + * @param nextHop nextHop address + */ + public NextHop(Ip4Address nextHop) { + this.nextHop = Preconditions.checkNotNull(nextHop); + this.isNextHop = true; + } + + /** + * Returns whether next hop is present. + * + * @return whether next hop is present + */ + public boolean isNextHopSet() { + return this.isNextHop; + } + + /** + * Reads from ChannelBuffer and parses NextHop. + * + * @param cb ChannelBuffer + * @return object of NextHop + * @throws BGPParseException while parsing nexthop attribute + */ + public static NextHop read(ChannelBuffer cb) throws BGPParseException { + Ip4Address nextHop; + ChannelBuffer tempCb = cb.copy(); + Validation parseFlags = Validation.parseAttributeHeader(cb); + + if (cb.readableBytes() < parseFlags.getLength()) { + Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_LENGTH_ERROR, + parseFlags.getLength()); + } + int len = parseFlags.isShort() ? parseFlags.getLength() + TYPE_AND_LEN_AS_SHORT : parseFlags + .getLength() + TYPE_AND_LEN_AS_BYTE; + ChannelBuffer data = tempCb.readBytes(len); + if (parseFlags.getFirstBit() && !parseFlags.getSecondBit() && parseFlags.getThirdBit()) { + throw new BGPParseException(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_FLAGS_ERROR, data); + } + + //TODO: use Validation.toInetAddress once Validation is merged + InetAddress ipAddress = (InetAddress) cb.readBytes(parseFlags.getLength()); + if (ipAddress.isMulticastAddress()) { + throw new BGPParseException("Multicast address is not supported"); + } + + nextHop = Ip4Address.valueOf(ipAddress); + return new NextHop(nextHop); + } + + /** + * Return nexthop address. + * + * @return nexthop address + */ + public Ip4Address nextHop() { + return nextHop; + } + + @Override + public short getType() { + return NEXTHOP_TYPE; + } + + @Override + public int write(ChannelBuffer cb) { + //Not required to be implemented now + return 0; + } + + @Override + public int hashCode() { + return Objects.hash(nextHop); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof NextHop) { + NextHop other = (NextHop) obj; + return Objects.equals(nextHop, other.nextHop); + } + return false; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("nextHop", nextHop) + .toString(); + } +} \ No newline at end of file diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/Origin.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/Origin.java new file mode 100644 index 00000000..3b2070de --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/Origin.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.bgpio.types; + +import java.util.Objects; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.onosproject.bgpio.exceptions.BGPParseException; +import org.onosproject.bgpio.util.Validation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.MoreObjects; + +/** + * Provides Implementation of mandatory BGP Origin path attribute. + */ +public class Origin implements BGPValueType { + private static final Logger log = LoggerFactory.getLogger(Origin.class); + + /** + * Enum to provide ORIGIN types. + */ + public enum ORIGINTYPE { + IGP(0), EGP(1), INCOMPLETE(2); + int value; + /** + * Assign val with the value as the ORIGIN type. + * + * @param val ORIGIN type + */ + ORIGINTYPE(int val) { + value = val; + } + + /** + * Returns value of ORIGIN type. + * + * @return ORIGIN type + */ + public byte getType() { + return (byte) value; + } + } + + public static final byte ORIGIN_TYPE = 1; + public static final byte ORIGIN_VALUE_LEN = 1; + public static final int TYPE_AND_LEN_AS_SHORT = 4; + public static final int TYPE_AND_LEN_AS_BYTE = 3; + + private boolean isOrigin = false; + private byte origin; + + /** + * Constructor to initialize parameters. + * + * @param origin origin value + */ + public Origin(byte origin) { + this.origin = origin; + this.isOrigin = true; + } + + /** + * Returns true if origin attribute is present otherwise false. + * + * @return whether origin is present or not + */ + public boolean isOriginSet() { + return this.isOrigin; + } + + /** + * Returns type of Origin in Enum values. + * + * @return type of Origin in Enum values + */ + public ORIGINTYPE origin() { + if (this.origin == 0) { + return ORIGINTYPE.IGP; + } else if (this.origin == 1) { + return ORIGINTYPE.EGP; + } else { + return ORIGINTYPE.INCOMPLETE; + } + } + + /** + * Reads from ChannelBuffer and parses Origin. + * + * @param cb ChannelBuffer + * @return object of Origin + * @throws BGPParseException while parsing Origin path attribute + */ + public static Origin read(ChannelBuffer cb) throws BGPParseException { + ChannelBuffer tempCb = cb.copy(); + Validation parseFlags = Validation.parseAttributeHeader(cb); + + int len = parseFlags.isShort() ? parseFlags.getLength() + TYPE_AND_LEN_AS_SHORT : parseFlags + .getLength() + TYPE_AND_LEN_AS_BYTE; + ChannelBuffer data = tempCb.readBytes(len); + if ((parseFlags.getLength() > ORIGIN_VALUE_LEN) || (cb.readableBytes() < parseFlags.getLength())) { + Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_LENGTH_ERROR, + parseFlags.getLength()); + } + if (parseFlags.getFirstBit() && !parseFlags.getSecondBit() && parseFlags.getThirdBit()) { + throw new BGPParseException(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_FLAGS_ERROR, data); + } + + byte originValue; + originValue = cb.readByte(); + if ((originValue != ORIGINTYPE.INCOMPLETE.value) || (originValue != ORIGINTYPE.IGP.value) || + (originValue != ORIGINTYPE.EGP.value)) { + throw new BGPParseException(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.INVALID_ORIGIN_ATTRIBUTE, data); + } + return new Origin(originValue); + } + + @Override + public short getType() { + return ORIGIN_TYPE; + } + + @Override + public int write(ChannelBuffer cb) { + //Not required to Implement as of now + return 0; + } + + @Override + public int hashCode() { + return Objects.hash(origin); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof Origin) { + Origin other = (Origin) obj; + return Objects.equals(origin, other.origin); + } + return false; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("origin", origin) + .toString(); + } +} \ No newline at end of file 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 index ba02f6d1..e7f4a4c0 100755 --- 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 @@ -30,7 +30,7 @@ import com.google.common.base.MoreObjects; /** * Implements BGP attribute node flag. */ -public class BgpAttrNodeFlagBitTlv implements BGPValueType { +public final class BgpAttrNodeFlagBitTlv implements BGPValueType { protected static final Logger log = LoggerFactory .getLogger(BgpAttrNodeFlagBitTlv.class); @@ -38,16 +38,15 @@ public class BgpAttrNodeFlagBitTlv implements BGPValueType { public static final int ATTRNODE_FLAGBIT = 1024; /* Node flag bit TLV */ - private boolean bOverloadBit; - private boolean bAttachedBit; - private boolean bExternalBit; - private boolean bABRBit; + private final boolean bOverloadBit; + private final boolean bAttachedBit; + private final boolean bExternalBit; + private final boolean bAbrBit; - public static final int BIT_SET = 1; - public static final int FIRST_BIT = 0x80; - public static final int SECOND_BIT = 0x40; - public static final int THIRD_BIT = 0x20; - public static final int FOURTH_BIT = 0x01; + public static final byte FIRST_BIT = (byte) 0x80; + public static final byte SECOND_BIT = 0x40; + public static final byte THIRD_BIT = 0x20; + public static final byte FOURTH_BIT = 0x01; /** * Constructor to initialize parameters. @@ -55,14 +54,31 @@ public class BgpAttrNodeFlagBitTlv implements BGPValueType { * @param bOverloadBit Overload bit * @param bAttachedBit Attached bit * @param bExternalBit External bit - * @param bABRBit ABR Bit + * @param bAbrBit ABR Bit */ - BgpAttrNodeFlagBitTlv(boolean bOverloadBit, boolean bAttachedBit, - boolean bExternalBit, boolean bABRBit) { + private BgpAttrNodeFlagBitTlv(boolean bOverloadBit, boolean bAttachedBit, + boolean bExternalBit, boolean bAbrBit) { this.bOverloadBit = bOverloadBit; this.bAttachedBit = bAttachedBit; this.bExternalBit = bExternalBit; - this.bABRBit = bABRBit; + this.bAbrBit = bAbrBit; + } + + /** + * Returns object of this class with specified values. + * + * @param bOverloadBit Overload bit + * @param bAttachedBit Attached bit + * @param bExternalBit External bit + * @param bAbrBit ABR Bit + * @return object of BgpAttrNodeFlagBitTlv + */ + public static BgpAttrNodeFlagBitTlv of(final boolean bOverloadBit, + final boolean bAttachedBit, + final boolean bExternalBit, + final boolean bAbrBit) { + return new BgpAttrNodeFlagBitTlv(bOverloadBit, bAttachedBit, + bExternalBit, bAbrBit); } /** @@ -77,11 +93,11 @@ public class BgpAttrNodeFlagBitTlv implements BGPValueType { boolean bOverloadBit = false; boolean bAttachedBit = false; boolean bExternalBit = false; - boolean bABRBit = false; + boolean bAbrBit = false; short lsAttrLength = cb.readShort(); - if (lsAttrLength != 1) { + if ((lsAttrLength != 1) || (cb.readableBytes() < lsAttrLength)) { Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_LENGTH_ERROR, lsAttrLength); @@ -89,13 +105,13 @@ public class BgpAttrNodeFlagBitTlv implements BGPValueType { byte nodeFlagBits = cb.readByte(); - bOverloadBit = ((nodeFlagBits & (byte) FIRST_BIT) == FIRST_BIT); - bAttachedBit = ((nodeFlagBits & (byte) SECOND_BIT) == SECOND_BIT); - bExternalBit = ((nodeFlagBits & (byte) THIRD_BIT) == THIRD_BIT); - bABRBit = ((nodeFlagBits & (byte) FOURTH_BIT) == FOURTH_BIT); + bOverloadBit = ((nodeFlagBits & FIRST_BIT) == FIRST_BIT); + bAttachedBit = ((nodeFlagBits & SECOND_BIT) == SECOND_BIT); + bExternalBit = ((nodeFlagBits & THIRD_BIT) == THIRD_BIT); + bAbrBit = ((nodeFlagBits & FOURTH_BIT) == FOURTH_BIT); - return new BgpAttrNodeFlagBitTlv(bOverloadBit, bAttachedBit, - bExternalBit, bABRBit); + return BgpAttrNodeFlagBitTlv.of(bOverloadBit, bAttachedBit, + bExternalBit, bAbrBit); } /** @@ -103,7 +119,7 @@ public class BgpAttrNodeFlagBitTlv implements BGPValueType { * * @return Overload Bit */ - boolean getOverLoadBit() { + public boolean overLoadBit() { return bOverloadBit; } @@ -112,7 +128,7 @@ public class BgpAttrNodeFlagBitTlv implements BGPValueType { * * @return Attached Bit */ - boolean getAttachedBit() { + public boolean attachedBit() { return bAttachedBit; } @@ -121,7 +137,7 @@ public class BgpAttrNodeFlagBitTlv implements BGPValueType { * * @return External Bit */ - boolean getExternalBit() { + public boolean externalBit() { return bExternalBit; } @@ -130,8 +146,8 @@ public class BgpAttrNodeFlagBitTlv implements BGPValueType { * * @return ABR Bit */ - boolean getABRBit() { - return bABRBit; + public boolean abrBit() { + return bAbrBit; } @Override @@ -141,13 +157,13 @@ public class BgpAttrNodeFlagBitTlv implements BGPValueType { @Override public int write(ChannelBuffer cb) { - // TODO will be implementing it later + // TODO This will be implemented in the next version return 0; } @Override public int hashCode() { - return Objects.hash(bOverloadBit, bAttachedBit, bExternalBit, bABRBit); + return Objects.hash(bOverloadBit, bAttachedBit, bExternalBit, bAbrBit); } @Override @@ -161,7 +177,7 @@ public class BgpAttrNodeFlagBitTlv implements BGPValueType { return Objects.equals(bOverloadBit, other.bOverloadBit) && Objects.equals(bAttachedBit, other.bAttachedBit) && Objects.equals(bExternalBit, other.bExternalBit) - && Objects.equals(bABRBit, other.bABRBit); + && Objects.equals(bAbrBit, other.bAbrBit); } return false; } @@ -171,7 +187,7 @@ public class BgpAttrNodeFlagBitTlv implements BGPValueType { return MoreObjects.toStringHelper(getClass()) .add("bOverloadBit", bOverloadBit) .add("bAttachedBit", bAttachedBit) - .add("bExternalBit", bExternalBit).add("bABRBit", bABRBit) + .add("bExternalBit", bExternalBit).add("bAbrBit", bAbrBit) .toString(); } } diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpAttrRouterIdV4.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpAttrRouterIdV4.java index 00dffb58..a10d167a 100755 --- a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpAttrRouterIdV4.java +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpAttrRouterIdV4.java @@ -31,15 +31,15 @@ import com.google.common.base.MoreObjects; /** * Implements BGP attribute node router ID. */ -public class BgpAttrRouterIdV4 implements BGPValueType { +public final class BgpAttrRouterIdV4 implements BGPValueType { protected static final Logger log = LoggerFactory .getLogger(BgpAttrRouterIdV4.class); - public short sType; + private final short sType; /* IPv4 Router-ID of Node */ - private Ip4Address ip4RouterId; + private final Ip4Address ip4RouterId; /** * Constructor to initialize the value. @@ -47,35 +47,45 @@ public class BgpAttrRouterIdV4 implements BGPValueType { * @param ip4RouterId IPV4 address of router * @param sType TLV type */ - BgpAttrRouterIdV4(Ip4Address ip4RouterId, short sType) { + private BgpAttrRouterIdV4(Ip4Address ip4RouterId, short sType) { this.ip4RouterId = ip4RouterId; this.sType = sType; } + /** + * Returns object of this class with specified values. + * + * @param ip4RouterId IPv4 address + * @param sType Type of this TLV + * @return object of BgpAttrRouterIdV4 + */ + public static BgpAttrRouterIdV4 of(final Ip4Address ip4RouterId, + final short sType) { + return new BgpAttrRouterIdV4(ip4RouterId, sType); + } + /** * Reads the IPv4 Router-ID. * * @param cb ChannelBuffer + * @param sType tag type * @return object of BgpAttrRouterIdV4 - * @throws BGPParseException while parsing BgpAttrNodeRouterId + * @throws BGPParseException while parsing BgpAttrRouterIdV4 */ public static BgpAttrRouterIdV4 read(ChannelBuffer cb, short sType) throws BGPParseException { - byte[] ipBytes; - Ip4Address ip4RouterId; - short lsAttrLength = cb.readShort(); - if (4 != lsAttrLength) { + if ((lsAttrLength != 4) || (cb.readableBytes() < lsAttrLength)) { Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_LENGTH_ERROR, lsAttrLength); } - ipBytes = new byte[lsAttrLength]; - cb.readBytes(ipBytes); - ip4RouterId = Ip4Address.valueOf(ipBytes); - return new BgpAttrRouterIdV4(ip4RouterId, sType); + byte[] ipBytes = new byte[lsAttrLength]; + cb.readBytes(ipBytes, 0, lsAttrLength); + Ip4Address ip4RouterId = Ip4Address.valueOf(ipBytes); + return BgpAttrRouterIdV4.of(ip4RouterId, sType); } /** @@ -83,7 +93,7 @@ public class BgpAttrRouterIdV4 implements BGPValueType { * * @return Router ID */ - Ip4Address getAttrRouterId() { + public Ip4Address attrRouterId() { return ip4RouterId; } @@ -112,7 +122,7 @@ public class BgpAttrRouterIdV4 implements BGPValueType { @Override public int write(ChannelBuffer cb) { - // TODO Auto-generated method stub + // TODO This will be implemented in the next version return 0; } diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpAttrRouterIdV6.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpAttrRouterIdV6.java index 561c3d4c..ea63c379 100755 --- a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpAttrRouterIdV6.java +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpAttrRouterIdV6.java @@ -31,15 +31,15 @@ import com.google.common.base.MoreObjects; /** * Implements BGP attribute IPv6 router ID. */ -public class BgpAttrRouterIdV6 implements BGPValueType { +public final class BgpAttrRouterIdV6 implements BGPValueType { protected static final Logger log = LoggerFactory .getLogger(BgpAttrRouterIdV6.class); - public short sType; + private final short sType; /* IPv4 Router-ID of Node */ - private Ip6Address ip6RouterId; + private final Ip6Address ip6RouterId; /** * Constructor to initialize the value. @@ -47,15 +47,28 @@ public class BgpAttrRouterIdV6 implements BGPValueType { * @param ip6RouterId IPV6 address of the router ID * @param sType TLV type */ - BgpAttrRouterIdV6(Ip6Address ip6RouterId, short sType) { + private BgpAttrRouterIdV6(Ip6Address ip6RouterId, short sType) { this.ip6RouterId = ip6RouterId; this.sType = sType; } + /** + * Returns object of this class with specified values. + * + * @param ip6RouterId IPV6 address of the router ID + * @param sType TLV type + * @return object of BgpAttrRouterIdV6 + */ + public static BgpAttrRouterIdV6 of(final Ip6Address ip6RouterId, + final short sType) { + return new BgpAttrRouterIdV6(ip6RouterId, sType); + } + /** * Reads the IPv6 Router-ID. * * @param cb ChannelBuffer + * @param sType TLV type * @return object of BgpAttrRouterIdV6 * @throws BGPParseException while parsing BgpAttrRouterIdV6 */ @@ -66,7 +79,7 @@ public class BgpAttrRouterIdV6 implements BGPValueType { short lsAttrLength = cb.readShort(); - if (16 != lsAttrLength) { + if ((lsAttrLength != 16) || (cb.readableBytes() < lsAttrLength)) { Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_LENGTH_ERROR, lsAttrLength); @@ -75,7 +88,7 @@ public class BgpAttrRouterIdV6 implements BGPValueType { ipBytes = new byte[lsAttrLength]; cb.readBytes(ipBytes); ip6RouterId = Ip6Address.valueOf(ipBytes); - return new BgpAttrRouterIdV6(ip6RouterId, sType); + return BgpAttrRouterIdV6.of(ip6RouterId, sType); } /** @@ -83,7 +96,7 @@ public class BgpAttrRouterIdV6 implements BGPValueType { * * @return Router ID */ - Ip6Address getAttrRouterId() { + public Ip6Address attrRouterId() { return ip6RouterId; } @@ -112,7 +125,7 @@ public class BgpAttrRouterIdV6 implements BGPValueType { @Override public int write(ChannelBuffer cb) { - // TODO Auto-generated method stub + // TODO This will be implemented in the next version return 0; } diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpLinkAttrIgpMetric.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpLinkAttrIgpMetric.java new file mode 100755 index 00000000..c1cb299c --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpLinkAttrIgpMetric.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.types.attr; + +import java.util.Objects; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.onosproject.bgpio.exceptions.BGPParseException; +import org.onosproject.bgpio.types.BGPErrorType; +import org.onosproject.bgpio.types.BGPValueType; +import org.onosproject.bgpio.util.Validation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.MoreObjects; + +/** + * Implements BGP link IGP metric attribute. + */ +public class BgpLinkAttrIgpMetric implements BGPValueType { + + protected static final Logger log = LoggerFactory + .getLogger(BgpLinkAttrIgpMetric.class); + + public static final int ATTRLINK_IGPMETRIC = 1095; + public static final int ATTRLINK_MAX_LEN = 3; + + /* Variable metric length based on protocol */ + public static final int ISIS_SMALL_METRIC = 1; + public static final int OSPF_LINK_METRIC = 2; + public static final int ISIS_WIDE_METRIC = 3; + + /* IGP Metric */ + private final int igpMetric; + private final int igpMetricLen; + + /** + * Constructor to initialize the value. + * + * @param igpMetric 3 byte IGP metric data. + * @param igpMetricLen length of IGP metric data. + */ + public BgpLinkAttrIgpMetric(final int igpMetric, final int igpMetricLen) { + this.igpMetric = igpMetric; + this.igpMetricLen = igpMetricLen; + } + + /** + * Returns object of this class with specified values. + * + * @param igpMetric 3 byte IGP metric data. + * @param igpMetricLen length of IGP metric data. + * @return object of BgpLinkAttrIgpMetric + */ + public static BgpLinkAttrIgpMetric of(final int igpMetric, + final int igpMetricLen) { + return new BgpLinkAttrIgpMetric(igpMetric, igpMetricLen); + } + + /** + * Reads the BGP link attributes IGP Metric. + * + * @param cb Channel buffer + * @return object of type BgpLinkAttrIgpMetric + * @throws BGPParseException while parsing BgpLinkAttrIgpMetric + */ + public static BgpLinkAttrIgpMetric read(ChannelBuffer cb) + throws BGPParseException { + + short linkigp; + int igpMetric = 0; + int igpMetricLen = 0; + + short lsAttrLength = cb.readShort(); + + if (cb.readableBytes() < lsAttrLength + || lsAttrLength > ATTRLINK_MAX_LEN) { + Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, + BGPErrorType.ATTRIBUTE_LENGTH_ERROR, + lsAttrLength); + } + + switch (lsAttrLength) { + case ISIS_SMALL_METRIC: + igpMetric = cb.readByte(); + igpMetricLen = ISIS_SMALL_METRIC; + break; + case OSPF_LINK_METRIC: + igpMetric = cb.readShort(); + igpMetricLen = OSPF_LINK_METRIC; + break; + case ISIS_WIDE_METRIC: + linkigp = cb.readShort(); + igpMetric = cb.readByte(); + igpMetric = (igpMetric << 16) | linkigp; + igpMetricLen = ISIS_WIDE_METRIC; + break; + default: // validation is already in place + break; + } + + return BgpLinkAttrIgpMetric.of(igpMetric, igpMetricLen); + } + + /** + * Returns the variable length IGP metric data. + * + * @return IGP metric data + */ + public int attrLinkIgpMetric() { + return igpMetric; + } + + /** + * Returns IGP metric data length. + * + * @return IGP metric length + */ + public int attrLinkIgpMetricLength() { + return igpMetricLen; + } + + @Override + public short getType() { + return ATTRLINK_IGPMETRIC; + } + + @Override + public int hashCode() { + return Objects.hash(igpMetric, igpMetricLen); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj instanceof BgpLinkAttrIgpMetric) { + BgpLinkAttrIgpMetric other = (BgpLinkAttrIgpMetric) obj; + return Objects.equals(igpMetric, other.igpMetric) + && Objects.equals(igpMetricLen, other.igpMetricLen); + } + return false; + } + + @Override + public int write(ChannelBuffer cb) { + // TODO This will be implemented in the next version + return 0; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("igpMetric", igpMetric).add("igpMetricLen", igpMetricLen) + .toString(); + } +} diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpLinkAttrMplsProtocolMask.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpLinkAttrMplsProtocolMask.java new file mode 100755 index 00000000..61143fae --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpLinkAttrMplsProtocolMask.java @@ -0,0 +1,152 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.bgpio.types.attr; + +import java.util.Objects; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.onosproject.bgpio.exceptions.BGPParseException; +import org.onosproject.bgpio.types.BGPErrorType; +import org.onosproject.bgpio.types.BGPValueType; +import org.onosproject.bgpio.util.Validation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.MoreObjects; + +/** + * Implements BGP MPLS protocol mask attribute. + */ +public class BgpLinkAttrMplsProtocolMask implements BGPValueType { + + protected static final Logger log = LoggerFactory + .getLogger(BgpLinkAttrMplsProtocolMask.class); + + public static final int ATTRLINK_MPLSPROTOMASK = 1094; + public static final int MASK_BYTE_LEN = 1; + + private final boolean bLdp; + private final boolean bRsvpTe; + + public static final byte FIRST_BIT = (byte) 0x80; + public static final byte SECOND_BIT = 0x40; + + /** + * Constructor to initialize the values. + * + * @param bLdp boolean value true if LDP flag is available + * @param bRsvpTe boolean value true if RSVP TE information is available + */ + public BgpLinkAttrMplsProtocolMask(boolean bLdp, boolean bRsvpTe) { + this.bLdp = bLdp; + this.bRsvpTe = bRsvpTe; + } + + /** + * Returns object of this class with specified values. + * + * @param bLdp boolean value true if LDP flag is available + * @param bRsvpTe boolean value true if RSVP TE information is available + * @return object of BgpLinkAttrMplsProtocolMask + */ + public static BgpLinkAttrMplsProtocolMask of(final boolean bLdp, + final boolean bRsvpTe) { + return new BgpLinkAttrMplsProtocolMask(bLdp, bRsvpTe); + } + + /** + * Reads the BGP link attributes MPLS protocol mask. + * + * @param cb Channel buffer + * @return object of type BgpLinkAttrMPLSProtocolMask + * @throws BGPParseException while parsing BgpLinkAttrMplsProtocolMask + */ + public static BgpLinkAttrMplsProtocolMask read(ChannelBuffer cb) + throws BGPParseException { + boolean bLdp = false; + boolean bRsvpTe = false; + + short lsAttrLength = cb.readShort(); + + if ((lsAttrLength != MASK_BYTE_LEN) + || (cb.readableBytes() < lsAttrLength)) { + Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, + BGPErrorType.ATTRIBUTE_LENGTH_ERROR, + lsAttrLength); + } + + byte flags = cb.readByte(); + + bLdp = ((flags & (byte) FIRST_BIT) == FIRST_BIT); + bRsvpTe = ((flags & (byte) SECOND_BIT) == SECOND_BIT); + + return BgpLinkAttrMplsProtocolMask.of(bLdp, bRsvpTe); + } + + /** + * Returns true if LDP bit is set. + * + * @return True if LDP information is set else false. + */ + public boolean ldpBit() { + return bLdp; + } + + /** + * Returns RSVP TE information. + * + * @return True if RSVP TE information is set else false. + */ + public boolean rsvpBit() { + return bRsvpTe; + } + + @Override + public short getType() { + return ATTRLINK_MPLSPROTOMASK; + } + + @Override + public int hashCode() { + return Objects.hash(bLdp, bRsvpTe); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj instanceof BgpLinkAttrMplsProtocolMask) { + BgpLinkAttrMplsProtocolMask other = (BgpLinkAttrMplsProtocolMask) obj; + return Objects.equals(bLdp, other.bLdp) + && Objects.equals(bRsvpTe, other.bRsvpTe); + } + return false; + } + + @Override + public int write(ChannelBuffer cb) { + // TODO This will be implemented in the next version + return 0; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("bLdp", bLdp).add("bRsvpTe", bRsvpTe).toString(); + } +} diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpLinkAttrProtectionType.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpLinkAttrProtectionType.java new file mode 100755 index 00000000..b45d95b8 --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpLinkAttrProtectionType.java @@ -0,0 +1,240 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.bgpio.types.attr; + +import java.util.Objects; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.onosproject.bgpio.exceptions.BGPParseException; +import org.onosproject.bgpio.types.BGPErrorType; +import org.onosproject.bgpio.types.BGPValueType; +import org.onosproject.bgpio.util.Validation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.MoreObjects; + +/** + * Implements BGP link protection type attribute. + */ +public final class BgpLinkAttrProtectionType implements BGPValueType { + + protected static final Logger log = LoggerFactory + .getLogger(BgpLinkAttrProtectionType.class); + + public static final int ATTRLINK_PROTECTIONTYPE = 1093; + public static final int LINK_PROTECTION_LEN = 2; + + public static final int EXTRA_TRAFFIC = 0x01; + public static final int UNPROTECTED = 0x02; + public static final int SHARED = 0x04; + public static final int DEDICATED_ONE_ISTO_ONE = 0x08; + public static final int DEDICATED_ONE_PLUS_ONE = 0x10; + public static final int ENHANCED = 0x20; + + /* Link Protection type flags */ + private final boolean bExtraTraffic; + private final boolean bUnprotected; + private final boolean bShared; + private final boolean bDedOneIstoOne; + private final boolean bDedOnePlusOne; + private final boolean bEnhanced; + + /** + * Constructor to initialize the value. + * + * @param bExtraTraffic Extra Traffic + * @param bUnprotected Unprotected + * @param bShared Shared + * @param bDedOneIstoOne Dedicated 1:1 + * @param bDedOnePlusOne Dedicated 1+1 + * @param bEnhanced Enhanced + */ + private BgpLinkAttrProtectionType(boolean bExtraTraffic, + boolean bUnprotected, + boolean bShared, boolean bDedOneIstoOne, + boolean bDedOnePlusOne, boolean bEnhanced) { + this.bExtraTraffic = bExtraTraffic; + this.bUnprotected = bUnprotected; + this.bShared = bShared; + this.bDedOneIstoOne = bDedOneIstoOne; + this.bDedOnePlusOne = bDedOnePlusOne; + this.bEnhanced = bEnhanced; + } + + /** + * Returns object of this class with specified values. + * + * @param bExtraTraffic Extra Traffic + * @param bUnprotected Unprotected + * @param bShared Shared + * @param bDedOneIstoOne Dedicated 1:1 + * @param bDedOnePlusOne Dedicated 1+1 + * @param bEnhanced Enhanced + * @return object of BgpLinkAttrProtectionType + */ + public static BgpLinkAttrProtectionType of(boolean bExtraTraffic, + boolean bUnprotected, + boolean bShared, + boolean bDedOneIstoOne, + boolean bDedOnePlusOne, + boolean bEnhanced) { + return new BgpLinkAttrProtectionType(bExtraTraffic, bUnprotected, + bShared, bDedOneIstoOne, + bDedOnePlusOne, bEnhanced); + } + + /** + * Reads the BGP link attributes protection type. + * + * @param cb Channel buffer + * @return object of type BgpLinkAttrProtectionType + * @throws BGPParseException while parsing BgpLinkAttrProtectionType + */ + public static BgpLinkAttrProtectionType read(ChannelBuffer cb) + throws BGPParseException { + short linkProtectionType; + byte higherByte; + short lsAttrLength = cb.readShort(); + + boolean bExtraTraffic; + boolean bUnprotected; + boolean bShared; + boolean bDedOneIstoOne; + boolean bDedOnePlusOne; + boolean bEnhanced; + + if ((lsAttrLength != LINK_PROTECTION_LEN) + || (cb.readableBytes() < lsAttrLength)) { + Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, + BGPErrorType.ATTRIBUTE_LENGTH_ERROR, + lsAttrLength); + } + + linkProtectionType = cb.readShort(); + higherByte = (byte) (linkProtectionType >> 8); + + bExtraTraffic = ((higherByte & (byte) EXTRA_TRAFFIC) == EXTRA_TRAFFIC); + bUnprotected = ((higherByte & (byte) UNPROTECTED) == UNPROTECTED); + bShared = ((higherByte & (byte) SHARED) == SHARED); + bDedOneIstoOne = ((higherByte & (byte) DEDICATED_ONE_ISTO_ONE) == DEDICATED_ONE_ISTO_ONE); + bDedOnePlusOne = ((higherByte & (byte) DEDICATED_ONE_PLUS_ONE) == DEDICATED_ONE_PLUS_ONE); + bEnhanced = ((higherByte & (byte) ENHANCED) == ENHANCED); + + return BgpLinkAttrProtectionType.of(bExtraTraffic, bUnprotected, + bShared, bDedOneIstoOne, + bDedOnePlusOne, bEnhanced); + } + + /** + * Returns ExtraTraffic Bit. + * + * @return ExtraTraffic Bit + */ + public boolean extraTraffic() { + return bExtraTraffic; + } + + /** + * Returns Unprotected Bit. + * + * @return Unprotected Bit + */ + public boolean unprotected() { + return bUnprotected; + } + + /** + * Returns Shared Bit. + * + * @return Shared Bit + */ + public boolean shared() { + return bShared; + } + + /** + * Returns DedOneIstoOne Bit. + * + * @return DedOneIstoOne Bit + */ + public boolean dedOneIstoOne() { + return bDedOneIstoOne; + } + + /** + * Returns DedOnePlusOne Bit. + * + * @return DedOnePlusOne Bit + */ + public boolean dedOnePlusOne() { + return bDedOnePlusOne; + } + + /** + * Returns Enhanced Bit. + * + * @return Enhanced Bit + */ + public boolean enhanced() { + return bEnhanced; + } + + @Override + public short getType() { + return ATTRLINK_PROTECTIONTYPE; + } + + @Override + public int hashCode() { + return Objects.hash(bExtraTraffic, bUnprotected, bShared, + bDedOneIstoOne, bDedOnePlusOne, bEnhanced); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj instanceof BgpLinkAttrProtectionType) { + BgpLinkAttrProtectionType other = (BgpLinkAttrProtectionType) obj; + return Objects.equals(bExtraTraffic, other.bExtraTraffic) + && Objects.equals(bUnprotected, other.bUnprotected) + && Objects.equals(bShared, other.bShared) + && Objects.equals(bDedOneIstoOne, other.bDedOneIstoOne) + && Objects.equals(bDedOnePlusOne, other.bDedOnePlusOne) + && Objects.equals(bEnhanced, other.bEnhanced); + } + return false; + } + + @Override + public int write(ChannelBuffer cb) { + // TODO This will be implemented in the next version + return 0; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("bExtraTraffic", bExtraTraffic) + .add("bUnprotected", bUnprotected).add("bShared", bShared) + .add("bDedOneIstoOne", bDedOneIstoOne) + .add("bDedOnePlusOne", bDedOnePlusOne) + .add("bEnhanced", bEnhanced).toString(); + } +} diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpPrefixAttrMetric.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpPrefixAttrMetric.java new file mode 100755 index 00000000..0678b81f --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpPrefixAttrMetric.java @@ -0,0 +1,131 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.bgpio.types.attr; + +import java.util.Objects; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.onosproject.bgpio.exceptions.BGPParseException; +import org.onosproject.bgpio.types.BGPErrorType; +import org.onosproject.bgpio.types.BGPValueType; +import org.onosproject.bgpio.util.Validation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.MoreObjects; + +/** + * Implements BGP prefix metric attribute. + */ +public class BgpPrefixAttrMetric implements BGPValueType { + + protected static final Logger log = LoggerFactory + .getLogger(BgpPrefixAttrMetric.class); + + public static final int ATTR_PREFIX_METRIC = 1155; + public static final int ATTR_PREFIX_LEN = 4; + + /* TE Default Metric */ + private final int linkPfxMetric; + + /** + * Constructor to initialize value. + * + * @param linkPfxMetric Prefix Metric + */ + public BgpPrefixAttrMetric(int linkPfxMetric) { + this.linkPfxMetric = linkPfxMetric; + } + + /** + * Returns object of this class with specified values. + * + * @param linkPfxMetric Prefix Metric + * @return object of BgpPrefixAttrMetric + */ + public static BgpPrefixAttrMetric of(final int linkPfxMetric) { + return new BgpPrefixAttrMetric(linkPfxMetric); + } + + /** + * Reads the Prefix Metric. + * + * @param cb ChannelBuffer + * @return object of BgpPrefixAttrMetric + * @throws BGPParseException while parsing BgpPrefixAttrMetric + */ + public static BgpPrefixAttrMetric read(ChannelBuffer cb) + throws BGPParseException { + int linkPfxMetric; + + short lsAttrLength = cb.readShort(); // 4 Bytes + + if ((lsAttrLength != ATTR_PREFIX_LEN) + || (cb.readableBytes() < lsAttrLength)) { + Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, + BGPErrorType.ATTRIBUTE_LENGTH_ERROR, + lsAttrLength); + } + + linkPfxMetric = cb.readInt(); + + return BgpPrefixAttrMetric.of(linkPfxMetric); + } + + /** + * Returns the Prefix Metric. + * + * @return Prefix Metric + */ + public int attrPfxMetric() { + return linkPfxMetric; + } + + @Override + public short getType() { + return ATTR_PREFIX_METRIC; + } + + @Override + public int hashCode() { + return Objects.hash(linkPfxMetric); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj instanceof BgpPrefixAttrMetric) { + BgpPrefixAttrMetric other = (BgpPrefixAttrMetric) obj; + return Objects.equals(linkPfxMetric, other.linkPfxMetric); + } + return false; + } + + @Override + public int write(ChannelBuffer cb) { + // TODO This will be implemented in the next version + return 0; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("linkPfxMetric", linkPfxMetric).toString(); + } +} diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpPrefixAttrOspfFwdAddr.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpPrefixAttrOspfFwdAddr.java new file mode 100755 index 00000000..cf043046 --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpPrefixAttrOspfFwdAddr.java @@ -0,0 +1,187 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.bgpio.types.attr; + +import java.util.Objects; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.onlab.packet.Ip4Address; +import org.onlab.packet.Ip6Address; +import org.onosproject.bgpio.exceptions.BGPParseException; +import org.onosproject.bgpio.types.BGPErrorType; +import org.onosproject.bgpio.types.BGPValueType; +import org.onosproject.bgpio.util.Validation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.MoreObjects; + +/** + * Implements BGP prefix OSPF Forwarding address attribute. + */ +public class BgpPrefixAttrOspfFwdAddr implements BGPValueType { + + protected static final Logger log = LoggerFactory + .getLogger(BgpPrefixAttrOspfFwdAddr.class); + + public static final int ATTR_PREFIX_OSPFFWDADDR = 1156; + public static final int IPV4_LEN = 4; + public static final int IPV6_LEN = 16; + + /* OSPF Forwarding Address */ + private final short lsAttrLength; + private final Ip4Address ip4RouterId; + private final Ip6Address ip6RouterId; + + /** + * Constructor to initialize the value. + * + * @param lsAttrLength length of the IP address + * @param ip4RouterId Valid IPV4 address if length is 4 else null + * @param ip6RouterId Valid IPV6 address if length is 16 else null + */ + public BgpPrefixAttrOspfFwdAddr(short lsAttrLength, Ip4Address ip4RouterId, + Ip6Address ip6RouterId) { + this.lsAttrLength = lsAttrLength; + this.ip4RouterId = ip4RouterId; + this.ip6RouterId = ip6RouterId; + } + + /** + * Returns object of this class with specified values. + * + * @param lsAttrLength length of the IP address + * @param ip4RouterId Valid IPV4 address if length is 4 else null + * @param ip6RouterId Valid IPV6 address if length is 16 else null + * @return object of BgpPrefixAttrOspfFwdAddr + */ + public static BgpPrefixAttrOspfFwdAddr of(final short lsAttrLength, + final Ip4Address ip4RouterId, + final Ip6Address ip6RouterId) { + return new BgpPrefixAttrOspfFwdAddr(lsAttrLength, ip4RouterId, + ip6RouterId); + } + + /** + * Reads the OSPF Forwarding Address. + * + * @param cb ChannelBuffer + * @return object of BgpPrefixAttrOSPFFwdAddr + * @throws BGPParseException while parsing BgpPrefixAttrOspfFwdAddr + */ + public static BgpPrefixAttrOspfFwdAddr read(ChannelBuffer cb) + throws BGPParseException { + short lsAttrLength; + byte[] ipBytes; + Ip4Address ip4RouterId = null; + Ip6Address ip6RouterId = null; + + lsAttrLength = cb.readShort(); + ipBytes = new byte[lsAttrLength]; + + if ((cb.readableBytes() < lsAttrLength)) { + Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, + BGPErrorType.ATTRIBUTE_LENGTH_ERROR, + lsAttrLength); + } + + cb.readBytes(ipBytes); + + if (IPV4_LEN == lsAttrLength) { + ip4RouterId = Ip4Address.valueOf(ipBytes); + } else if (IPV6_LEN == lsAttrLength) { + ip6RouterId = Ip6Address.valueOf(ipBytes); + } + + return BgpPrefixAttrOspfFwdAddr.of(lsAttrLength, ip4RouterId, + ip6RouterId); + } + + /** + * Returns IPV4 Address of OSPF forwarding address. + * + * @return IPV4 address + */ + public Ip4Address ospfv4FwdAddr() { + return ip4RouterId; + } + + /** + * Returns IPV6 Address of OSPF forwarding address. + * + * @return IPV6 address + */ + public Ip6Address ospfv6FwdAddr() { + return ip6RouterId; + } + + /** + * Returns OSPF forwarding address length. + * + * @return length of the ip address + */ + public short ospfFwdAddrLen() { + return lsAttrLength; + } + + @Override + public short getType() { + return ATTR_PREFIX_OSPFFWDADDR; + } + + @Override + public int hashCode() { + if (IPV4_LEN == lsAttrLength) { + return Objects.hash(ip4RouterId); + } else { + return Objects.hash(ip6RouterId); + } + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj instanceof BgpPrefixAttrOspfFwdAddr) { + BgpPrefixAttrOspfFwdAddr other = (BgpPrefixAttrOspfFwdAddr) obj; + if (IPV4_LEN == lsAttrLength) { + return Objects.equals(ip4RouterId, other.ip4RouterId); + } else { + return Objects.equals(ip6RouterId, other.ip6RouterId); + } + } + return false; + } + + @Override + public int write(ChannelBuffer cb) { + // TODO This will be implemented in the next version + return 0; + } + + @Override + public String toString() { + if (IPV4_LEN == lsAttrLength) { + return MoreObjects.toStringHelper(getClass()).omitNullValues() + .add("ip4RouterId", ip4RouterId).toString(); + } else { + return MoreObjects.toStringHelper(getClass()).omitNullValues() + .add("ip6RouterId", ip6RouterId).toString(); + } + } +} 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 index 915aa580..bc131893 100644 --- 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 @@ -16,6 +16,8 @@ package org.onosproject.bgpio.util; +import java.net.InetAddress; +import java.net.UnknownHostException; import java.util.Arrays; import org.jboss.netty.buffer.ChannelBuffer; @@ -23,6 +25,8 @@ import org.jboss.netty.buffer.ChannelBuffers; import org.onlab.packet.IpAddress; import org.onlab.packet.IpPrefix; import org.onosproject.bgpio.exceptions.BGPParseException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.google.common.primitives.Ints; @@ -30,10 +34,11 @@ import com.google.common.primitives.Ints; * Provides methods to parse attribute header, validate length and type. */ public class Validation { + private static final Logger log = LoggerFactory.getLogger(Validation.class); public static final byte FIRST_BIT = (byte) 0x80; public static final byte SECOND_BIT = 0x40; public static final byte THIRD_BIT = 0x20; - public static final byte FOURTH_BIT = 0x01; + public static final byte FOURTH_BIT = (byte) 0x10; public static final byte IPV4_SIZE = 4; private boolean firstBit; private boolean secondBit; @@ -42,6 +47,16 @@ public class Validation { private int len; private boolean isShort; + /** + * Constructor to initialize parameter. + * + * @param firstBit in AttributeFlags + * @param secondBit in AttributeFlags + * @param thirdBit in AttributeFlags + * @param fourthBit in AttributeFlags + * @param len length + * @param isShort true if length is read as short otherwise false + */ Validation(boolean firstBit, boolean secondBit, boolean thirdBit, boolean fourthBit, int len, boolean isShort) { this.firstBit = firstBit; this.secondBit = secondBit; @@ -118,6 +133,25 @@ public class Validation { throw new BGPParseException(errorCode, subErrCode, buffer); } + /** + * Convert byte array to InetAddress. + * + * @param length of IpAddress + * @param cb channelBuffer + * @return InetAddress + */ + public static InetAddress toInetAddress(int length, ChannelBuffer cb) { + byte[] address = new byte[length]; + cb.readBytes(address, 0, length); + InetAddress ipAddress = null; + try { + ipAddress = InetAddress.getByAddress(address); + } catch (UnknownHostException e) { + log.info("InetAddress convertion failed"); + } + return ipAddress; + } + /** * Returns first bit in type flags. * diff --git a/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpAttrNodeFlagBitTlvTest.java b/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpAttrNodeFlagBitTlvTest.java new file mode 100644 index 00000000..5f1411ff --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpAttrNodeFlagBitTlvTest.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.bgp; + +import org.junit.Test; +import org.onosproject.bgpio.types.attr.BgpAttrNodeFlagBitTlv; + +import com.google.common.testing.EqualsTester; + +/** + * Test for BGP attribute node flag. + */ +public class BgpAttrNodeFlagBitTlvTest { + + private final boolean bOverloadBit = true; + private final boolean bAttachedBit = true; + private final boolean bExternalBit = true; + private final boolean bABRBit = true; + + private final boolean bOverloadBit1 = false; + private final boolean bAttachedBit1 = false; + private final boolean bExternalBit1 = false; + private final boolean bABRBit1 = false; + + private final BgpAttrNodeFlagBitTlv data = BgpAttrNodeFlagBitTlv + .of(bOverloadBit, bAttachedBit, bExternalBit, bABRBit); + private final BgpAttrNodeFlagBitTlv sameAsData = BgpAttrNodeFlagBitTlv + .of(bOverloadBit, bAttachedBit, bExternalBit, bABRBit); + private final BgpAttrNodeFlagBitTlv diffData = BgpAttrNodeFlagBitTlv + .of(bOverloadBit1, bAttachedBit1, bExternalBit1, bABRBit1); + + @Test + public void basics() { + + new EqualsTester().addEqualityGroup(data, sameAsData) + .addEqualityGroup(diffData).testEquals(); + } +} \ No newline at end of file diff --git a/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpAttrRouterIdV6Test.java b/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpAttrRouterIdV6Test.java new file mode 100644 index 00000000..72ca5dbf --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpAttrRouterIdV6Test.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.bgp; + +import org.junit.Test; +import org.onlab.packet.Ip6Address; +import org.onosproject.bgpio.types.attr.BgpAttrRouterIdV6; + +import com.google.common.testing.EqualsTester; + +/** + * Test for BGP attribute node router ID. + */ +public class BgpAttrRouterIdV6Test { + + private final short sType = 1; + private final Ip6Address ip6RouterId = Ip6Address + .valueOf("2001:0db8:0a0b:12f0:0000:0000:0000:0001"); + + private final short sType1 = 2; + private final Ip6Address ip6RouterId1 = Ip6Address + .valueOf("2004:0db8:0a0b:12f0:0000:0000:0000:0004"); + + private final BgpAttrRouterIdV6 data = BgpAttrRouterIdV6.of(ip6RouterId, + sType); + private final BgpAttrRouterIdV6 sameAsData = BgpAttrRouterIdV6 + .of(ip6RouterId, sType); + private final BgpAttrRouterIdV6 diffData = BgpAttrRouterIdV6 + .of(ip6RouterId1, sType1); + + @Test + public void basics() { + + new EqualsTester().addEqualityGroup(data, sameAsData) + .addEqualityGroup(diffData).testEquals(); + } +} \ No newline at end of file diff --git a/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpLinkAttrIgpMetricTest.java b/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpLinkAttrIgpMetricTest.java new file mode 100644 index 00000000..32280a79 --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpLinkAttrIgpMetricTest.java @@ -0,0 +1,44 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.bgp; + +import org.junit.Test; +import org.onosproject.bgpio.types.attr.BgpLinkAttrIgpMetric; + +import com.google.common.testing.EqualsTester; + +/** + * Test for BGP link IGP metric attribute. + */ +public class BgpLinkAttrIgpMetricTest { + private final int val = 0x010203; + private final int valLen = 3; + private final int val1 = 0x01020304; + private final int val1Len = 4; + + private final BgpLinkAttrIgpMetric data = BgpLinkAttrIgpMetric.of(val, + valLen); + private final BgpLinkAttrIgpMetric sameAsData = BgpLinkAttrIgpMetric + .of(val, valLen); + private final BgpLinkAttrIgpMetric diffData = BgpLinkAttrIgpMetric + .of(val1, val1Len); + + @Test + public void basics() { + new EqualsTester().addEqualityGroup(data, sameAsData) + .addEqualityGroup(diffData).testEquals(); + } +} \ No newline at end of file diff --git a/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpLinkAttrProtectionTypeTest.java b/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpLinkAttrProtectionTypeTest.java new file mode 100644 index 00000000..89f97a83 --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpLinkAttrProtectionTypeTest.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.bgp; + +import org.junit.Test; +import org.onosproject.bgpio.types.attr.BgpLinkAttrProtectionType; + +import com.google.common.testing.EqualsTester; + +/** + * Test for MPLS protocol mask attribute. + */ +public class BgpLinkAttrProtectionTypeTest { + boolean bExtraTraffic = true; + boolean bUnprotected = true; + boolean bShared = true; + boolean bDedOneIstoOne = true; + boolean bDedOnePlusOne = true; + boolean bEnhanced = true; + + boolean bExtraTraffic1 = false; + boolean bUnprotected1 = false; + boolean bShared1 = false; + boolean bDedOneIstoOne1 = false; + boolean bDedOnePlusOne1 = false; + boolean bEnhanced1 = false; + + private final BgpLinkAttrProtectionType data = BgpLinkAttrProtectionType + .of(bExtraTraffic, bUnprotected, bShared, bDedOneIstoOne, + bDedOnePlusOne, bEnhanced); + private final BgpLinkAttrProtectionType sameAsData = BgpLinkAttrProtectionType + .of(bExtraTraffic, bUnprotected, bShared, bDedOneIstoOne, + bDedOnePlusOne, bEnhanced); + private final BgpLinkAttrProtectionType diffData = BgpLinkAttrProtectionType + .of(bExtraTraffic1, bUnprotected1, bShared1, bDedOneIstoOne1, + bDedOnePlusOne1, bEnhanced1); + + @Test + public void basics() { + + new EqualsTester().addEqualityGroup(data, sameAsData) + .addEqualityGroup(diffData).testEquals(); + } +} \ No newline at end of file diff --git a/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpPrefixAttrOspfFwdAddrTest.java b/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpPrefixAttrOspfFwdAddrTest.java new file mode 100644 index 00000000..f736bead --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpPrefixAttrOspfFwdAddrTest.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; + +import org.junit.Test; +import org.onlab.packet.Ip4Address; +import org.onlab.packet.Ip6Address; +import org.onosproject.bgpio.types.attr.BgpPrefixAttrOspfFwdAddr; + +import com.google.common.testing.EqualsTester; + +/** + * Test for BGP prefix metric attribute. + */ +public class BgpPrefixAttrOspfFwdAddrTest { + + private final short lsAttrLength = 4; + private final Ip4Address ip4RouterId = Ip4Address.valueOf("192.168.1.1"); + private final Ip6Address ip6RouterId = Ip6Address + .valueOf("2001:0db8:0a0b:12f0:0000:0000:0000:0001"); + + private final short lsAttrLength1 = 16; + private final Ip4Address ip4RouterId1 = Ip4Address.valueOf("192.168.1.2"); + private final Ip6Address ip6RouterId1 = Ip6Address + .valueOf("1002:0db8:0a0b:12f0:0000:0000:0000:0002"); + + private final BgpPrefixAttrOspfFwdAddr data = BgpPrefixAttrOspfFwdAddr + .of(lsAttrLength, ip4RouterId, ip6RouterId); + private final BgpPrefixAttrOspfFwdAddr sameAsData = BgpPrefixAttrOspfFwdAddr + .of(lsAttrLength, ip4RouterId, ip6RouterId); + private final BgpPrefixAttrOspfFwdAddr diffData = BgpPrefixAttrOspfFwdAddr + .of(lsAttrLength1, ip4RouterId1, ip6RouterId1); + + @Test + public void basics() { + new EqualsTester().addEqualityGroup(data, sameAsData) + .addEqualityGroup(diffData).testEquals(); + } +} \ No newline at end of file diff --git a/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/NextHopTest.java b/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/NextHopTest.java new file mode 100755 index 00000000..109197bb --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/NextHopTest.java @@ -0,0 +1,41 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.bgp; + +import org.junit.Test; +import org.onlab.packet.Ip4Address; +import org.onosproject.bgpio.types.NextHop; + +import com.google.common.testing.EqualsTester; + +/** + * Test for NextHop BGP Path Attribute. + */ +public class NextHopTest { + private final Ip4Address value1 = Ip4Address.valueOf("12.12.12.12"); + private final Ip4Address value2 = Ip4Address.valueOf("12.12.12.13"); + private final NextHop attr1 = new NextHop(value1); + private final NextHop sameAsAttr1 = new NextHop(value1); + private final NextHop attr2 = new NextHop(value2); + + @Test + public void basics() { + new EqualsTester() + .addEqualityGroup(attr1, sameAsAttr1) + .addEqualityGroup(attr2) + .testEquals(); + } +} \ No newline at end of file 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 1df2f049..03d25cee 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 @@ -71,7 +71,10 @@ public final class Comparators { public static final Comparator FLOW_RULE_COMPARATOR = new Comparator() { @Override public int compare(FlowRule f1, FlowRule f2) { - return Long.valueOf(f1.id().value()).compareTo(f2.id().value()); + int tableCompare = Integer.valueOf(f1.tableId()).compareTo(f2.tableId()); + return (tableCompare == 0) + ? Long.valueOf(f1.id().value()).compareTo(f2.id().value()) + : tableCompare; } }; diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AddOpticalIntentCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AddOpticalIntentCommand.java index 57c41009..1049d90d 100644 --- a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AddOpticalIntentCommand.java +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AddOpticalIntentCommand.java @@ -44,12 +44,12 @@ public class AddOpticalIntentCommand extends ConnectivityIntentCommand { @Argument(index = 0, name = "ingressDevice", description = "Ingress Device/Port Description", required = true, multiValued = false) - String ingressDeviceString = null; + String ingressDeviceString = ""; @Argument(index = 1, name = "egressDevice", description = "Egress Device/Port Description", required = true, multiValued = false) - String egressDeviceString = null; + String egressDeviceString = ""; @Option(name = "-b", aliases = "--bidirectional", description = "If this argument is passed the optical link created will be bidirectional, " + @@ -65,7 +65,6 @@ public class AddOpticalIntentCommand extends ConnectivityIntentCommand { "Connect point must be in \"deviceUri/portNumber\" format"); DeviceId deviceId = DeviceId.deviceId(splitted[0]); - DeviceService deviceService = get(DeviceService.class); List ports = deviceService.getPorts(deviceId); @@ -87,7 +86,8 @@ public class AddOpticalIntentCommand extends ConnectivityIntentCommand { ConnectPoint egress = createConnectPoint(egressDeviceString); if (ingress == null || egress == null) { - print("Could not create optical intent"); + print("Invalid endpoint(s); could not create optical intent"); + return; } DeviceService deviceService = get(DeviceService.class); diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/FlowsListCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/FlowsListCommand.java index de84f519..331cca17 100644 --- a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/FlowsListCommand.java +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/FlowsListCommand.java @@ -123,8 +123,14 @@ public class FlowsListCommand extends AbstractShellCommand { if (state != null && !state.equals("any")) { s = FlowEntryState.valueOf(state.toUpperCase()); } - Iterable devices = uri == null ? deviceService.getDevices() : - Collections.singletonList(deviceService.getDevice(DeviceId.deviceId(uri))); + Iterable devices = null; + if (uri == null) { + devices = deviceService.getDevices(); + } else { + Device dev = deviceService.getDevice(DeviceId.deviceId(uri)); + devices = (dev == null) ? deviceService.getDevices() + : Collections.singletonList(dev); + } for (Device d : devices) { if (s == null) { rules = newArrayList(service.getFlowEntries(d.id())); diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/GroupsListCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/GroupsListCommand.java index afbcab80..b10621de 100644 --- a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/GroupsListCommand.java +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/GroupsListCommand.java @@ -46,7 +46,7 @@ import static com.google.common.collect.Lists.newArrayList; public class GroupsListCommand extends AbstractShellCommand { private static final String FORMAT = - " id=%s, state=%s, bytes=%s, packets=%s, appId=%s"; + " id=%s, state=%s, type=%s, bytes=%s, packets=%s, appId=%s"; private static final String BUCKET_FORMAT = " id=%s, bucket=%s, bytes=%s, packets=%s, actions=%s"; @@ -121,7 +121,7 @@ public class GroupsListCommand extends AbstractShellCommand { private void printGroups(DeviceId deviceId, List groups) { print("deviceId=%s", deviceId); for (Group group : groups) { - print(FORMAT, group.id().id(), group.state(), + print(FORMAT, group.id().id(), group.state(), group.type(), group.bytes(), group.packets(), group.appId().name()); int i = 0; for (GroupBucket bucket:group.buckets().buckets()) { 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 cf76febe..9bd5dd9f 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 @@ -19,7 +19,6 @@ - diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterAdminService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterAdminService.java index 5f2b5fff..47944874 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterAdminService.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterAdminService.java @@ -30,9 +30,8 @@ public interface ClusterAdminService { * instance. * * @param nodes set of nodes that form the cluster - * @param ipPrefix IP address prefix, e.g. 10.0.1.* */ - void formCluster(Set nodes, String ipPrefix); + void formCluster(Set nodes); /** * Adds a new controller node to the cluster. diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterDefinitionService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterDefinitionService.java deleted file mode 100644 index 1ee78b15..00000000 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterDefinitionService.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.onosproject.cluster; - -import java.util.Set; - -/** - * Service for obtaining the static definition of a controller cluster. - */ -public interface ClusterDefinitionService { - - /** - * Returns the local controller node. - * @return local controller node - */ - ControllerNode localNode(); - - /** - * Returns the set of seed nodes that should be used for discovering other members - * of the cluster. - * @return set of seed controller nodes - */ - Set seedNodes(); - - /** - * Forms cluster configuration based on the specified set of node - * information. Assumes subsequent restart for the new configuration to - * take hold. - * - * @param nodes set of nodes that form the cluster - * @param ipPrefix IP address prefix, e.g. 10.0.1.* - */ - void formCluster(Set nodes, String ipPrefix); -} \ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadata.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadata.java new file mode 100644 index 00000000..e1eacfee --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadata.java @@ -0,0 +1,185 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.cluster; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Set; +import java.util.stream.Collectors; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Verify.verifyNotNull; +import static com.google.common.base.Verify.verify; + +import com.google.common.base.MoreObjects; +import com.google.common.collect.Collections2; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; + +/** + * Cluster metadata. + *

+ * Metadata specifies the attributes that define a ONOS cluster and comprises the collection + * of {@link org.onosproject.cluster.ControllerNode nodes} and the collection of data + * {@link org.onosproject.cluster.Partition partitions}. + */ +public final class ClusterMetadata { + + private String name; + private Set nodes; + private Set partitions; + + /** + * Returns a new cluster metadata builder. + * @return The cluster metadata builder. + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Returns the name of the cluster. + * + * @return cluster name + */ + public String getName() { + return this.name; + } + + /** + * Returns the collection of {@link org.onosproject.cluster.ControllerNode nodes} that make up the cluster. + * @return cluster nodes + */ + public Collection getNodes() { + return this.nodes; + } + + /** + * Returns the collection of data {@link org.onosproject.cluster.Partition partitions} that make up the cluster. + * @return collection of partitions. + */ + public Collection getPartitions() { + return this.partitions; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(ClusterMetadata.class) + .add("name", name) + .add("nodes", nodes) + .add("partitions", partitions) + .toString(); + } + + @Override + public int hashCode() { + return Arrays.deepHashCode(new Object[] {name, nodes, partitions}); + } + + /* + * Provide a deep quality check of the meta data (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object object) { + + if (!ClusterMetadata.class.isInstance(object)) { + return false; + } + ClusterMetadata that = (ClusterMetadata) object; + + if (!this.name.equals(that.name) || this.nodes.size() != that.nodes.size() + || this.partitions.size() != that.partitions.size()) { + return false; + } + + return Sets.symmetricDifference(this.nodes, that.nodes).isEmpty() + && Sets.symmetricDifference(this.partitions, that.partitions).isEmpty(); + } + + /** + * Builder for a {@link ClusterMetadata} instance. + */ + public static class Builder { + + private final ClusterMetadata metadata; + + public Builder() { + metadata = new ClusterMetadata(); + } + + /** + * Sets the cluster name, returning the cluster metadata builder for method chaining. + * @param name cluster name + * @return this cluster metadata builder + */ + public Builder withName(String name) { + metadata.name = checkNotNull(name); + return this; + } + + /** + * Sets the collection of cluster nodes, returning the cluster metadata builder for method chaining. + * @param controllerNodes collection of cluster nodes + * @return this cluster metadata builder + */ + public Builder withControllerNodes(Collection controllerNodes) { + metadata.nodes = ImmutableSet.copyOf(checkNotNull(controllerNodes)); + return this; + } + + /** + * Sets the collection of data partitions, returning the cluster metadata builder for method chaining. + * @param partitions collection of partitions + * @return this cluster metadata builder + */ + public Builder withPartitions(Collection partitions) { + metadata.partitions = ImmutableSet.copyOf(checkNotNull(partitions)); + return this; + } + + /** + * Builds the cluster metadata. + * @return cluster metadata + * @throws com.google.common.base.VerifyException VerifyException if the metadata is misconfigured + */ + public ClusterMetadata build() { + verifyMetadata(); + return metadata; + } + + /** + * Validates the constructed metadata for semantic correctness. + * @throws VerifyException if the metadata is misconfigured. + */ + private void verifyMetadata() { + verifyNotNull(metadata.getName(), "Cluster name must be specified"); + verifyNotNull(metadata.getNodes(), "Cluster nodes must be specified"); + verifyNotNull(metadata.getPartitions(), "Cluster partitions must be specified"); + verify(!metadata.getNodes().isEmpty(), "Cluster nodes must not be empty"); + verify(!metadata.getPartitions().isEmpty(), "Cluster nodes must not be empty"); + + // verify that partitions are constituted from valid cluster nodes. + boolean validPartitions = Collections2.transform(metadata.getNodes(), ControllerNode::id) + .containsAll(metadata.getPartitions() + .stream() + .flatMap(r -> r.getMembers().stream()) + .collect(Collectors.toSet())); + verify(validPartitions, "Partition locations must be valid cluster nodes"); + } + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataEvent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataEvent.java new file mode 100644 index 00000000..a0f461c4 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataEvent.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.cluster; + +import org.onosproject.event.AbstractEvent; + +/** + * Describes a cluster metadata event. + */ +public class ClusterMetadataEvent extends AbstractEvent { + + /** + * Type of cluster metadata events. + */ + public enum Type { + /** + * Signifies that the cluster metadata has changed. + */ + METADATA_CHANGED, + } + + /** + * Creates an event of a given type and for the specified metadata and the + * current time. + * + * @param type cluster metadata event type + * @param metadata cluster metadata subject + */ + public ClusterMetadataEvent(Type type, ClusterMetadata metadata) { + super(type, metadata); + } + + /** + * Creates an event of a given type and for the specified metadata and time. + * + * @param type cluster metadata event type + * @param metadata cluster metadata subject + * @param time occurrence time + */ + public ClusterMetadataEvent(Type type, ClusterMetadata metadata, long time) { + super(type, metadata, time); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataEventListener.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataEventListener.java new file mode 100644 index 00000000..fdfaeed0 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataEventListener.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.cluster; + +import org.onosproject.event.EventListener; + +/** + * Entity capable of receiving cluster metadata related events. + */ +public interface ClusterMetadataEventListener extends EventListener { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataService.java new file mode 100644 index 00000000..25a6df63 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataService.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.cluster; + +/** + * Service for obtaining metadata information about the cluster. + */ +public interface ClusterMetadataService { + + /** + * Returns the current cluster metadata. + * @return cluster metadata + */ + ClusterMetadata getClusterMetadata(); + + /** + * Updates the cluster metadata. + * @param metadata new metadata + */ + void setClusterMetadata(ClusterMetadata metadata); + + /** + * Returns the local controller node representing this instance. + * @return local controller node + */ + ControllerNode getLocalNode(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataStore.java new file mode 100644 index 00000000..7e83b5b5 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataStore.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.cluster; + +import java.util.Collection; + +import org.onosproject.store.Store; +import org.onosproject.store.service.Versioned; + +/** + * Manages persistence of cluster metadata; not intended for direct use. + */ +public interface ClusterMetadataStore extends Store { + + /** + * Returns the cluster metadata. + *

+ * The returned metadata is versioned to aid determining if a metadata instance is more recent than another. + * @return cluster metadata + */ + Versioned getClusterMetadata(); + + /** + * Updates the cluster metadata. + * @param metadata new metadata value + */ + void setClusterMetadata(ClusterMetadata metadata); + + // TODO: The below methods should move to a separate store interface that is responsible for + // tracking cluster partition operational state. + + /** + * Sets a controller node as an active member of a partition. + *

+ * Active members are those replicas that are up to speed with the rest of the system and are + * usually capable of participating in the replica state management activities in accordance with + * the data consistency and replication protocol in use. + * @param partitionId partition identifier + * @param nodeId id of controller node + */ + void setActiveReplica(String partitionId, NodeId nodeId); + + /** + * Removes a controller node as an active member for a partition. + *

+ * Active members are those replicas that are up to speed with the rest of the system and are + * usually capable of participating in the replica state management activities in accordance with + * the data consistency and replication protocol in use. + * @param partitionId partition identifier + * @param nodeId id of controller node + */ + void unsetActiveReplica(String partitionId, NodeId nodeId); + + /** + * Returns the collection of controller nodes that are the active replicas for a partition. + *

+ * Active members are those replicas that are up to speed with the rest of the system and are + * usually capable of participating in the replica state management activities in accordance with + * the data consistency and replication protocol in use. + * @param partitionId partition identifier + * @return identifiers of controller nodes that are the active replicas + */ + Collection getActiveReplicas(String partitionId); +} \ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataStoreDelegate.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataStoreDelegate.java new file mode 100644 index 00000000..b56b7a24 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataStoreDelegate.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.cluster; + +import org.onosproject.store.StoreDelegate; + +/** + * Cluster metadata store delegate abstraction. + */ +public interface ClusterMetadataStoreDelegate extends StoreDelegate { +} \ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/NodeId.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/NodeId.java index 68b490f2..6cfb42c7 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/NodeId.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/NodeId.java @@ -20,7 +20,7 @@ import java.util.Objects; /** * Controller cluster identity. */ -public class NodeId { +public class NodeId implements Comparable { private final String id; @@ -55,4 +55,9 @@ public class NodeId { return id; } + @Override + public int compareTo(NodeId that) { + return this.id.compareTo(that.id); + } + } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/Partition.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/Partition.java new file mode 100644 index 00000000..1eca4aeb --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/Partition.java @@ -0,0 +1,91 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.cluster; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Set; + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A data partition. + *

+ * Partition represents a slice of the data space and is made up of a collection + * of {@link org.onosproject.cluster.ControllerNode nodes} + * that all maintain copies of this data. + */ +public class Partition { + + private final String name; + private final Set members; + + private Partition() { + name = null; + members = null; + } + + public Partition(String name, Collection members) { + this.name = checkNotNull(name); + this.members = ImmutableSet.copyOf(checkNotNull(members)); + } + + /** + * Returns the partition name. + *

+ * Each partition is identified by a unique name. + * @return partition name + */ + public String getName() { + return this.name; + } + + /** + * Returns the collection of controller node identifiers that make up this partition. + * @return collection of controller node identifiers + */ + public Collection getMembers() { + return this.members; + } + + @Override + public int hashCode() { + return Arrays.deepHashCode(new Object[] {name, members}); + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + + if (other == null || !Partition.class.isInstance(other)) { + return false; + } + + Partition that = (Partition) other; + + if (!this.name.equals(that.name) || (this.members == null && that.members != null) + || (this.members != null && that.members == null) || this.members.size() != that.members.size()) { + return false; + } + + return Sets.symmetricDifference(this.members, that.members).isEmpty(); + } +} \ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/BridgeConfig.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/BridgeConfig.java index 7f157e95..e3d6993c 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/BridgeConfig.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/BridgeConfig.java @@ -35,6 +35,17 @@ public interface BridgeConfig extends HandlerBehaviour { */ void addBridge(BridgeName bridgeName); + /** + * Adds a bridge with given bridge name and dpid, and sets the controller + * of the bridge with given controllers. + * + * @param bridgeName bridge name + * @param dpid dpid + * @param controllers list of controller + * @return true if succeeds, fail otherwise + */ + boolean addBridge(BridgeName bridgeName, String dpid, List controllers); + /** * Remove a bridge. * diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ExtensionResolver.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ExtensionResolver.java new file mode 100644 index 00000000..54cbc7ac --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ExtensionResolver.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.net.behaviour; + +import com.google.common.annotations.Beta; +import org.onosproject.net.driver.HandlerBehaviour; +import org.onosproject.net.flow.instructions.ExtensionInstruction; +import org.onosproject.net.flow.instructions.ExtensionType; + +/** + * Provides access to the extension implemented by this driver. + */ +@Beta +public interface ExtensionResolver extends HandlerBehaviour { + + /** + * Gets an extension instruction instance of the specified type, if supported + * by the driver. + * + * @param type type of extension to get + * @return extension instruction + * @throws UnsupportedOperationException if the extension type is not + * supported by this driver + */ + ExtensionInstruction getExtensionInstruction(ExtensionType type); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/TunnelConfig.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/TunnelConfig.java index 7e79a57e..e3b4c198 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/TunnelConfig.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/TunnelConfig.java @@ -31,6 +31,15 @@ public interface TunnelConfig extends HandlerBehaviour { */ void createTunnel(TunnelDescription tunnel); + /** + * Creates a tunnel interface on a given bridge of this device. + * + * @param bridgeName bridge name + * @param tunnel tunnel description + * @return true if succeeds, false otherwise + */ + boolean createTunnelInterface(BridgeName bridgeName, TunnelDescription tunnel); + /** * Removes a tunnel on this device. * 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 4416456c..453a7648 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 @@ -15,8 +15,14 @@ */ package org.onosproject.net.flow; -import com.google.common.base.MoreObjects; -import com.google.common.collect.ImmutableSet; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.TreeSet; + import org.onlab.packet.Ip6Address; import org.onlab.packet.IpPrefix; import org.onlab.packet.MacAddress; @@ -27,13 +33,8 @@ import org.onosproject.net.PortNumber; import org.onosproject.net.flow.criteria.Criteria; import org.onosproject.net.flow.criteria.Criterion; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.TreeSet; +import com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableSet; /** * Default traffic selector implementation. 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 6174cef6..6beeecc9 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 @@ -15,9 +15,11 @@ */ package org.onosproject.net.flow; -import com.google.common.base.MoreObjects; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.List; +import java.util.Objects; + import org.onlab.packet.EthType; import org.onlab.packet.IpAddress; import org.onlab.packet.MacAddress; @@ -25,16 +27,17 @@ import org.onlab.packet.MplsLabel; import org.onlab.packet.TpPort; import org.onlab.packet.VlanId; import org.onosproject.core.GroupId; +import org.onosproject.net.DeviceId; import org.onosproject.net.IndexedLambda; import org.onosproject.net.PortNumber; +import org.onosproject.net.flow.instructions.ExtensionInstruction; import org.onosproject.net.flow.instructions.Instruction; import org.onosproject.net.flow.instructions.Instructions; import org.onosproject.net.meter.MeterId; -import java.util.List; -import java.util.Objects; - -import static com.google.common.base.Preconditions.checkNotNull; +import com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; /** * Default traffic treatment implementation. @@ -239,9 +242,11 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { case GROUP: case QUEUE: case L0MODIFICATION: + case L1MODIFICATION: case L2MODIFICATION: case L3MODIFICATION: case L4MODIFICATION: + case EXTENSION: current.add(instruction); break; case TABLE: @@ -478,6 +483,12 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { return add(Instructions.modUdpDst(port)); } + @Override + public TrafficTreatment.Builder extension(ExtensionInstruction extension, + DeviceId deviceId) { + return add(Instructions.extension(extension, deviceId)); + } + @Override public TrafficTreatment build() { if (deferred.size() == 0 && immediate.size() == 0 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 c7fe8b85..b14ab99c 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 @@ -15,6 +15,8 @@ */ package org.onosproject.net.flow; +import java.util.List; + import org.onlab.packet.EthType; import org.onlab.packet.IpAddress; import org.onlab.packet.MacAddress; @@ -22,13 +24,13 @@ import org.onlab.packet.MplsLabel; import org.onlab.packet.TpPort; import org.onlab.packet.VlanId; import org.onosproject.core.GroupId; +import org.onosproject.net.DeviceId; import org.onosproject.net.PortNumber; +import org.onosproject.net.flow.instructions.ExtensionInstruction; import org.onosproject.net.flow.instructions.Instruction; import org.onosproject.net.flow.instructions.Instructions; import org.onosproject.net.meter.MeterId; -import java.util.List; - /** * Abstraction of network traffic treatment. */ @@ -412,6 +414,15 @@ public interface TrafficTreatment { */ Builder setUdpDst(TpPort port); + /** + * Uses an extension treatment. + * + * @param extension extension treatment + * @param deviceId device ID + * @return a treatment builder + */ + Builder extension(ExtensionInstruction extension, DeviceId deviceId); + /** * Builds an immutable traffic treatment descriptor. *

diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/Treatment.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/Treatment.java deleted file mode 100644 index a77079ce..00000000 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/Treatment.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.onosproject.net.flow; - -import org.onosproject.net.PortNumber; - -/** - * Abstraction of different kinds of treatment that can be applied to an - * outbound packet. - */ -public interface Treatment { - - // TODO: implement these later: modifications, group - // TODO: elsewhere provide factory methods for some default treatments - - /** - * Returns the port number where the packet should be emitted. - * - * @return output port number - */ - PortNumber output(); - -} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/AbstractExtensionInstruction.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/AbstractExtensionInstruction.java new file mode 100644 index 00000000..9f22f888 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/AbstractExtensionInstruction.java @@ -0,0 +1,71 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.net.flow.instructions; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; + +/** + * Abstract implementation of the set/get property methods of ExtensionInstruction. + */ +public abstract class AbstractExtensionInstruction implements ExtensionInstruction { + + private static final String INVALID_KEY = "Invalid property key: "; + private static final String INVALID_TYPE = "Given type does not match field type: "; + + @Override + public void setPropertyValue(String key, T value) throws ExtensionPropertyException { + Class clazz = this.getClass(); + try { + Field field = clazz.getDeclaredField(key); + field.setAccessible(true); + field.set(this, value); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new ExtensionPropertyException(INVALID_KEY + key); + } + } + + @Override + public T getPropertyValue(String key) throws ExtensionPropertyException { + Class clazz = this.getClass(); + try { + Field field = clazz.getDeclaredField(key); + field.setAccessible(true); + @SuppressWarnings("unchecked") + T result = (T) field.get(this); + return result; + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new ExtensionPropertyException(INVALID_KEY + key); + } catch (ClassCastException e) { + throw new ExtensionPropertyException(INVALID_TYPE + key); + } + } + + @Override + public List getProperties() { + Class clazz = this.getClass(); + + List fields = new ArrayList<>(); + + for (Field field : clazz.getDeclaredFields()) { + fields.add(field.getName()); + } + + return fields; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionInstruction.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionInstruction.java new file mode 100644 index 00000000..89e0cc5e --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionInstruction.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.net.flow.instructions; + +import java.util.List; + +/** + * An extensible instruction type. + */ +public interface ExtensionInstruction { + + /** + * Gets the type of the extension instruction. + * + * @return type + */ + ExtensionType type(); + + /** + * Sets a property on the extension instruction. + * + * @param key property key + * @param value value to set for the given key + * @param class of the value + * @throws ExtensionPropertyException if the given key is not a valid + * property on this extension instruction + */ + void setPropertyValue(String key, T value) throws ExtensionPropertyException; + + /** + * Gets a property value of an extension instruction. + * + * @param key property key + * @param class of the value + * @return value of the property + * @throws ExtensionPropertyException if the given key is not a valid + * property on this extension instruction + */ + T getPropertyValue(String key) throws ExtensionPropertyException; + + /** + * Gets a list of all properties on the extension instruction. + * + * @return list of properties + */ + List getProperties(); + + /** + * Serialize the extension instruction to a byte array. + * + * @return byte array + */ + byte[] serialize(); + + /** + * Deserialize the extension instruction from a byte array. The properties + * of this object will be overwritten with the data in the byte array. + * + * @param data input byte array + */ + void deserialize(byte[] data); + + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionPropertyException.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionPropertyException.java new file mode 100644 index 00000000..5750d09e --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionPropertyException.java @@ -0,0 +1,32 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.net.flow.instructions; + +/** + * Exception indicating there was an error while setting/getting an extension + * instruction property. + */ +public class ExtensionPropertyException extends Exception { + + public ExtensionPropertyException(String message) { + super(message); + } + + public ExtensionPropertyException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionType.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionType.java new file mode 100644 index 00000000..747a85b5 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionType.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.net.flow.instructions; + +import com.google.common.annotations.Beta; +import com.google.common.base.MoreObjects; + +import java.util.Objects; + +/** + * Type of extension instructions. + */ +@Beta +public final class ExtensionType { + + /** + * A list of well-known named extension instruction type codes. + */ + public enum ExtensionTypes { + // TODO fix type numbers to include experimenter id + NICIRA_SET_TUNNEL_DST(31); + + private ExtensionType type; + + /** + * Creates a new named extension instruction type. + * + * @param type type code + */ + ExtensionTypes(int type) { + this.type = new ExtensionType(type); + } + + /** + * Gets the extension type object for this named type code. + * + * @return extension type object + */ + public ExtensionType type() { + return type; + } + } + + private final int type; + + /** + * Creates an extension type with the given int type code. + * + * @param type type code + */ + public ExtensionType(int type) { + this.type = type; + } + + @Override + public int hashCode() { + return Objects.hash(type); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ExtensionType) { + final ExtensionType that = (ExtensionType) obj; + return this.type == that.type; + } + return false; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(ExtensionType.class) + .add("type", type) + .toString(); + } +} 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 2f6a1cc1..31ad80c5 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 @@ -92,7 +92,12 @@ public interface Instruction { /** * Signifies that the traffic should be modified in L4 way. */ - L4MODIFICATION + L4MODIFICATION, + + /** + * Signifies that an extension instruction will be used. + */ + EXTENSION } /** 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 8868bf7c..aad407c8 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 @@ -22,6 +22,7 @@ import org.onlab.packet.MplsLabel; import org.onlab.packet.TpPort; import org.onlab.packet.VlanId; import org.onosproject.core.GroupId; +import org.onosproject.net.DeviceId; import org.onosproject.net.IndexedLambda; import org.onosproject.net.Lambda; import org.onosproject.net.OchSignal; @@ -479,6 +480,20 @@ public final class Instructions { return new ModTransportPortInstruction(L4SubType.UDP_DST, port); } + /** + * Creates an extension instruction. + * + * @param extension extension instruction + * @param deviceId device ID + * @return extension instruction + */ + public static ExtensionInstructionWrapper extension(ExtensionInstruction extension, + DeviceId deviceId) { + checkNotNull(extension, "Extension instruction cannot be null"); + checkNotNull(deviceId, "Device ID cannot be null"); + return new ExtensionInstructionWrapper(extension, deviceId); + } + /** * Drop instruction. */ @@ -820,6 +835,59 @@ public final class Instructions { } } + /** + * Extension instruction. + */ + public static class ExtensionInstructionWrapper implements Instruction { + private final ExtensionInstruction extensionInstruction; + private final DeviceId deviceId; + + ExtensionInstructionWrapper(ExtensionInstruction extension, DeviceId deviceId) { + extensionInstruction = extension; + this.deviceId = deviceId; + } + + public ExtensionInstruction extensionInstruction() { + return extensionInstruction; + } + + public DeviceId deviceId() { + return deviceId; + } + + @Override + public Type type() { + return Type.EXTENSION; + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("extension", extensionInstruction) + .add("deviceId", deviceId) + .toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), extensionInstruction, deviceId); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ExtensionInstructionWrapper) { + ExtensionInstructionWrapper that = (ExtensionInstructionWrapper) obj; + return Objects.equals(extensionInstruction, that.extensionInstruction) + && Objects.equals(deviceId, that.deviceId); + + } + return false; + } + } + } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultFilteringObjective.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultFilteringObjective.java index 7b5924fb..06305bf7 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultFilteringObjective.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultFilteringObjective.java @@ -18,6 +18,7 @@ package org.onosproject.net.flowobjective; import com.google.common.annotations.Beta; import com.google.common.collect.ImmutableList; import org.onosproject.core.ApplicationId; +import org.onosproject.net.flow.TrafficTreatment; import org.onosproject.net.flow.criteria.Criteria; import org.onosproject.net.flow.criteria.Criterion; @@ -46,6 +47,7 @@ public final class DefaultFilteringObjective implements FilteringObjective { private final int id; private final Operation op; private final Optional context; + private final TrafficTreatment meta; private DefaultFilteringObjective(Builder builder) { this.key = builder.key; @@ -57,6 +59,7 @@ public final class DefaultFilteringObjective implements FilteringObjective { this.conditions = builder.conditions; this.op = builder.op; this.context = Optional.ofNullable(builder.context); + this.meta = builder.meta; this.id = Objects.hash(type, key, conditions, permanent, timeout, appId, priority); @@ -82,6 +85,12 @@ public final class DefaultFilteringObjective implements FilteringObjective { return id; } + @Override + public TrafficTreatment meta() { + return meta; + } + + @Override public int priority() { return priority; @@ -135,6 +144,7 @@ public final class DefaultFilteringObjective implements FilteringObjective { private List conditions; private Operation op; private ObjectiveContext context; + private TrafficTreatment meta; @Override public Builder withKey(Criterion key) { @@ -185,6 +195,12 @@ public final class DefaultFilteringObjective implements FilteringObjective { return this; } + @Override + public Builder setMeta(TrafficTreatment treatment) { + this.meta = treatment; + return this; + } + @Override public FilteringObjective add() { conditions = listBuilder.build(); diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/FilteringObjective.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/FilteringObjective.java index 58304571..29257c61 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/FilteringObjective.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/FilteringObjective.java @@ -17,49 +17,54 @@ package org.onosproject.net.flowobjective; import com.google.common.annotations.Beta; import org.onosproject.core.ApplicationId; +import org.onosproject.net.flow.TrafficTreatment; import org.onosproject.net.flow.criteria.Criterion; import java.util.Collection; /** * Represents a filtering flow objective. Each filtering flow objective - * is made up of a key (criterion) to a set of criteria. Using this information - * a pipeline aware driver will decide how this objective should be mapped - * to the specific device pipeline. For example, consider the following - * filtering objective: - * - * portX -> {MAC1, IP1, MAC2} - * - * The driver could decide to pass L3 packet to the L3 table and L2 packets to - * the L2 table for packets arriving on portX. - * - * Filtering objectives do not only represent what should be permitted into the - * pipeline but can also be used to deny or drop unwanted packets by specifying - * the appropriate type of filtering objective. It is also important to note - * that submitting a filtering objective does not necessarily result in rules - * programmed at the switch, the driver is free to decide when these rules are - * programmed. For example, a filtering rule may only be programmed once a - * corresponding forwarding objective has been received. + * is made up of a key (typically a PortCriterion) mapped to a set of criteria. + * Using this information, a pipeline aware driver will decide how this objective + * should be mapped to the device specific pipeline-tables in order to satisfy the + * filtering condition. For example, consider the following PERMIT filtering + * objective: + *

+ * portX -> {MAC1, VLAN1} + *

+ * The driver could decide to pass packets to the MAC table or VLAN or PORT + * tables to ensure that only those packets arriving with the correct dst MAC + * and VLAN ids from Port X are allowed into the pipeline. + *

+ * Filtering objectives of type PERMIT allow packets that match the key:criteria + * to enter the pipeline. As a result, the implication is that packets that don't + * match are automatically denied (dropped). + *

+ * Filtering objectives of type DENY, are used to deny packets that would + * otherwise be permitted and forwarded through the pipeline (ie. those packets + * that make it through the PERMIT filters). */ @Beta public interface FilteringObjective extends Objective { enum Type { /** - * Enables the filtering condition. + * Permits packets that match the filtering condition to be processed + * by the rest of the pipeline. Automatically denies packets that don't + * match the criteria. */ PERMIT, /** - * Disables the filtering condition. + * Denies packets that make it through the permit filters. */ DENY } /** - * Obtain the key for this filter. + * Obtain the key for this filter. The filter may or may not require a key. * - * @return a criterion + * @return a criterion, which could be null if no key was provided. */ Criterion key(); @@ -77,6 +82,16 @@ public interface FilteringObjective extends Objective { */ Collection conditions(); + /** + * Auxiliary optional information provided to the device-driver.Typically + * conveys information about changes (treatments) to packets that are + * permitted into the pipeline by the PERMIT filtering condition. + * + * @return a treatment on the packets that make it through the PERMIT filters. + * Value may be null if no meta information is provided. + */ + TrafficTreatment meta(); + /** * Builder of Filtering objective entities. */ @@ -112,12 +127,21 @@ public interface FilteringObjective extends Objective { */ Builder deny(); + /** + * Set meta information about this filtering condition set. + * + * @param treatment traffic treatment to use + * @return a filtering builder + */ + Builder setMeta(TrafficTreatment treatment); + /** * Assigns an application id. * * @param appId an application id * @return a filtering builder */ + @Override Builder fromApp(ApplicationId appId); /** diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/DefaultGroupBucket.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/DefaultGroupBucket.java index 6efd3e79..9d942ee4 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/DefaultGroupBucket.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/DefaultGroupBucket.java @@ -139,6 +139,20 @@ public final class DefaultGroupBucket implements GroupBucket, StoredGroupBucketE watchGroup); } + /** + * Creates all group bucket. + * + * @param treatment traffic treatment associated with group bucket + * @return all group bucket object + */ + public static GroupBucket createAllGroupBucket(TrafficTreatment treatment) { + return new DefaultGroupBucket(GroupDescription.Type.ALL, + treatment, + (short) -1, + null, + null); + } + @Override public GroupDescription.Type type() { return this.type; diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/HostToHostIntent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/HostToHostIntent.java index bd4219ad..c1467241 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/HostToHostIntent.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/HostToHostIntent.java @@ -17,11 +17,15 @@ package org.onosproject.net.intent; import com.google.common.annotations.Beta; import com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; + import org.onosproject.core.ApplicationId; import org.onosproject.net.HostId; +import org.onosproject.net.Link; import org.onosproject.net.flow.TrafficSelector; import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.intent.constraint.LinkTypeConstraint; import java.util.List; @@ -33,6 +37,8 @@ import static com.google.common.base.Preconditions.checkNotNull; @Beta public final class HostToHostIntent extends ConnectivityIntent { + static final LinkTypeConstraint NOT_OPTICAL = new LinkTypeConstraint(false, Link.Type.OPTICAL); + private final HostId one; private final HostId two; @@ -115,6 +121,15 @@ public final class HostToHostIntent extends ConnectivityIntent { */ public HostToHostIntent build() { + List theConstraints = constraints; + // If not-OPTICAL constraint hasn't been specified, add them + if (!constraints.contains(NOT_OPTICAL)) { + theConstraints = ImmutableList.builder() + .add(NOT_OPTICAL) + .addAll(constraints) + .build(); + } + return new HostToHostIntent( appId, key, @@ -122,7 +137,7 @@ public final class HostToHostIntent extends ConnectivityIntent { two, selector, treatment, - constraints, + theConstraints, priority ); } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/Key.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/Key.java index 18baafc8..0344acbf 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/Key.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/Key.java @@ -28,7 +28,7 @@ import java.util.Objects; */ // TODO maybe pull this up to utils @Beta -public abstract class Key { +public abstract class Key implements Comparable { //TODO consider making this a HashCode object (worry about performance) private final long hash; @@ -117,6 +117,12 @@ public abstract class Key { Objects.equals(this.appId, other.appId) && Objects.equals(this.key, other.key); } + + @Override + public int compareTo(Key o) { + StringKey sk = (StringKey) o; + return this.key.compareTo(sk.key); + } } private static final class LongKey extends Key { @@ -157,6 +163,13 @@ public abstract class Key { this.key == other.key && Objects.equals(this.appId, other.appId); } + + @Override + public int compareTo(Key o) { + Long myKey = key; + Long otherKey = ((LongKey) o).key; + return myKey.compareTo(otherKey); + } } } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/BandwidthConstraint.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/BandwidthConstraint.java index 43b8e4b1..20ccb55d 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/BandwidthConstraint.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/BandwidthConstraint.java @@ -16,6 +16,8 @@ package org.onosproject.net.intent.constraint; import com.google.common.annotations.Beta; + +import org.onlab.util.DataRateUnit; import org.onosproject.net.Link; import org.onosproject.net.resource.link.BandwidthResource; import org.onosproject.net.resource.link.BandwidthResourceRequest; @@ -32,7 +34,7 @@ import static com.google.common.base.Preconditions.checkNotNull; * Constraint that evaluates links based on available bandwidths. */ @Beta -public class BandwidthConstraint extends BooleanConstraint { +public final class BandwidthConstraint extends BooleanConstraint { private final BandwidthResource bandwidth; @@ -45,6 +47,17 @@ public class BandwidthConstraint extends BooleanConstraint { this.bandwidth = checkNotNull(bandwidth, "Bandwidth cannot be null"); } + /** + * Creates a new bandwidth constraint. + * + * @param v required amount of bandwidth + * @param unit {@link DataRateUnit} of {@code v} + * @return {@link BandwidthConstraint} instance with given bandwidth requirement + */ + public static BandwidthConstraint of(double v, DataRateUnit unit) { + return new BandwidthConstraint(BandwidthResource.of(v, unit)); + } + // Constructor for serialization private BandwidthConstraint() { this.bandwidth = null; 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 82d84743..ad684c8c 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 @@ -152,6 +152,14 @@ public interface ResourceService { */ Collection getResourceAllocations(ResourceConsumer consumer); + /** + * Returns resource paths that point available child resources under the specified resource path. + * + * @param parent parent resource path + * @return available resource paths under the specified resource path + */ + Collection getAvailableResources(ResourcePath parent); + /** * Returns the availability of the specified resource. * diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceStore.java index 5a034b4d..2cab9d4b 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceStore.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceStore.java @@ -91,6 +91,14 @@ public interface ResourceStore { */ Collection getResources(ResourceConsumer consumer); + /** + * Returns a collection of the child resources of the specified parent. + * + * @param parent parent of the resource to be returned + * @return a collection of the child resources of the specified resource + */ + Collection getChildResources(ResourcePath parent); + /** * Returns a collection of the resources which are children of the specified parent and * whose type is the specified class. diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/BandwidthResource.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/BandwidthResource.java index fe21e042..0bfb3795 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/BandwidthResource.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/BandwidthResource.java @@ -16,7 +16,7 @@ package org.onosproject.net.resource.link; import org.onlab.util.Bandwidth; - +import org.onlab.util.DataRateUnit; import java.util.Objects; import static com.google.common.base.Preconditions.checkNotNull; @@ -42,6 +42,17 @@ public final class BandwidthResource implements LinkResource { this.bandwidth = null; } + /** + * Creates a new bandwidth resource. + * + * @param v amount of bandwidth to request + * @param unit {@link DataRateUnit} of {@code v} + * @return {@link BandwidthResource} instance with given bandwidth + */ + public static BandwidthResource of(double v, DataRateUnit unit) { + return new BandwidthResource(Bandwidth.of(v, unit)); + } + /** * Returns bandwidth as a double value. * diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/DefaultLinkResourceRequest.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/DefaultLinkResourceRequest.java index 5153aebf..f8e143a4 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/DefaultLinkResourceRequest.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/DefaultLinkResourceRequest.java @@ -16,48 +16,47 @@ package org.onosproject.net.resource.link; import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; import java.util.Objects; +import java.util.stream.Collectors; +import com.google.common.annotations.Beta; +import com.google.common.collect.ImmutableMap; import org.onlab.util.Bandwidth; import org.onosproject.net.Link; import org.onosproject.net.intent.Constraint; import org.onosproject.net.intent.IntentId; -import com.google.common.collect.ImmutableSet; - import org.onosproject.net.intent.constraint.BandwidthConstraint; import org.onosproject.net.intent.constraint.LambdaConstraint; import org.onosproject.net.resource.ResourceRequest; import org.onosproject.net.resource.ResourceType; +import static com.google.common.base.Preconditions.checkNotNull; + /** * Implementation of {@link LinkResourceRequest}. */ public final class DefaultLinkResourceRequest implements LinkResourceRequest { private final IntentId intentId; - private final Collection links; - private final Set resources; + protected final Map> requests; /** - * Creates a new link resource request with the given ID, links, and - * resource requests. + * Creates a new link resource request with the specified Intent ID, + * and resource requests over links. * - * @param intentId intent ID related to this request - * @param links a set of links for the request - * @param resources a set of resources to be requested + * @param intentId intent ID associated with this request + * @param requests resource requests over links */ - private DefaultLinkResourceRequest(IntentId intentId, - Collection links, - Set resources) { - this.intentId = intentId; - this.links = ImmutableSet.copyOf(links); - this.resources = ImmutableSet.copyOf(resources); + private DefaultLinkResourceRequest(IntentId intentId, Map> requests) { + this.intentId = checkNotNull(intentId); + this.requests = checkNotNull(ImmutableMap.copyOf(requests)); } - @Override public ResourceType type() { return null; @@ -70,12 +69,19 @@ public final class DefaultLinkResourceRequest implements LinkResourceRequest { @Override public Collection links() { - return links; + return requests.keySet(); } @Override public Set resources() { - return resources; + return requests.values().stream() + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + } + + @Override + public Set resources(Link link) { + return requests.get(link); } /** @@ -95,8 +101,7 @@ public final class DefaultLinkResourceRequest implements LinkResourceRequest { */ public static final class Builder implements LinkResourceRequest.Builder { private IntentId intentId; - private Collection links; - private Set resources; + private Map> requests; /** * Creates a new link resource request. @@ -106,18 +111,33 @@ public final class DefaultLinkResourceRequest implements LinkResourceRequest { */ private Builder(IntentId intentId, Collection links) { this.intentId = intentId; - this.links = links; - this.resources = new HashSet<>(); + this.requests = new HashMap<>(); + for (Link link : links) { + requests.put(link, new HashSet<>()); + } } /** * Adds lambda request. * * @return self + * @deprecated in Emu Release */ + @Deprecated @Override public Builder addLambdaRequest() { - resources.add(new LambdaResourceRequest()); + for (Link link : requests.keySet()) { + requests.get(link).add(new LambdaResourceRequest()); + } + return this; + } + + @Beta + @Override + public LinkResourceRequest.Builder addLambdaRequest(LambdaResource lambda) { + for (Link link : requests.keySet()) { + requests.get(link).add(new LambdaResourceRequest(lambda)); + } return this; } @@ -125,10 +145,36 @@ public final class DefaultLinkResourceRequest implements LinkResourceRequest { * Adds Mpls request. * * @return self + * @deprecated in Emu Release */ + @Deprecated @Override public Builder addMplsRequest() { - resources.add(new MplsLabelResourceRequest()); + for (Link link : requests.keySet()) { + requests.get(link).add(new MplsLabelResourceRequest()); + } + return this; + } + + @Beta + @Override + public Builder addMplsRequest(MplsLabel label) { + for (Link link : requests.keySet()) { + requests.get(link).add(new MplsLabelResourceRequest(label)); + } + return this; + } + + @Beta + @Override + public LinkResourceRequest.Builder addMplsRequest(Map labels) { + for (Link link : labels.keySet()) { + if (!requests.containsKey(link)) { + requests.put(link, new HashSet<>()); + } + requests.get(link).add(new MplsLabelResourceRequest(labels.get(link))); + } + return this; } @@ -140,7 +186,9 @@ public final class DefaultLinkResourceRequest implements LinkResourceRequest { */ @Override public Builder addBandwidthRequest(double bandwidth) { - resources.add(new BandwidthResourceRequest(new BandwidthResource(Bandwidth.bps(bandwidth)))); + for (Link link : requests.keySet()) { + requests.get(link).add(new BandwidthResourceRequest(new BandwidthResource(Bandwidth.bps(bandwidth)))); + } return this; } @@ -162,13 +210,13 @@ public final class DefaultLinkResourceRequest implements LinkResourceRequest { */ @Override public LinkResourceRequest build() { - return new DefaultLinkResourceRequest(intentId, links, resources); + return new DefaultLinkResourceRequest(intentId, requests); } } @Override public int hashCode() { - return Objects.hash(intentId, links); + return Objects.hash(intentId, links()); } @Override @@ -181,6 +229,6 @@ public final class DefaultLinkResourceRequest implements LinkResourceRequest { } final DefaultLinkResourceRequest other = (DefaultLinkResourceRequest) obj; return Objects.equals(this.intentId, other.intentId) - && Objects.equals(this.links, other.links); + && Objects.equals(this.links(), other.links()); } } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LambdaResourceRequest.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LambdaResourceRequest.java index b0391f5a..d264d5e5 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LambdaResourceRequest.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LambdaResourceRequest.java @@ -15,15 +15,50 @@ */ package org.onosproject.net.resource.link; +import com.google.common.annotations.Beta; import com.google.common.base.MoreObjects; import org.onosproject.net.resource.ResourceRequest; import org.onosproject.net.resource.ResourceType; +import static com.google.common.base.Preconditions.checkNotNull; + /** * Representation of a request for lambda resource. */ public class LambdaResourceRequest implements ResourceRequest { + private final LambdaResource lambda; + + /** + * Constructs a request specifying the given lambda. + * + * @param lambda lambda to be requested + */ + @Beta + public LambdaResourceRequest(LambdaResource lambda) { + this.lambda = checkNotNull(lambda); + } + + /** + * Constructs a request asking an arbitrary available lambda. + * + * @deprecated in Emu Release + */ + @Deprecated + public LambdaResourceRequest() { + this.lambda = null; + } + + /** + * Returns the lambda this request expects. + * + * @return the lambda this request expects + */ + @Beta + public LambdaResource lambda() { + return lambda; + } + @Override public ResourceType type() { return ResourceType.LAMBDA; @@ -32,6 +67,7 @@ public class LambdaResourceRequest implements ResourceRequest { @Override public String toString() { return MoreObjects.toStringHelper(this) + .add("lambda", lambda) .toString(); } } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceRequest.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceRequest.java index 8023a92e..37622e79 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceRequest.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceRequest.java @@ -16,8 +16,10 @@ package org.onosproject.net.resource.link; import java.util.Collection; +import java.util.Map; import java.util.Set; +import com.google.common.annotations.Beta; import org.onosproject.net.Link; import org.onosproject.net.intent.Constraint; import org.onosproject.net.intent.IntentId; @@ -49,23 +51,63 @@ public interface LinkResourceRequest extends ResourceRequest { */ Set resources(); + /** + * Returns the set of resource request against the specified link. + * + * @param link link whose associated resource request is to be returned + * @return set of resource request against the specified link + */ + @Beta + Set resources(Link link); + /** * Builder of link resource request. */ interface Builder { - /** + /** * Adds lambda request. * * @return self + * @deprecated in Emu Release */ + @Deprecated Builder addLambdaRequest(); /** - * Adds MPLS request. - * - * @return self - */ - Builder addMplsRequest(); + * Adds lambda request. + * + * @param lambda lambda to be requested + * @return self + */ + @Beta + Builder addLambdaRequest(LambdaResource lambda); + + /** + * Adds MPLS request. + * + * @return self + * @deprecated in Emu Release + */ + @Deprecated + Builder addMplsRequest(); + + /** + * Adds MPLS request. + * + * @param label MPLS label to be requested + * @return self + */ + @Beta + Builder addMplsRequest(MplsLabel label); + + /** + * Adds MPLS request against the specified links. + * + * @param labels MPLS labels to be requested against links + * @return self + */ + @Beta + Builder addMplsRequest(Map labels); /** * Adds bandwidth request with bandwidth value. diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceService.java index 6dc04dfc..71ea7e1a 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceService.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceService.java @@ -22,7 +22,10 @@ import org.onosproject.net.resource.ResourceRequest; /** * Service for providing link resource allocation. + * + * @deprecated in Emu Release */ +@Deprecated public interface LinkResourceService extends ListenerService { @@ -31,14 +34,18 @@ public interface LinkResourceService * * @param req resources to be allocated * @return allocated resources + * @deprecated in Emu Release */ + @Deprecated LinkResourceAllocations requestResources(LinkResourceRequest req); /** * Releases resources. * * @param allocations resources to be released + * @deprecated in Emu Release */ + @Deprecated void releaseResources(LinkResourceAllocations allocations); /** @@ -47,7 +54,9 @@ public interface LinkResourceService * @param req updated resource request * @param oldAllocations old resource allocations * @return new resource allocations + * @deprecated in Emu Release */ + @Deprecated LinkResourceAllocations updateResources(LinkResourceRequest req, LinkResourceAllocations oldAllocations); @@ -55,7 +64,9 @@ public interface LinkResourceService * Returns all allocated resources. * * @return allocated resources + * @deprecated in Emu Release */ + @Deprecated Iterable getAllocations(); /** @@ -63,7 +74,9 @@ public interface LinkResourceService * * @param link a target link * @return allocated resources + * @deprecated in Emu Release */ + @Deprecated Iterable getAllocations(Link link); /** @@ -71,7 +84,9 @@ public interface LinkResourceService * * @param intentId the target Intent's id * @return allocated resources for Intent + * @deprecated in Emu Release */ + @Deprecated LinkResourceAllocations getAllocations(IntentId intentId); /** @@ -79,7 +94,9 @@ public interface LinkResourceService * * @param link a target link * @return available resources for the target link + * @deprecated in Emu Release */ + @Deprecated Iterable getAvailableResources(Link link); /** @@ -88,7 +105,9 @@ public interface LinkResourceService * @param link a target link * @param allocations allocations to be included as available * @return available resources for the target link + * @deprecated in Emu Release */ + @Deprecated Iterable getAvailableResources(Link link, LinkResourceAllocations allocations); diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/MplsLabelResourceRequest.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/MplsLabelResourceRequest.java index 0a03f450..01a048b7 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/MplsLabelResourceRequest.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/MplsLabelResourceRequest.java @@ -15,15 +15,50 @@ */ package org.onosproject.net.resource.link; +import com.google.common.annotations.Beta; import com.google.common.base.MoreObjects; import org.onosproject.net.resource.ResourceRequest; import org.onosproject.net.resource.ResourceType; +import static com.google.common.base.Preconditions.checkNotNull; + /** * Representation of a request for lambda resource. */ public class MplsLabelResourceRequest implements ResourceRequest { + private final MplsLabel mplsLabel; + + /** + * Constructs a request specifying the given MPLS label. + * + * @param mplsLabel MPLS label to be requested + */ + @Beta + public MplsLabelResourceRequest(MplsLabel mplsLabel) { + this.mplsLabel = checkNotNull(mplsLabel); + } + + /** + * Constructs a request asking an arbitrary available MPLS label. + * + * @deprecated in Emu Release + */ + @Deprecated + public MplsLabelResourceRequest() { + this.mplsLabel = null; + } + + /** + * Returns the MPLS label this request expects. + * + * @return the MPLS label this request expects + */ + @Beta + public MplsLabel mplsLabel() { + return mplsLabel; + } + @Override public ResourceType type() { return ResourceType.MPLS_LABEL; @@ -32,6 +67,7 @@ public class MplsLabelResourceRequest implements ResourceRequest { @Override public String toString() { return MoreObjects.toStringHelper(this) + .add("mplsLabel", mplsLabel) .toString(); } } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/persistence/PersistenceService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/persistence/PersistenceService.java new file mode 100644 index 00000000..09065dec --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/persistence/PersistenceService.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.persistence; + +/** + * Service that allows for the creation of local disk backed map for instance specific values that persist across + * restarts. Empty maps and sets are deleted on shutdown. + */ +public interface PersistenceService { + /** + * A builder for the creation of local persistent maps backed by disk. + * + * @param the type of keys in this map + * @param the type of values in this map + * @return a persistent map builder + */ + PersistentMapBuilder persistentMapBuilder(); + + /** + * A builder for the creation of local persistent sets backed by disk. + * + * @param the type of the elements + * @return a persistent set builder + */ + PersistentSetBuilder persistentSetBuilder(); +} \ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/persistence/PersistentMapBuilder.java b/framework/src/onos/core/api/src/main/java/org/onosproject/persistence/PersistentMapBuilder.java new file mode 100644 index 00000000..c3c855e1 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/persistence/PersistentMapBuilder.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.persistence; + + +import org.onosproject.store.service.Serializer; + +import java.util.Map; + +/** + * The interface for a persistent map builder for use with mapDB. + */ +public interface PersistentMapBuilder { + + /** + * Sets the name of this map. + * @param name the string name of this map + * @return a persistent map builder with the name option now set + */ + PersistentMapBuilder withName(String name); + + /** + * Sets the key serializer to be used to serialize this map, this is a required parameter. + * @param serializer the serializer to be used for keys + * @return a persistent map builder with the key serializer set + */ + PersistentMapBuilder withSerializer(Serializer serializer); + + /** + * Validates the map settings and then builds this map in the database. Throws an exception if invalid settings + * are found. + * @return The map that was created + */ + Map build(); +} \ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/persistence/PersistentSetBuilder.java b/framework/src/onos/core/api/src/main/java/org/onosproject/persistence/PersistentSetBuilder.java new file mode 100644 index 00000000..851872cf --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/persistence/PersistentSetBuilder.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.persistence; + +import org.onosproject.store.service.Serializer; + +import java.util.Set; + +/** + * The default interface for the persistent set builder for use with mapDB. + */ +public interface PersistentSetBuilder { + + /** + * Sets the name of this set. + * @param name the string name of this set + * @return a persistent set builder with the name option now set + */ + PersistentSetBuilder withName(String name); + + /** + * Sets the serializer to be used to serialize this set, this is a required parameter. + * @param serializer the serializer to be used + * @return a persistent set builder with the serializer set + */ + PersistentSetBuilder withSerializer(Serializer serializer); + + /** + * Validates the set settings and then builds this map in the database. Throws an exception if invalid settings + * are found. + * @return The set that was created + */ + Set build(); +} \ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/persistence/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/persistence/package-info.java new file mode 100644 index 00000000..6e11a5e1 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/persistence/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. + */ + +/** + * Persistence service and builders. + */ +package org.onosproject.persistence; diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/TransactionContext.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/TransactionContext.java index 94942e20..ef972536 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/TransactionContext.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/TransactionContext.java @@ -56,9 +56,9 @@ public interface TransactionContext { * Commits a transaction that was previously started thereby making its changes permanent * and externally visible. * - * @throws TransactionException if transaction fails to commit + * @return true if this transaction succeeded, otherwise false. */ - void commit(); + boolean commit(); /** * Aborts any changes made in this transaction context and discarding all locally cached updates. diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiTopoOverlay.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiTopoOverlay.java index e0d7d239..88796de7 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiTopoOverlay.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiTopoOverlay.java @@ -16,6 +16,8 @@ package org.onosproject.ui; +import org.onosproject.net.DeviceId; +import org.onosproject.net.HostId; import org.onosproject.ui.topo.PropertyPanel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -105,8 +107,9 @@ public class UiTopoOverlay { * This default implementation does nothing. * * @param pp property panel model of summary data + * @param deviceId device id */ - public void modifyDeviceDetails(PropertyPanel pp) { + public void modifyDeviceDetails(PropertyPanel pp, DeviceId deviceId) { } /** @@ -115,7 +118,8 @@ public class UiTopoOverlay { * This default implementation does nothing. * * @param pp property panel model of summary data + * @param hostId host id */ - public void modifyHostDetails(PropertyPanel pp) { + public void modifyHostDetails(PropertyPanel pp, HostId hostId) { } } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/AppIdFormatter.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/AppIdFormatter.java index 0e1c248b..f7947a75 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/AppIdFormatter.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/AppIdFormatter.java @@ -27,6 +27,7 @@ public final class AppIdFormatter extends AbstractCellFormatter { // non-instantiable private AppIdFormatter() { } + // NOTE: do not change this format; we parse it on the client side. @Override protected String nonNullFormat(Object value) { ApplicationId appId = (ApplicationId) value; diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/NodeBadge.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/NodeBadge.java index 7b517111..4edb6712 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/NodeBadge.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/NodeBadge.java @@ -40,7 +40,7 @@ public final class NodeBadge { return "{" + code + "}"; } - /** Returns the status code in string form. */ + /* Returns the status code in string form. */ public String code() { return code; } diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/HostToHostIntentTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/HostToHostIntentTest.java index 3f7650e4..c3a95473 100644 --- a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/HostToHostIntentTest.java +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/HostToHostIntentTest.java @@ -16,15 +16,18 @@ package org.onosproject.net.intent; import org.junit.Test; +import org.onlab.util.DataRateUnit; import org.onosproject.TestApplicationId; import org.onosproject.core.ApplicationId; import org.onosproject.net.HostId; import org.onosproject.net.flow.TrafficSelector; - +import org.onosproject.net.intent.constraint.BandwidthConstraint; +import com.google.common.collect.ImmutableList; import com.google.common.testing.EqualsTester; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.is; import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; import static org.onosproject.net.NetTestTools.hid; @@ -102,6 +105,55 @@ public class HostToHostIntentTest extends IntentTest { .testEquals(); } + @Test + public void testImplicitConstraintsAreAdded() { + final Constraint other = BandwidthConstraint.of(1, DataRateUnit.GBPS); + final HostToHostIntent intent = HostToHostIntent.builder() + .appId(APPID) + .one(id1) + .two(id2) + .selector(selector) + .treatment(treatment) + .constraints(ImmutableList.of(other)) + .build(); + + assertThat(intent.constraints(), hasItem(HostToHostIntent.NOT_OPTICAL)); + } + + @Test + public void testImplicitConstraints() { + final HostToHostIntent implicit = HostToHostIntent.builder() + .appId(APPID) + .one(id1) + .two(id2) + .selector(selector) + .treatment(treatment) + .build(); + final HostToHostIntent empty = HostToHostIntent.builder() + .appId(APPID) + .one(id1) + .two(id2) + .selector(selector) + .treatment(treatment) + .constraints(ImmutableList.of()) + .build(); + final HostToHostIntent exact = HostToHostIntent.builder() + .appId(APPID) + .one(id1) + .two(id2) + .selector(selector) + .treatment(treatment) + .constraints(ImmutableList.of(HostToHostIntent.NOT_OPTICAL)) + .build(); + + new EqualsTester() + .addEqualityGroup(implicit.constraints(), + empty.constraints(), + exact.constraints()) + .testEquals(); + + } + @Override protected Intent createOne() { return HostToHostIntent.builder() diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/DefaultPacketRequestTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/DefaultPacketRequestTest.java new file mode 100644 index 00000000..592cd983 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/DefaultPacketRequestTest.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.net.packet; + +import org.junit.Test; +import org.onosproject.core.DefaultApplicationId; +import org.onosproject.net.NetTestTools; +import org.onosproject.net.flow.DefaultTrafficSelector; +import org.onosproject.net.flow.TrafficSelector; + +import com.google.common.testing.EqualsTester; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +/** + * Unit tests for the DefaultPacketRequest class. + */ +public class DefaultPacketRequestTest { + + private final TrafficSelector selector = DefaultTrafficSelector + .builder() + .matchIcmpCode((byte) 1) + .build(); + + private final DefaultPacketRequest packetRequest1 = + new DefaultPacketRequest(DefaultTrafficSelector.emptySelector(), + PacketPriority.CONTROL, + NetTestTools.APP_ID); + private final DefaultPacketRequest sameAsacketRequest1 = + new DefaultPacketRequest(DefaultTrafficSelector.emptySelector(), + PacketPriority.CONTROL, + NetTestTools.APP_ID); + private final DefaultPacketRequest packetRequest2 = + new DefaultPacketRequest(selector, + PacketPriority.CONTROL, + NetTestTools.APP_ID); + private final DefaultPacketRequest packetRequest3 = + new DefaultPacketRequest(DefaultTrafficSelector.emptySelector(), + PacketPriority.REACTIVE, + NetTestTools.APP_ID); + private final DefaultPacketRequest packetRequest4 = + new DefaultPacketRequest(DefaultTrafficSelector.emptySelector(), + PacketPriority.CONTROL, + new DefaultApplicationId(1, "foo")); + + /** + * Tests the operation of the equals(), toAstring() and hashCode() methods. + */ + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup(packetRequest1, sameAsacketRequest1) + .addEqualityGroup(packetRequest2) + .addEqualityGroup(packetRequest3) + .addEqualityGroup(packetRequest4) + .testEquals(); + } + + /** + * Tests that building and fetching from a DefaultPacketRequest is correct. + */ + @Test + public void testConstruction() { + assertThat(packetRequest1.priority(), is(PacketPriority.CONTROL)); + assertThat(packetRequest1.priority().priorityValue(), + is(PacketPriority.CONTROL.priorityValue())); + assertThat(packetRequest1.selector(), is(DefaultTrafficSelector.emptySelector())); + assertThat(packetRequest1.appId(), is(NetTestTools.APP_ID)); + } + + /** + * Checks that the DefaultPacketRequest class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(DefaultPacketRequest.class); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/PacketEventTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/PacketEventTest.java new file mode 100644 index 00000000..f0d45f0c --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/PacketEventTest.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.net.packet; + +import org.junit.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.hamcrest.Matchers.is; + +/** + * Unit tests for PacketEvent class. + */ +public class PacketEventTest { + + OutboundPacket packet; + + @Test + public void testConstruction1() { + long time = System.currentTimeMillis(); + PacketEvent event = new PacketEvent(PacketEvent.Type.EMIT, packet); + + assertThat(event.type(), is(PacketEvent.Type.EMIT)); + assertThat(event.subject(), is(packet)); + assertThat(event.time(), greaterThanOrEqualTo(time)); + } + + @Test + public void testConstruction2() { + long time = 12345678; + PacketEvent event = new PacketEvent(PacketEvent.Type.EMIT, packet, time); + + assertThat(event.type(), is(PacketEvent.Type.EMIT)); + assertThat(event.subject(), is(packet)); + assertThat(event.time(), is(time)); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/PacketProcessorTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/PacketProcessorTest.java new file mode 100644 index 00000000..7b2ef541 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/PacketProcessorTest.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.packet; + +import org.junit.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.hamcrest.Matchers.lessThan; + +/** + * Unit tests for static APIs in the packet processor class. + */ +public class PacketProcessorTest { + + /** + * Tests a priority in the advisor range. + */ + @Test + public void testAdvisorPriorities() { + int advisorPriority = PacketProcessor.advisor(3); + assertThat(advisorPriority, lessThan(PacketProcessor.ADVISOR_MAX)); + assertThat(advisorPriority, greaterThanOrEqualTo(0)); + } + + /** + * Tests a priority in the director range. + */ + @Test + public void testDirectorPriorities() { + int directorPriority = PacketProcessor.director(3); + assertThat(directorPriority, lessThan(PacketProcessor.DIRECTOR_MAX)); + assertThat(directorPriority, greaterThanOrEqualTo(PacketProcessor.ADVISOR_MAX)); + } + + /** + * Tests a priority in the observer range. + */ + @Test + public void testObserverPriorities() { + int observerPriority = PacketProcessor.observer(3); + assertThat(observerPriority, lessThan(PacketProcessor.OBSERVER_MAX)); + assertThat(observerPriority, greaterThanOrEqualTo(PacketProcessor.DIRECTOR_MAX)); + } + +} diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/DecodeCriterionCodecHelper.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/DecodeCriterionCodecHelper.java index 4e0f2bd9..69c5e791 100644 --- a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/DecodeCriterionCodecHelper.java +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/DecodeCriterionCodecHelper.java @@ -15,6 +15,8 @@ */ package org.onosproject.codec.impl; +import static org.onlab.util.Tools.nullIsIllegal; + import java.util.HashMap; import java.util.Map; @@ -24,9 +26,13 @@ import org.onlab.packet.MacAddress; import org.onlab.packet.MplsLabel; import org.onlab.packet.TpPort; import org.onlab.packet.VlanId; +import org.onlab.util.HexString; import org.onosproject.net.ChannelSpacing; import org.onosproject.net.GridType; import org.onosproject.net.Lambda; +import org.onosproject.net.OchSignalType; +import org.onosproject.net.OduSignalId; +import org.onosproject.net.OduSignalType; import org.onosproject.net.PortNumber; import org.onosproject.net.flow.criteria.Criteria; import org.onosproject.net.flow.criteria.Criterion; @@ -34,8 +40,6 @@ import org.onosproject.net.flow.criteria.Criterion; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; -import static org.onlab.util.Tools.nullIsIllegal; - /** * Decode portion of the criterion codec. */ @@ -95,6 +99,8 @@ public final class DecodeCriterionCodecHelper { decoderMap.put(Criterion.Type.OCH_SIGID.name(), new OchSigIdDecoder()); decoderMap.put(Criterion.Type.OCH_SIGTYPE.name(), new OchSigTypeDecoder()); decoderMap.put(Criterion.Type.TUNNEL_ID.name(), new TunnelIdDecoder()); + decoderMap.put(Criterion.Type.ODU_SIGID.name(), new OduSigIdDecoder()); + decoderMap.put(Criterion.Type.ODU_SIGTYPE.name(), new OduSigTypeDecoder()); } private class EthTypeDecoder implements CriterionDecoder { @@ -415,7 +421,9 @@ public final class DecodeCriterionCodecHelper { private class OchSigTypeDecoder implements CriterionDecoder { @Override public Criterion decodeCriterion(ObjectNode json) { - return null; + OchSignalType ochSignalType = OchSignalType.valueOf(nullIsIllegal(json.get(CriterionCodec.OCH_SIGNAL_TYPE), + CriterionCodec.OCH_SIGNAL_TYPE + MISSING_MEMBER_MESSAGE).asText()); + return Criteria.matchOchSignalType(ochSignalType); } } @@ -428,6 +436,34 @@ public final class DecodeCriterionCodecHelper { } } + private class OduSigIdDecoder implements CriterionDecoder { + @Override + public Criterion decodeCriterion(ObjectNode json) { + JsonNode oduSignalId = nullIsIllegal(json.get(CriterionCodec.ODU_SIGNAL_ID), + CriterionCodec.TRIBUTARY_PORT_NUMBER + MISSING_MEMBER_MESSAGE); + + int tributaryPortNumber = nullIsIllegal(oduSignalId.get(CriterionCodec.TRIBUTARY_PORT_NUMBER), + CriterionCodec.TRIBUTARY_PORT_NUMBER + MISSING_MEMBER_MESSAGE).asInt(); + int tributarySlotLen = nullIsIllegal(oduSignalId.get(CriterionCodec.TRIBUTARY_SLOT_LEN), + CriterionCodec.TRIBUTARY_SLOT_LEN + MISSING_MEMBER_MESSAGE).asInt(); + byte[] tributarySlotBitmap = HexString.fromHexString( + nullIsIllegal(oduSignalId.get(CriterionCodec.TRIBUTARY_SLOT_BITMAP), + CriterionCodec.TRIBUTARY_SLOT_BITMAP + MISSING_MEMBER_MESSAGE).asText()); + + return Criteria.matchOduSignalId( + OduSignalId.oduSignalId(tributaryPortNumber, tributarySlotLen, tributarySlotBitmap)); + } + } + + private class OduSigTypeDecoder implements CriterionDecoder { + @Override + public Criterion decodeCriterion(ObjectNode json) { + OduSignalType oduSignalType = OduSignalType.valueOf(nullIsIllegal(json.get(CriterionCodec.ODU_SIGNAL_TYPE), + CriterionCodec.ODU_SIGNAL_TYPE + MISSING_MEMBER_MESSAGE).asText()); + return Criteria.matchOduSignalType(oduSignalType); + } + } + /** * Decodes the JSON into a criterion object. * diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java index 6a97a076..14555b3d 100644 --- a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java @@ -15,26 +15,29 @@ */ package org.onosproject.codec.impl; +import static org.onlab.util.Tools.nullIsIllegal; + import org.onlab.packet.IpAddress; import org.onlab.packet.MacAddress; import org.onlab.packet.MplsLabel; import org.onlab.packet.TpPort; import org.onlab.packet.VlanId; +import org.onlab.util.HexString; import org.onosproject.net.ChannelSpacing; import org.onosproject.net.GridType; import org.onosproject.net.Lambda; import org.onosproject.net.OchSignal; +import org.onosproject.net.OduSignalId; import org.onosproject.net.PortNumber; - -import com.fasterxml.jackson.databind.node.ObjectNode; import org.onosproject.net.flow.instructions.Instruction; import org.onosproject.net.flow.instructions.Instructions; import org.onosproject.net.flow.instructions.L0ModificationInstruction; +import org.onosproject.net.flow.instructions.L1ModificationInstruction; import org.onosproject.net.flow.instructions.L2ModificationInstruction; import org.onosproject.net.flow.instructions.L3ModificationInstruction; import org.onosproject.net.flow.instructions.L4ModificationInstruction; -import static org.onlab.util.Tools.nullIsIllegal; +import com.fasterxml.jackson.databind.node.ObjectNode; /** * Decoding portion of the instruction codec. @@ -173,6 +176,30 @@ public final class DecodeInstructionCodecHelper { + subType + " is not supported"); } + /** + * Decodes a Layer 1 instruction. + * + * @return instruction object decoded from the JSON + * @throws IllegalArgumentException if the JSON is invalid + */ + private Instruction decodeL1() { + String subType = json.get(InstructionCodec.SUBTYPE).asText(); + if (subType.equals(L1ModificationInstruction.L1SubType.ODU_SIGID.name())) { + int tributaryPortNumber = nullIsIllegal(json.get(InstructionCodec.TRIBUTARY_PORT_NUMBER), + InstructionCodec.TRIBUTARY_PORT_NUMBER + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt(); + int tributarySlotLen = nullIsIllegal(json.get(InstructionCodec.TRIBUTARY_SLOT_LEN), + InstructionCodec.TRIBUTARY_SLOT_LEN + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt(); + byte[] tributarySlotBitmap = null; + tributarySlotBitmap = HexString.fromHexString( + nullIsIllegal(json.get(InstructionCodec.TRIBUTARY_SLOT_BITMAP), + InstructionCodec.TRIBUTARY_SLOT_BITMAP + InstructionCodec.MISSING_MEMBER_MESSAGE).asText()); + return Instructions.modL1OduSignalId(OduSignalId.oduSignalId(tributaryPortNumber, tributarySlotLen, + tributarySlotBitmap)); + } + throw new IllegalArgumentException("L1 Instruction subtype " + + subType + " is not supported"); + } + /** * Decodes a Layer 4 instruction. * @@ -221,6 +248,8 @@ public final class DecodeInstructionCodecHelper { return Instructions.createDrop(); } else if (type.equals(Instruction.Type.L0MODIFICATION.name())) { return decodeL0(); + } else if (type.equals(Instruction.Type.L1MODIFICATION.name())) { + return decodeL1(); } else if (type.equals(Instruction.Type.L2MODIFICATION.name())) { return decodeL2(); } else if (type.equals(Instruction.Type.L3MODIFICATION.name())) { diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodecHelper.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodecHelper.java index f7af736e..8fc6bbcf 100644 --- a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodecHelper.java +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodecHelper.java @@ -17,8 +17,10 @@ package org.onosproject.codec.impl; import java.util.EnumMap; +import org.onlab.util.HexString; import org.onosproject.codec.CodecContext; import org.onosproject.net.OchSignal; +import org.onosproject.net.OduSignalId; import org.onosproject.net.flow.criteria.Criterion; import org.onosproject.net.flow.criteria.EthCriterion; import org.onosproject.net.flow.criteria.EthTypeCriterion; @@ -370,12 +372,18 @@ public final class EncodeCriterionCodecHelper { private static class FormatOduSignalId implements CriterionTypeFormatter { @Override public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) { - final OduSignalIdCriterion oduSignalIdCriterion = - (OduSignalIdCriterion) criterion; - return root.put(CriterionCodec.ODU_SIGNAL_ID, oduSignalIdCriterion.oduSignalId().toString()); + OduSignalId oduSignalId = ((OduSignalIdCriterion) criterion).oduSignalId(); + ObjectNode child = root.putObject(CriterionCodec.ODU_SIGNAL_ID); + + child.put(CriterionCodec.TRIBUTARY_PORT_NUMBER, oduSignalId.tributaryPortNumber()); + child.put(CriterionCodec.TRIBUTARY_SLOT_LEN, oduSignalId.tributarySlotLength()); + child.put(CriterionCodec.TRIBUTARY_SLOT_BITMAP, HexString.toHexString(oduSignalId.tributarySlotBitmap())); + + return root; } } + private static class FormatOduSignalType implements CriterionTypeFormatter { @Override public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) { 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 d12e4ad8..2ec301db 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 @@ -15,11 +15,14 @@ */ package org.onosproject.codec.impl; +import org.onlab.util.HexString; import org.onosproject.codec.CodecContext; import org.onosproject.net.OchSignal; +import org.onosproject.net.OduSignalId; import org.onosproject.net.flow.instructions.Instruction; import org.onosproject.net.flow.instructions.Instructions; import org.onosproject.net.flow.instructions.L0ModificationInstruction; +import org.onosproject.net.flow.instructions.L1ModificationInstruction; import org.onosproject.net.flow.instructions.L2ModificationInstruction; import org.onosproject.net.flow.instructions.L3ModificationInstruction; import org.onosproject.net.flow.instructions.L4ModificationInstruction; @@ -80,6 +83,36 @@ public final class EncodeInstructionCodecHelper { } } + /** + * Encode an L1 modification instruction. + * + * @param result json node that the instruction attributes are added to + * @param instruction The L1 instruction + * @param context context of the request + */ + private void encodeL1(ObjectNode result) { + L1ModificationInstruction instruction = + (L1ModificationInstruction) this.instruction; + result.put(InstructionCodec.SUBTYPE, instruction.subtype().name()); + + switch (instruction.subtype()) { + case ODU_SIGID: + final L1ModificationInstruction.ModOduSignalIdInstruction oduSignalIdInstruction = + (L1ModificationInstruction.ModOduSignalIdInstruction) instruction; + OduSignalId oduSignalId = oduSignalIdInstruction.oduSignalId(); + + ObjectNode child = result.putObject("oduSignalId"); + + child.put(InstructionCodec.TRIBUTARY_PORT_NUMBER, oduSignalId.tributaryPortNumber()); + child.put(InstructionCodec.TRIBUTARY_SLOT_LEN, oduSignalId.tributarySlotLength()); + child.put(InstructionCodec.TRIBUTARY_SLOT_BITMAP, HexString.toHexString(oduSignalId.tributarySlotBitmap())); + break; + default: + log.info("Cannot convert L1 subtype of {}", instruction.subtype()); + break; + } + } + /** * Encode an L2 modification instruction. * @@ -222,6 +255,10 @@ public final class EncodeInstructionCodecHelper { encodeL0(result); break; + case L1MODIFICATION: + encodeL1(result); + break; + case L2MODIFICATION: encodeL2(result); break; diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/InstructionCodec.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/InstructionCodec.java index f4d5008a..d7307ad3 100644 --- a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/InstructionCodec.java +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/InstructionCodec.java @@ -50,6 +50,9 @@ public final class InstructionCodec extends JsonCodec { protected static final String TUNNEL_ID = "tunnelId"; protected static final String TCP_PORT = "tcpPort"; protected static final String UDP_PORT = "udpPort"; + protected static final String TRIBUTARY_PORT_NUMBER = "tributaryPortNumber"; + protected static final String TRIBUTARY_SLOT_LEN = "tributarySlotLength"; + protected static final String TRIBUTARY_SLOT_BITMAP = "tributarySlotBitmap"; protected static final String MISSING_MEMBER_MESSAGE = " member is required in Instruction"; 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 54e1146b..86374f81 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 @@ -31,6 +31,8 @@ import org.onosproject.net.ChannelSpacing; import org.onosproject.net.GridType; import org.onosproject.net.Lambda; import org.onosproject.net.OchSignalType; +import org.onosproject.net.OduSignalId; +import org.onosproject.net.OduSignalType; import org.onosproject.net.PortNumber; import org.onosproject.net.flow.criteria.Criteria; import org.onosproject.net.flow.criteria.Criterion; @@ -54,6 +56,10 @@ public class CriterionCodecTest { final IpPrefix ipPrefix6 = IpPrefix.valueOf("fe80::/64"); final MacAddress mac1 = MacAddress.valueOf("00:00:11:00:00:01"); final TpPort tpPort = TpPort.tpPort(40000); + final int tributaryPortNumber = 11; + final int tributarySlotLen = 80; + final byte[] tributarySlotBitmap = new byte[] {1, 2, 3, 4, 2, 3, 4, 2, 3, 4}; + /** * Sets up for each test. Creates a context and fetches the criterion @@ -427,4 +433,31 @@ public class CriterionCodecTest { ObjectNode result = criterionCodec.encode(criterion, context); assertThat(result, matchesCriterion(criterion)); } + + /** + * Tests Odu Signal ID criterion. + */ + @Test + public void matchOduSignalIdTest() { + + OduSignalId oduSignalId = OduSignalId.oduSignalId(tributaryPortNumber, tributarySlotLen, tributarySlotBitmap); + + Criterion criterion = Criteria.matchOduSignalId(oduSignalId); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests Odu Signal Type criterion. + */ + @Test + public void matchOduSignalTypeTest() { + + OduSignalType signalType = OduSignalType.ODU2; + + Criterion criterion = Criteria.matchOduSignalType(signalType); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + } diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/CriterionJsonMatcher.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/CriterionJsonMatcher.java index bb3acad5..b00632c3 100644 --- a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/CriterionJsonMatcher.java +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/CriterionJsonMatcher.java @@ -15,13 +15,14 @@ */ package org.onosproject.codec.impl; -import com.google.common.base.Joiner; +import java.util.Objects; + import org.hamcrest.Description; import org.hamcrest.TypeSafeDiagnosingMatcher; +import org.onlab.util.HexString; import org.onosproject.net.OchSignal; +import org.onosproject.net.OduSignalId; import org.onosproject.net.flow.criteria.Criterion; - -import com.fasterxml.jackson.databind.JsonNode; import org.onosproject.net.flow.criteria.EthCriterion; import org.onosproject.net.flow.criteria.EthTypeCriterion; import org.onosproject.net.flow.criteria.IPCriterion; @@ -40,6 +41,8 @@ import org.onosproject.net.flow.criteria.MetadataCriterion; import org.onosproject.net.flow.criteria.MplsCriterion; import org.onosproject.net.flow.criteria.OchSignalCriterion; import org.onosproject.net.flow.criteria.OchSignalTypeCriterion; +import org.onosproject.net.flow.criteria.OduSignalIdCriterion; +import org.onosproject.net.flow.criteria.OduSignalTypeCriterion; import org.onosproject.net.flow.criteria.PortCriterion; import org.onosproject.net.flow.criteria.SctpPortCriterion; import org.onosproject.net.flow.criteria.TcpPortCriterion; @@ -47,7 +50,8 @@ import org.onosproject.net.flow.criteria.UdpPortCriterion; import org.onosproject.net.flow.criteria.VlanIdCriterion; import org.onosproject.net.flow.criteria.VlanPcpCriterion; -import java.util.Objects; +import com.fasterxml.jackson.databind.JsonNode; +import com.google.common.base.Joiner; /** * Hamcrest matcher for criterion objects. @@ -496,6 +500,44 @@ public final class CriterionJsonMatcher extends return true; } + /** + * Matches an ODU signal ID criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(OduSignalIdCriterion criterion) { + final OduSignalId oduSignal = criterion.oduSignalId(); + final JsonNode jsonOduSignal = jsonCriterion.get(CriterionCodec.ODU_SIGNAL_ID); + int jsonTpn = jsonOduSignal.get(CriterionCodec.TRIBUTARY_PORT_NUMBER).intValue(); + int jsonTsLen = jsonOduSignal.get(CriterionCodec.TRIBUTARY_SLOT_LEN).intValue(); + byte[] jsonTributaryBitMap = HexString.fromHexString( + jsonOduSignal.get(CriterionCodec.TRIBUTARY_SLOT_BITMAP).asText()); + OduSignalId jsonOduSignalId = OduSignalId.oduSignalId(jsonTpn, jsonTsLen, jsonTributaryBitMap); + if (!oduSignal.equals(jsonOduSignalId)) { + description.appendText("oduSignalId was " + criterion); + return false; + } + return true; + } + + /** + * Matches an ODU signal Type criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(OduSignalTypeCriterion criterion) { + final String signalType = criterion.signalType().name(); + final String jsonOduSignalType = jsonCriterion.get("oduSignalType").textValue(); + if (!signalType.equals(jsonOduSignalType)) { + description.appendText("signalType was " + signalType); + return false; + } + return true; + } + + @Override public boolean matchesSafely(JsonNode jsonCriterion, Description description) { @@ -594,6 +636,12 @@ public final class CriterionJsonMatcher extends case OCH_SIGTYPE: return matchCriterion((OchSignalTypeCriterion) criterion); + case ODU_SIGID: + return matchCriterion((OduSignalIdCriterion) criterion); + + case ODU_SIGTYPE: + return matchCriterion((OduSignalTypeCriterion) criterion); + default: // Don't know how to format this type description.appendText("unknown criterion type " + diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/FlowRuleCodecTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/FlowRuleCodecTest.java index 6c88ac1e..f6a92131 100644 --- a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/FlowRuleCodecTest.java +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/FlowRuleCodecTest.java @@ -15,6 +15,15 @@ */ package org.onosproject.codec.impl; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.onosproject.net.NetTestTools.APP_ID; + import java.io.IOException; import java.io.InputStream; import java.util.SortedMap; @@ -35,6 +44,8 @@ import org.onosproject.net.ChannelSpacing; import org.onosproject.net.GridType; import org.onosproject.net.Lambda; import org.onosproject.net.OchSignal; +import org.onosproject.net.OchSignalType; +import org.onosproject.net.OduSignalType; import org.onosproject.net.PortNumber; import org.onosproject.net.flow.FlowRule; import org.onosproject.net.flow.criteria.Criterion; @@ -55,6 +66,9 @@ import org.onosproject.net.flow.criteria.Icmpv6TypeCriterion; import org.onosproject.net.flow.criteria.IndexedLambdaCriterion; import org.onosproject.net.flow.criteria.MplsCriterion; import org.onosproject.net.flow.criteria.OchSignalCriterion; +import org.onosproject.net.flow.criteria.OchSignalTypeCriterion; +import org.onosproject.net.flow.criteria.OduSignalIdCriterion; +import org.onosproject.net.flow.criteria.OduSignalTypeCriterion; import org.onosproject.net.flow.criteria.PortCriterion; import org.onosproject.net.flow.criteria.SctpPortCriterion; import org.onosproject.net.flow.criteria.TcpPortCriterion; @@ -62,9 +76,6 @@ import org.onosproject.net.flow.criteria.TunnelIdCriterion; import org.onosproject.net.flow.criteria.UdpPortCriterion; import org.onosproject.net.flow.criteria.VlanIdCriterion; import org.onosproject.net.flow.criteria.VlanPcpCriterion; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ObjectNode; import org.onosproject.net.flow.instructions.Instruction; import org.onosproject.net.flow.instructions.Instructions; import org.onosproject.net.flow.instructions.L0ModificationInstruction; @@ -72,14 +83,8 @@ import org.onosproject.net.flow.instructions.L2ModificationInstruction; import org.onosproject.net.flow.instructions.L3ModificationInstruction; import org.onosproject.net.flow.instructions.L4ModificationInstruction; -import static org.easymock.EasyMock.createMock; -import static org.easymock.EasyMock.expect; -import static org.easymock.EasyMock.replay; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.instanceOf; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.onosproject.net.NetTestTools.APP_ID; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; /** * Flow rule codec unit tests. @@ -382,7 +387,7 @@ public class FlowRuleCodecTest { checkCommonData(rule); - assertThat(rule.selector().criteria().size(), is(33)); + assertThat(rule.selector().criteria().size(), is(36)); rule.selector().criteria() .stream() @@ -518,6 +523,25 @@ public class FlowRuleCodecTest { criterion = getCriterion(Criterion.Type.TUNNEL_ID); assertThat(((TunnelIdCriterion) criterion).tunnelId(), is(100L)); + + criterion = getCriterion(Criterion.Type.OCH_SIGTYPE); + assertThat(((OchSignalTypeCriterion) criterion).signalType(), + is(OchSignalType.FIXED_GRID)); + + criterion = getCriterion(Criterion.Type.ODU_SIGTYPE); + assertThat(((OduSignalTypeCriterion) criterion).signalType(), + is(OduSignalType.ODU4)); + + + criterion = getCriterion(Criterion.Type.ODU_SIGID); + assertThat(((OduSignalIdCriterion) criterion).oduSignalId().tributaryPortNumber(), + is(1)); + + assertThat(((OduSignalIdCriterion) criterion).oduSignalId().tributarySlotLength(), + is(80)); + + assertThat(((OduSignalIdCriterion) criterion).oduSignalId().tributarySlotBitmap(), + is(new byte [] {1, 1, 1, 1, 1, 1, 1, 1, 1, 1})); } /** diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionCodecTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionCodecTest.java index bafbc0f1..f7b0261e 100644 --- a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionCodecTest.java +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionCodecTest.java @@ -15,6 +15,10 @@ */ package org.onosproject.codec.impl; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.notNullValue; +import static org.onosproject.codec.impl.InstructionJsonMatcher.matchesInstruction; + import org.junit.Before; import org.junit.Test; import org.onlab.packet.Ip4Address; @@ -28,26 +32,23 @@ import org.onosproject.net.ChannelSpacing; import org.onosproject.net.GridType; import org.onosproject.net.IndexedLambda; import org.onosproject.net.Lambda; +import org.onosproject.net.OduSignalId; import org.onosproject.net.PortNumber; import org.onosproject.net.flow.instructions.Instruction; import org.onosproject.net.flow.instructions.Instructions; import org.onosproject.net.flow.instructions.L0ModificationInstruction; +import org.onosproject.net.flow.instructions.L1ModificationInstruction; import org.onosproject.net.flow.instructions.L2ModificationInstruction; import org.onosproject.net.flow.instructions.L3ModificationInstruction; import com.fasterxml.jackson.databind.node.ObjectNode; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.notNullValue; -import static org.onosproject.codec.impl.InstructionJsonMatcher.matchesInstruction; - /** * Unit tests for Instruction codec. */ public class InstructionCodecTest { CodecContext context; JsonCodec instructionCodec; - /** * Sets up for each test. Creates a context and fetches the instruction * codec. @@ -121,6 +122,20 @@ public class InstructionCodecTest { assertThat(instructionJson, matchesInstruction(instruction)); } + /** + * Tests the encoding of mod ODU signal ID instructions. + */ + @Test + public void modOduSignalIdInstructionTest() { + OduSignalId oduSignalId = OduSignalId.oduSignalId(1, 8, new byte [] {8, 0, 0, 0, 0, 0, 0, 0, 0, 0}); + L1ModificationInstruction.ModOduSignalIdInstruction instruction = + (L1ModificationInstruction.ModOduSignalIdInstruction) + Instructions.modL1OduSignalId(oduSignalId); + ObjectNode instructionJson = + instructionCodec.encode(instruction, context); + assertThat(instructionJson, matchesInstruction(instruction)); + } + /** * Tests the encoding of mod ether instructions. */ 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 c3cdca0f..9ffb3c3a 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 @@ -17,15 +17,25 @@ package org.onosproject.codec.impl; import org.hamcrest.Description; import org.hamcrest.TypeSafeDiagnosingMatcher; +import org.onlab.util.HexString; +import org.onosproject.net.OduSignalId; import org.onosproject.net.flow.instructions.Instruction; +import org.onosproject.net.flow.instructions.Instructions.DropInstruction; +import org.onosproject.net.flow.instructions.Instructions.NoActionInstruction; +import org.onosproject.net.flow.instructions.Instructions.OutputInstruction; +import org.onosproject.net.flow.instructions.L0ModificationInstruction.ModLambdaInstruction; +import org.onosproject.net.flow.instructions.L0ModificationInstruction.ModOchSignalInstruction; +import org.onosproject.net.flow.instructions.L1ModificationInstruction.ModOduSignalIdInstruction; +import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction; +import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsLabelInstruction; +import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction; +import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanPcpInstruction; +import org.onosproject.net.flow.instructions.L2ModificationInstruction.PushHeaderInstructions; +import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPInstruction; +import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPv6FlowLabelInstruction; import com.fasterxml.jackson.databind.JsonNode; -import static org.onosproject.net.flow.instructions.Instructions.*; -import static org.onosproject.net.flow.instructions.L0ModificationInstruction.*; -import static org.onosproject.net.flow.instructions.L2ModificationInstruction.*; -import static org.onosproject.net.flow.instructions.L3ModificationInstruction.*; - /** * Hamcrest matcher for instructions. */ @@ -133,7 +143,7 @@ public final class InstructionJsonMatcher extends TypeSafeDiagnosingMatcher store.addNode(node.id(), node.ip(), node.tcpPort())); + clusterMetadataService.getClusterMetadata() + .getNodes() + .forEach(node -> store.addNode(node.id(), node.ip(), node.tcpPort())); log.info("Started"); } @@ -119,11 +127,16 @@ public class ClusterManager } @Override - public void formCluster(Set nodes, String ipPrefix) { + public void formCluster(Set nodes) { checkNotNull(nodes, "Nodes cannot be null"); checkArgument(!nodes.isEmpty(), "Nodes cannot be empty"); - checkNotNull(ipPrefix, "IP prefix cannot be null"); - clusterDefinitionService.formCluster(nodes, ipPrefix); + + ClusterMetadata metadata = ClusterMetadata.builder() + .withName("default") + .withControllerNodes(nodes) + .withPartitions(buildDefaultPartitions(nodes)) + .build(); + clusterMetadataService.setClusterMetadata(metadata); try { log.warn("Shutting down container for cluster reconfiguration!"); systemService.reboot("now", SystemService.Swipe.NONE); @@ -153,4 +166,21 @@ public class ClusterManager post(event); } } + + private static Collection buildDefaultPartitions(Collection nodes) { + List sorted = new ArrayList<>(nodes); + Collections.sort(sorted, (o1, o2) -> o1.id().toString().compareTo(o2.id().toString())); + Collection partitions = Lists.newArrayList(); + + int length = nodes.size(); + int count = 3; + for (int i = 0; i < length; i++) { + Set set = new HashSet<>(count); + for (int j = 0; j < count; j++) { + set.add(sorted.get((i + j) % length).id()); + } + partitions.add(new Partition("p" + (i + 1), set)); + } + return partitions; + } } diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/cluster/impl/ClusterMetadataManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/cluster/impl/ClusterMetadataManager.java new file mode 100644 index 00000000..a0f7a833 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/cluster/impl/ClusterMetadataManager.java @@ -0,0 +1,116 @@ +package org.onosproject.cluster.impl; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.slf4j.LoggerFactory.getLogger; + +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.Collection; +import java.util.Enumeration; + +import org.apache.felix.scr.annotations.Activate; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Deactivate; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.ReferenceCardinality; +import org.apache.felix.scr.annotations.Service; +import org.onlab.packet.IpAddress; +import org.onosproject.cluster.ClusterMetadata; +import org.onosproject.cluster.ClusterMetadataEvent; +import org.onosproject.cluster.ClusterMetadataEventListener; +import org.onosproject.cluster.ClusterMetadataService; +import org.onosproject.cluster.ClusterMetadataStore; +import org.onosproject.cluster.ClusterMetadataStoreDelegate; +import org.onosproject.cluster.ControllerNode; +import org.onosproject.event.AbstractListenerManager; +import org.onosproject.store.service.Versioned; +import org.slf4j.Logger; + +/** + * Implementation of ClusterMetadataService. + */ +@Component(immediate = true) +@Service +public class ClusterMetadataManager + extends AbstractListenerManager + implements ClusterMetadataService { + + private ControllerNode localNode; + private final Logger log = getLogger(getClass()); + + private ClusterMetadataStoreDelegate delegate = new InternalStoreDelegate(); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ClusterMetadataStore store; + + @Activate + public void activate() { + store.setDelegate(delegate); + eventDispatcher.addSink(ClusterMetadataEvent.class, listenerRegistry); + establishSelfIdentity(); + log.info("Started"); + } + + @Deactivate + public void deactivate() { + store.unsetDelegate(delegate); + eventDispatcher.removeSink(ClusterMetadataEvent.class); + log.info("Stopped"); + } + + @Override + public ClusterMetadata getClusterMetadata() { + return Versioned.valueOrElse(store.getClusterMetadata(), null); + } + + @Override + public ControllerNode getLocalNode() { + return localNode; + } + + @Override + public void setClusterMetadata(ClusterMetadata metadata) { + checkNotNull(metadata, "Cluster metadata cannot be null"); + store.setClusterMetadata(metadata); + } + + // Store delegate to re-post events emitted from the store. + private class InternalStoreDelegate implements ClusterMetadataStoreDelegate { + @Override + public void notify(ClusterMetadataEvent event) { + post(event); + } + } + + private IpAddress findLocalIp(Collection controllerNodes) throws SocketException { + Enumeration interfaces = + NetworkInterface.getNetworkInterfaces(); + while (interfaces.hasMoreElements()) { + NetworkInterface iface = interfaces.nextElement(); + Enumeration inetAddresses = iface.getInetAddresses(); + while (inetAddresses.hasMoreElements()) { + IpAddress ip = IpAddress.valueOf(inetAddresses.nextElement()); + if (controllerNodes.stream() + .map(ControllerNode::ip) + .anyMatch(nodeIp -> ip.equals(nodeIp))) { + return ip; + } + } + } + throw new IllegalStateException("Unable to determine local ip"); + } + + private void establishSelfIdentity() { + try { + IpAddress ip = findLocalIp(getClusterMetadata().getNodes()); + localNode = getClusterMetadata().getNodes() + .stream() + .filter(node -> node.ip().equals(ip)) + .findFirst() + .get(); + } catch (SocketException e) { + throw new IllegalStateException("Cannot determine local IP", e); + } + } +} \ No newline at end of file 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 19377cf6..8f601497 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 @@ -112,10 +112,10 @@ public final class OpticalPortOperator implements ConfigOperator { return new OduCltPortDescription(port, odu.isEnabled(), odu.signalType(), sa); case PACKET: case FIBER: + case COPPER: return new DefaultPortDescription(port, descr.isEnabled(), descr.type(), descr.portSpeed(), sa); default: - // this includes copper ports. log.warn("Unsupported optical port type {} - can't update", descr.type()); return descr; } diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FlowObjectiveCompositionUtil.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FlowObjectiveCompositionUtil.java index 137aca1e..0a1af6f5 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FlowObjectiveCompositionUtil.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FlowObjectiveCompositionUtil.java @@ -29,9 +29,11 @@ import org.onosproject.net.flow.criteria.VlanPcpCriterion; import org.onosproject.net.flow.criteria.MplsCriterion; import org.onosproject.net.flow.criteria.IPCriterion; import org.onosproject.net.flow.criteria.IPv6FlowLabelCriterion; +import org.onosproject.net.flow.criteria.OduSignalIdCriterion; import org.onosproject.net.flow.criteria.Criteria; import org.onosproject.net.flow.instructions.Instruction; import org.onosproject.net.flow.instructions.L0ModificationInstruction; +import org.onosproject.net.flow.instructions.L1ModificationInstruction; import org.onosproject.net.flow.instructions.L2ModificationInstruction; import org.onosproject.net.flow.instructions.L3ModificationInstruction; import org.onosproject.net.flowobjective.DefaultForwardingObjective; @@ -155,6 +157,7 @@ public final class FlowObjectiveCompositionUtil { return treatmentBuilder.build(); } + //CHECKSTYLE:OFF public static TrafficSelector revertTreatmentSelector(TrafficTreatment trafficTreatment, TrafficSelector trafficSelector) { @@ -195,14 +198,30 @@ public final class FlowObjectiveCompositionUtil { } else { return null; } - } else { - break; } default: break; } break; } + case L1MODIFICATION: { + L1ModificationInstruction l1 = (L1ModificationInstruction) instruction; + switch (l1.subtype()) { + case ODU_SIGID: + if (criterionMap.containsKey(Criterion.Type.ODU_SIGID)) { + if (((OduSignalIdCriterion) criterionMap.get((Criterion.Type.ODU_SIGID))).oduSignalId() + .equals(((L1ModificationInstruction.ModOduSignalIdInstruction) l1) + .oduSignalId())) { + criterionMap.remove(Criterion.Type.ODU_SIGID); + } else { + return null; + } + } + default: + break; + } + break; + } case L2MODIFICATION: { L2ModificationInstruction l2 = (L2ModificationInstruction) instruction; switch (l2.subtype()) { @@ -344,6 +363,7 @@ public final class FlowObjectiveCompositionUtil { return selectorBuilder.build(); } + //CHECKSTYLE:ON public static Set getTypeSet(TrafficSelector trafficSelector) { Set typeSet = new HashSet<>(); diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompiler.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompiler.java index 5fd1c85d..acc5a5d5 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompiler.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompiler.java @@ -24,12 +24,14 @@ import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.ReferenceCardinality; import org.onlab.packet.EthType; import org.onlab.packet.Ethernet; +import org.onlab.packet.MplsLabel; import org.onlab.packet.VlanId; import org.onosproject.core.ApplicationId; import org.onosproject.core.CoreService; import org.onosproject.net.ConnectPoint; import org.onosproject.net.DeviceId; import org.onosproject.net.Link; +import org.onosproject.net.LinkKey; import org.onosproject.net.PortNumber; import org.onosproject.net.flow.DefaultFlowRule; import org.onosproject.net.flow.DefaultTrafficSelector; @@ -46,24 +48,23 @@ import org.onosproject.net.intent.Intent; import org.onosproject.net.intent.IntentCompiler; import org.onosproject.net.intent.IntentExtensionService; import org.onosproject.net.intent.MplsPathIntent; -import org.onosproject.net.link.LinkStore; -import org.onosproject.net.resource.link.DefaultLinkResourceRequest; +import org.onosproject.net.newresource.ResourcePath; +import org.onosproject.net.newresource.ResourceService; import org.onosproject.net.resource.link.LinkResourceAllocations; -import org.onosproject.net.resource.link.LinkResourceRequest; -import org.onosproject.net.resource.link.LinkResourceService; -import org.onosproject.net.resource.link.MplsLabel; -import org.onosproject.net.resource.link.MplsLabelResourceAllocation; -import org.onosproject.net.resource.ResourceAllocation; -import org.onosproject.net.resource.ResourceType; import org.slf4j.Logger; import java.util.Collections; +import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import java.util.Map; +import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkNotNull; +import static org.onosproject.net.LinkKey.linkKey; import static org.slf4j.LoggerFactory.getLogger; @Component(immediate = true) @@ -78,18 +79,15 @@ public class MplsPathIntentCompiler implements IntentCompiler { protected CoreService coreService; @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected LinkResourceService resourceService; - - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected LinkStore linkStore; + protected ResourceService resourceService; protected ApplicationId appId; @Override public List compile(MplsPathIntent intent, List installable, Set resources) { - LinkResourceAllocations allocations = assignMplsLabel(intent); - List rules = generateRules(intent, allocations); + Map labels = assignMplsLabel(intent); + List rules = generateRules(intent, labels); return Collections.singletonList(new FlowRuleIntent(appId, rules, intent.resources())); } @@ -105,39 +103,60 @@ public class MplsPathIntentCompiler implements IntentCompiler { intentExtensionService.unregisterCompiler(MplsPathIntent.class); } - private LinkResourceAllocations assignMplsLabel(MplsPathIntent intent) { + private Map assignMplsLabel(MplsPathIntent intent) { // TODO: do it better... Suggestions? - Set linkRequest = Sets.newHashSetWithExpectedSize(intent.path() + Set linkRequest = Sets.newHashSetWithExpectedSize(intent.path() .links().size() - 2); for (int i = 1; i <= intent.path().links().size() - 2; i++) { - Link link = intent.path().links().get(i); + LinkKey link = linkKey(intent.path().links().get(i)); linkRequest.add(link); // add the inverse link. I want that the label is reserved both for // the direct and inverse link - linkRequest.add(linkStore.getLink(link.dst(), link.src())); + linkRequest.add(linkKey(link.dst(), link.src())); } - LinkResourceRequest.Builder request = DefaultLinkResourceRequest - .builder(intent.id(), linkRequest).addMplsRequest(); - LinkResourceAllocations reqMpls = resourceService - .requestResources(request.build()); - return reqMpls; - } + Map labels = findMplsLabels(linkRequest); + if (labels.isEmpty()) { + return Collections.emptyMap(); + } + + List resources = labels.entrySet().stream() + .map(x -> new ResourcePath(linkKey(x.getKey().src(), x.getKey().src()), x.getValue())) + .collect(Collectors.toList()); + List allocations = + resourceService.allocate(intent.id(), resources); + if (allocations.isEmpty()) { + Collections.emptyMap(); + } - private MplsLabel getMplsLabel(LinkResourceAllocations allocations, Link link) { - for (ResourceAllocation allocation : allocations - .getResourceAllocation(link)) { - if (allocation.type() == ResourceType.MPLS_LABEL) { - return ((MplsLabelResourceAllocation) allocation).mplsLabel(); + return labels; + } + private Map findMplsLabels(Set links) { + Map labels = new HashMap<>(); + for (LinkKey link : links) { + Optional label = findMplsLabel(link); + if (label.isPresent()) { + labels.put(link, label.get()); } } - log.warn("MPLS label was not assigned successfully"); - return null; + + return labels; + } + + private Optional findMplsLabel(LinkKey link) { + return resourceService.getAvailableResources(new ResourcePath(link)).stream() + .filter(x -> x.lastComponent() instanceof MplsLabel) + .map(x -> (MplsLabel) x.lastComponent()) + .findFirst(); + } + + private MplsLabel getMplsLabel(Map labels, LinkKey link) { + return labels.get(link); } private List generateRules(MplsPathIntent intent, - LinkResourceAllocations allocations) { + Map labels) { Iterator links = intent.path().links().iterator(); Link srcLink = links.next(); @@ -149,7 +168,7 @@ public class MplsPathIntentCompiler implements IntentCompiler { // Ingress traffic // Get the new MPLS label - MplsLabel mpls = getMplsLabel(allocations, link); + MplsLabel mpls = getMplsLabel(labels, linkKey(link)); checkNotNull(mpls); MplsLabel prevLabel = mpls; rules.add(ingressFlow(prev.port(), link, intent, mpls)); @@ -163,7 +182,7 @@ public class MplsPathIntentCompiler implements IntentCompiler { if (links.hasNext()) { // Transit traffic // Get the new MPLS label - mpls = getMplsLabel(allocations, link); + mpls = getMplsLabel(labels, linkKey(link)); checkNotNull(mpls); rules.add(transitFlow(prev.port(), link, intent, prevLabel, mpls)); @@ -181,7 +200,8 @@ public class MplsPathIntentCompiler implements IntentCompiler { } private FlowRule ingressFlow(PortNumber inPort, Link link, - MplsPathIntent intent, MplsLabel label) { + MplsPathIntent intent, + MplsLabel label) { TrafficSelector.Builder ingressSelector = DefaultTrafficSelector .builder(intent.selector()); @@ -193,10 +213,10 @@ public class MplsPathIntentCompiler implements IntentCompiler { .matchMplsLabel(intent.ingressLabel().get()); // Swap the MPLS label - treat.setMpls(label.label()); + treat.setMpls(label); } else { // Push and set the MPLS label - treat.pushMpls().setMpls(label.label()); + treat.pushMpls().setMpls(label); } // Add the output action treat.setOutput(link.src().port()); @@ -205,21 +225,21 @@ public class MplsPathIntentCompiler implements IntentCompiler { } private FlowRule transitFlow(PortNumber inPort, Link link, - MplsPathIntent intent, - MplsLabel prevLabel, - MplsLabel outLabel) { + MplsPathIntent intent, + MplsLabel prevLabel, + MplsLabel outLabel) { // Ignore the ingress Traffic Selector and use only the MPLS label // assigned in the previous link TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); selector.matchInPort(inPort).matchEthType(Ethernet.MPLS_UNICAST) - .matchMplsLabel(prevLabel.label()); + .matchMplsLabel(prevLabel); TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder(); // Set the new label only if the label on the packet is // different if (!prevLabel.equals(outLabel)) { - treat.setMpls(outLabel.label()); + treat.setMpls(outLabel); } treat.setOutput(link.src().port()); @@ -227,14 +247,14 @@ public class MplsPathIntentCompiler implements IntentCompiler { } private FlowRule egressFlow(PortNumber inPort, Link link, - MplsPathIntent intent, - MplsLabel prevLabel) { + MplsPathIntent intent, + MplsLabel prevLabel) { // egress point: either set the egress MPLS label or pop the // MPLS label based on the intent annotations TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); selector.matchInPort(inPort).matchEthType(Ethernet.MPLS_UNICAST) - .matchMplsLabel(prevLabel.label()); + .matchMplsLabel(prevLabel); // apply the intent's treatments TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder(intent 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 c6eb7c5a..fce8498c 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 @@ -17,6 +17,7 @@ package org.onosproject.net.intent.impl.compiler; import org.apache.commons.lang3.tuple.Pair; import org.apache.felix.scr.annotations.Activate; +import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Deactivate; import org.apache.felix.scr.annotations.Modified; import org.apache.felix.scr.annotations.Property; @@ -70,7 +71,7 @@ import static com.google.common.base.Preconditions.checkArgument; * An intent compiler for {@link org.onosproject.net.intent.OpticalCircuitIntent}. */ // For now, remove component designation until dependency on the new resource manager is available. -// @Component(immediate = true) +@Component(immediate = true) public class OpticalCircuitIntentCompiler implements IntentCompiler { private static final Logger log = LoggerFactory.getLogger(OpticalCircuitIntentCompiler.class); 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 eb5b4af8..d6725b7c 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,7 +16,11 @@ package org.onosproject.net.intent.impl.compiler; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; +import com.google.common.collect.Sets; import org.apache.felix.scr.annotations.Activate; +import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Deactivate; import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.ReferenceCardinality; @@ -24,6 +28,7 @@ import org.onlab.util.Frequency; import org.onosproject.net.AnnotationKeys; import org.onosproject.net.ConnectPoint; import org.onosproject.net.DeviceId; +import org.onosproject.net.IndexedLambda; import org.onosproject.net.Link; import org.onosproject.net.OchPort; import org.onosproject.net.OchSignal; @@ -38,32 +43,29 @@ import org.onosproject.net.intent.IntentExtensionService; import org.onosproject.net.intent.OpticalConnectivityIntent; import org.onosproject.net.intent.OpticalPathIntent; import org.onosproject.net.intent.impl.IntentCompilationException; +import org.onosproject.net.newresource.ResourceAllocation; import org.onosproject.net.newresource.ResourcePath; import org.onosproject.net.newresource.ResourceService; -import org.onosproject.net.resource.ResourceType; -import org.onosproject.net.resource.link.DefaultLinkResourceRequest; -import org.onosproject.net.resource.link.LambdaResource; -import org.onosproject.net.resource.link.LambdaResourceAllocation; import org.onosproject.net.resource.link.LinkResourceAllocations; -import org.onosproject.net.resource.link.LinkResourceRequest; -import org.onosproject.net.resource.link.LinkResourceService; import org.onosproject.net.topology.LinkWeight; import org.onosproject.net.topology.Topology; import org.onosproject.net.topology.TopologyService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Collections; import java.util.List; import java.util.Set; import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkArgument; +import static org.onosproject.net.LinkKey.linkKey; /** * An intent compiler for {@link org.onosproject.net.intent.OpticalConnectivityIntent}. */ // For now, remove component designation until dependency on the new resource manager is available. -// @Component(immediate = true) +@Component(immediate = true) public class OpticalConnectivityIntentCompiler implements IntentCompiler { protected static final Logger log = LoggerFactory.getLogger(OpticalConnectivityIntentCompiler.class); @@ -80,9 +82,6 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler linkAllocs.getResourceAllocation(x).stream()) - .filter(x -> x.type() == ResourceType.LAMBDA) - .findFirst() - .map(x -> (LambdaResourceAllocation) x) - .orElse(null); - } - /** * Request and reserve first available wavelength across path. * * @param path path in WDM topology - * @return first available lambda resource allocation + * @return first available lambda allocated */ - private LinkResourceAllocations assignWavelength(Intent intent, Path path) { - LinkResourceRequest.Builder request = - DefaultLinkResourceRequest.builder(intent.id(), path.links()) - .addLambdaRequest(); - - LinkResourceAllocations allocations = linkResourceService.requestResources(request.build()); - - if (!checkWavelengthContinuity(allocations, path)) { - linkResourceService.releaseResources(allocations); + private IndexedLambda assignWavelength(Intent intent, Path path) { + Set lambdas = findCommonLambdasOverLinks(path.links()); + if (lambdas.isEmpty()) { return null; } - return allocations; - } + IndexedLambda minLambda = findFirstLambda(lambdas); + List lambdaResources = path.links().stream() + .map(x -> new ResourcePath(linkKey(x.src(), x.dst()))) + .map(x -> ResourcePath.child(x, minLambda)) + .collect(Collectors.toList()); - /** - * Checks wavelength continuity constraint across path, i.e., an identical lambda is used on all links. - * @return true if wavelength continuity is met, false otherwise - */ - private boolean checkWavelengthContinuity(LinkResourceAllocations allocations, Path path) { - if (allocations == null) { - return false; + List allocations = resourceService.allocate(intent.id(), lambdaResources); + if (allocations.isEmpty()) { + log.info("Resource allocation for {} failed (resource request: {})", intent, lambdaResources); } - List lambdas = path.links().stream() - .flatMap(x -> allocations.getResourceAllocation(x).stream()) - .filter(x -> x.type() == ResourceType.LAMBDA) - .map(x -> ((LambdaResourceAllocation) x).lambda()) - .collect(Collectors.toList()); + return minLambda; + } - LambdaResource lambda = null; - for (LambdaResource nextLambda: lambdas) { - if (nextLambda == null) { - return false; - } - if (lambda == null) { - lambda = nextLambda; - continue; - } - if (!lambda.equals(nextLambda)) { - return false; - } - } + private Set findCommonLambdasOverLinks(List links) { + return links.stream() + .map(x -> new ResourcePath(linkKey(x.src(), x.dst()))) + .map(resourceService::getAvailableResources) + .map(x -> Iterables.filter(x, r -> r.lastComponent() instanceof IndexedLambda)) + .map(x -> Iterables.transform(x, r -> (IndexedLambda) r.lastComponent())) + .map(x -> (Set) ImmutableSet.copyOf(x)) + .reduce(Sets::intersection) + .orElse(Collections.emptySet()); + } - return true; + private IndexedLambda findFirstLambda(Set lambdas) { + return lambdas.stream() + .findFirst() + .get(); } private ConnectPoint staticPort(ConnectPoint connectPoint) { 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 5226967f..10fe75ea 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 @@ -41,7 +41,7 @@ import static com.google.common.base.Preconditions.checkNotNull; /** * An implementation of ResourceService. */ -@Component(immediate = true, enabled = false) +@Component(immediate = true) @Service @Beta public final class ResourceManager implements ResourceService, ResourceAdminService { @@ -126,6 +126,17 @@ public final class ResourceManager implements ResourceService, ResourceAdminServ .collect(Collectors.toList()); } + @Override + public Collection getAvailableResources(ResourcePath parent) { + checkNotNull(parent); + + Collection children = store.getChildResources(parent); + return children.stream() + // We access store twice in this method, then the store may be updated by others + .filter(x -> !store.getConsumer(x).isPresent()) + .collect(Collectors.toList()); + } + @Override public boolean isAvailable(ResourcePath resource) { checkNotNull(resource); diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/resource/impl/LinkResourceManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/resource/impl/LinkResourceManager.java index 8b9952ed..7eb189e5 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/resource/impl/LinkResourceManager.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/resource/impl/LinkResourceManager.java @@ -31,7 +31,6 @@ import org.onosproject.net.resource.ResourceType; import org.onosproject.net.resource.link.BandwidthResourceAllocation; import org.onosproject.net.resource.link.BandwidthResourceRequest; import org.onosproject.net.resource.link.DefaultLinkResourceAllocations; -import org.onosproject.net.resource.link.LambdaResource; import org.onosproject.net.resource.link.LambdaResourceAllocation; import org.onosproject.net.resource.link.LambdaResourceRequest; import org.onosproject.net.resource.link.LinkResourceAllocations; @@ -46,15 +45,12 @@ import org.onosproject.net.resource.link.MplsLabelResourceAllocation; import org.onosproject.net.resource.link.MplsLabelResourceRequest; import org.slf4j.Logger; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.Map; +import java.util.Optional; import java.util.Set; -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; import static org.onosproject.security.AppGuard.checkPermission; import static org.slf4j.LoggerFactory.getLogger; import static org.onosproject.security.AppPermission.Type.*; @@ -86,67 +82,6 @@ public class LinkResourceManager log.info("Stopped"); } - /** - * Returns available lambdas on specified link. - * - * @param link the link - * @return available lambdas on specified link - */ - private Set getAvailableLambdas(Link link) { - checkNotNull(link); - Set resAllocs = store.getFreeResources(link); - if (resAllocs == null) { - return Collections.emptySet(); - } - Set lambdas = new HashSet<>(); - for (ResourceAllocation res : resAllocs) { - if (res.type() == ResourceType.LAMBDA) { - lambdas.add(((LambdaResourceAllocation) res).lambda()); - } - } - return lambdas; - } - - - /** - * Returns available lambdas on specified links. - * - * @param links the links - * @return available lambdas on specified links - */ - private Iterable getAvailableLambdas(Iterable links) { - checkNotNull(links); - Iterator i = links.iterator(); - checkArgument(i.hasNext()); - Set lambdas = new HashSet<>(getAvailableLambdas(i.next())); - while (i.hasNext()) { - lambdas.retainAll(getAvailableLambdas(i.next())); - } - return lambdas; - } - - - /** - * Returns available MPLS label on specified link. - * - * @param link the link - * @return available MPLS labels on specified link - */ - private Iterable getAvailableMplsLabels(Link link) { - Set resAllocs = store.getFreeResources(link); - if (resAllocs == null) { - return Collections.emptySet(); - } - Set mplsLabels = new HashSet<>(); - for (ResourceAllocation res : resAllocs) { - if (res.type() == ResourceType.MPLS_LABEL) { - - mplsLabels.add(((MplsLabelResourceAllocation) res).mplsLabel()); - } - } - - return mplsLabels; - } @Override public LinkResourceAllocations requestResources(LinkResourceRequest req) { @@ -164,26 +99,23 @@ public class LinkResourceManager allocs.add(new BandwidthResourceAllocation(br.bandwidth())); break; case LAMBDA: - Iterator lambdaIterator = - getAvailableLambdas(req.links()).iterator(); - if (lambdaIterator.hasNext()) { - allocs.add(new LambdaResourceAllocation(lambdaIterator.next())); - } else { - log.info("Failed to allocate lambda resource."); - return null; - } + LambdaResourceRequest lr = (LambdaResourceRequest) r; + allocs.add(new LambdaResourceAllocation(lr.lambda())); break; case MPLS_LABEL: for (Link link : req.links()) { if (allocsPerLink.get(link) == null) { allocsPerLink.put(link, new HashSet<>()); } - Iterator mplsIter = getAvailableMplsLabels(link) - .iterator(); - if (mplsIter.hasNext()) { - allocsPerLink.get(link) - .add(new MplsLabelResourceAllocation(mplsIter - .next())); + + Optional label = req.resources(link).stream() + .filter(x -> x.type() == ResourceType.MPLS_LABEL) + .map(x -> (MplsLabelResourceRequest) x) + .map(MplsLabelResourceRequest::mplsLabel) + .findFirst(); + + if (label.isPresent()) { + allocsPerLink.get(link).add(new MplsLabelResourceAllocation(label.get())); } else { log.info("Failed to allocate MPLS resource."); break; @@ -258,10 +190,12 @@ public class LinkResourceManager ((BandwidthResourceAllocation) alloc).bandwidth())); break; case LAMBDA: - result.add(new LambdaResourceRequest()); + result.add(new LambdaResourceRequest( + ((LambdaResourceAllocation) alloc).lambda())); break; case MPLS_LABEL: - result.add(new MplsLabelResourceRequest()); + result.add(new MplsLabelResourceRequest( + ((MplsLabelResourceAllocation) alloc).mplsLabel())); break; default: break; diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MockResourceService.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MockResourceService.java new file mode 100644 index 00000000..06b2c81e --- /dev/null +++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MockResourceService.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.intent.impl.compiler; + +import com.google.common.collect.ImmutableList; +import org.onlab.packet.MplsLabel; +import org.onosproject.net.newresource.ResourceAllocation; +import org.onosproject.net.newresource.ResourceConsumer; +import org.onosproject.net.newresource.ResourcePath; +import org.onosproject.net.newresource.ResourceService; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +class MockResourceService implements ResourceService { + + private final Map assignment = new HashMap<>(); + + @Override + public List allocate(ResourceConsumer consumer, List resources) { + assignment.putAll( + resources.stream().collect(Collectors.toMap(x -> x, x -> consumer)) + ); + + return resources.stream() + .map(x -> new ResourceAllocation(x, consumer)) + .collect(Collectors.toList()); + } + + @Override + public boolean release(List allocations) { + allocations.forEach(x -> assignment.remove(x.resource())); + + return true; + } + + @Override + public boolean release(ResourceConsumer consumer) { + List resources = assignment.entrySet().stream() + .filter(x -> x.getValue().equals(consumer)) + .map(Map.Entry::getKey) + .collect(Collectors.toList()); + List allocations = resources.stream() + .map(x -> new ResourceAllocation(x, consumer)) + .collect(Collectors.toList()); + + return release(allocations); + } + + @Override + public Optional getResourceAllocation(ResourcePath resource) { + return Optional.ofNullable(assignment.get(resource)) + .map(x -> new ResourceAllocation(resource, x)); + } + + @Override + public Collection getResourceAllocations(ResourcePath parent, Class cls) { + return assignment.entrySet().stream() + .filter(x -> x.getKey().parent().isPresent()) + .filter(x -> x.getKey().parent().get().equals(parent)) + .map(x -> new ResourceAllocation(x.getKey(), x.getValue())) + .collect(Collectors.toList()); + } + + @Override + public Collection getResourceAllocations(ResourceConsumer consumer) { + return assignment.entrySet().stream() + .filter(x -> x.getValue().equals(consumer)) + .map(x -> new ResourceAllocation(x.getKey(), x.getValue())) + .collect(Collectors.toList()); + } + + @Override + public Collection getAvailableResources(ResourcePath parent) { + ResourcePath resource = ResourcePath.child(parent, MplsLabel.mplsLabel(10)); + return ImmutableList.of(resource); + } + + @Override + public boolean isAvailable(ResourcePath resource) { + return true; + } +} diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompilerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompilerTest.java index 771a9883..6cceee12 100644 --- a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompilerTest.java +++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompilerTest.java @@ -41,10 +41,8 @@ import org.onosproject.net.flow.TrafficTreatment; import org.onosproject.net.intent.FlowRuleIntent; import org.onosproject.net.intent.Intent; import org.onosproject.net.intent.IntentExtensionService; -import org.onosproject.net.intent.IntentTestsMocks; import org.onosproject.net.intent.MockIdGenerator; import org.onosproject.net.intent.MplsPathIntent; -import org.onosproject.store.trivial.SimpleLinkStore; import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.expect; @@ -52,6 +50,7 @@ import static org.easymock.EasyMock.replay; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; +import static org.onosproject.net.DefaultEdgeLink.createEdgeLink; import static org.onosproject.net.Link.Type.DIRECT; import static org.onosproject.net.NetTestTools.APP_ID; import static org.onosproject.net.NetTestTools.PID; @@ -61,10 +60,12 @@ public class MplsPathIntentCompilerTest { private final ApplicationId appId = new TestApplicationId("test"); + private final ConnectPoint d1pi = connectPoint("s1", 100); private final ConnectPoint d1p1 = connectPoint("s1", 0); private final ConnectPoint d2p0 = connectPoint("s2", 0); private final ConnectPoint d2p1 = connectPoint("s2", 1); private final ConnectPoint d3p1 = connectPoint("s3", 1); + private final ConnectPoint d3pe = connectPoint("s3", 100); private final TrafficSelector selector = DefaultTrafficSelector.builder().build(); private final TrafficTreatment treatment = DefaultTrafficTreatment.builder().build(); @@ -75,8 +76,10 @@ public class MplsPathIntentCompilerTest { Optional.of(MplsLabel.mplsLabel(20)); private final List links = Arrays.asList( + createEdgeLink(d1pi, true), new DefaultLink(PID, d1p1, d2p0, DIRECT), - new DefaultLink(PID, d2p1, d3p1, DIRECT) + new DefaultLink(PID, d2p1, d3p1, DIRECT), + createEdgeLink(d3pe, false) ); private IdGenerator idGenerator = new MockIdGenerator(); @@ -92,8 +95,7 @@ public class MplsPathIntentCompilerTest { expect(coreService.registerApplication("org.onosproject.net.intent")) .andReturn(appId); sut.coreService = coreService; - sut.linkStore = new SimpleLinkStore(); - sut.resourceService = new IntentTestsMocks.MockResourceService(); + sut.resourceService = new MockResourceService(); Intent.bindIdGenerator(idGenerator); @@ -128,7 +130,7 @@ public class MplsPathIntentCompilerTest { assertThat(compiled, hasSize(1)); Collection rules = ((FlowRuleIntent) compiled.get(0)).flowRules(); - assertThat(rules, hasSize(1)); + assertThat(rules, hasSize(3)); FlowRule rule = rules.stream() .filter(x -> x.deviceId().equals(d2p0.deviceId())) @@ -139,4 +141,5 @@ public class MplsPathIntentCompilerTest { sut.deactivate(); } + } diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/proxyarp/impl/ProxyArpManagerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/proxyarp/impl/ProxyArpManagerTest.java index 1a160d98..3e806a73 100644 --- a/framework/src/onos/core/net/src/test/java/org/onosproject/net/proxyarp/impl/ProxyArpManagerTest.java +++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/proxyarp/impl/ProxyArpManagerTest.java @@ -21,11 +21,19 @@ import org.junit.Before; import org.junit.Test; import org.onlab.packet.ARP; import org.onlab.packet.Ethernet; +import org.onlab.packet.ICMP6; +import org.onlab.packet.IPacket; +import org.onlab.packet.IPv6; import org.onlab.packet.Ip4Address; import org.onlab.packet.Ip4Prefix; +import org.onlab.packet.Ip6Address; +import org.onlab.packet.Ip6Prefix; import org.onlab.packet.IpPrefix; import org.onlab.packet.MacAddress; import org.onlab.packet.VlanId; +import org.onlab.packet.ndp.NeighborAdvertisement; +import org.onlab.packet.ndp.NeighborDiscoveryOptions; +import org.onlab.packet.ndp.NeighborSolicitation; import org.onosproject.incubator.net.intf.Interface; import org.onosproject.incubator.net.intf.InterfaceService; import org.onosproject.net.ConnectPoint; @@ -66,9 +74,13 @@ import static org.easymock.EasyMock.anyObject; import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.replay; +import static org.hamcrest.Matchers.anyOf; +import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; /** @@ -83,6 +95,8 @@ public class ProxyArpManagerTest { private static final Ip4Address IP1 = Ip4Address.valueOf("192.168.1.1"); private static final Ip4Address IP2 = Ip4Address.valueOf("192.168.1.2"); + private static final Ip6Address IP3 = Ip6Address.valueOf("1000::1"); + private static final Ip6Address IP4 = Ip6Address.valueOf("1000::2"); private static final ProviderId PID = new ProviderId("of", "foo"); @@ -90,8 +104,14 @@ public class ProxyArpManagerTest { private static final VlanId VLAN2 = VlanId.vlanId((short) 2); private static final MacAddress MAC1 = MacAddress.valueOf("00:00:11:00:00:01"); private static final MacAddress MAC2 = MacAddress.valueOf("00:00:22:00:00:02"); + private static final MacAddress MAC3 = MacAddress.valueOf("00:00:33:00:00:03"); + private static final MacAddress MAC4 = MacAddress.valueOf("00:00:44:00:00:04"); + private static final MacAddress SOLICITED_MAC3 = MacAddress.valueOf("33:33:FF:00:00:01"); private static final HostId HID1 = HostId.hostId(MAC1, VLAN1); private static final HostId HID2 = HostId.hostId(MAC2, VLAN1); + private static final HostId HID3 = HostId.hostId(MAC3, VLAN1); + private static final HostId HID4 = HostId.hostId(MAC4, VLAN1); + private static final HostId SOLICITED_HID3 = HostId.hostId(SOLICITED_MAC3, VLAN1); private static final DeviceId DID1 = getDeviceId(1); private static final DeviceId DID2 = getDeviceId(2); @@ -222,21 +242,29 @@ public class ProxyArpManagerTest { for (int i = 1; i <= NUM_ADDRESS_PORTS; i++) { ConnectPoint cp = new ConnectPoint(getDeviceId(i), P1); - Ip4Prefix prefix1 = - Ip4Prefix.valueOf("10.0." + (2 * i - 1) + ".0/24"); - Ip4Address addr1 = - Ip4Address.valueOf("10.0." + (2 * i - 1) + ".1"); + + // Interface address for IPv4 + Ip4Prefix prefix1 = Ip4Prefix.valueOf("10.0." + (2 * i - 1) + ".0/24"); + Ip4Address addr1 = Ip4Address.valueOf("10.0." + (2 * i - 1) + ".1"); Ip4Prefix prefix2 = Ip4Prefix.valueOf("10.0." + (2 * i) + ".0/24"); Ip4Address addr2 = Ip4Address.valueOf("10.0." + (2 * i) + ".1"); InterfaceIpAddress ia1 = new InterfaceIpAddress(addr1, prefix1); InterfaceIpAddress ia2 = new InterfaceIpAddress(addr2, prefix2); - Interface intf1 = new Interface(cp, Sets.newHashSet(ia1), + + // Interface address for IPv6 + Ip6Prefix prefix3 = Ip6Prefix.valueOf((2 * i - 1) + "000::0/64"); + Ip6Address addr3 = Ip6Address.valueOf((2 * i - 1) + "000::1"); + Ip6Prefix prefix4 = Ip6Prefix.valueOf((2 * i) + "000::0/64"); + Ip6Address addr4 = Ip6Address.valueOf((2 * i) + "000::1"); + InterfaceIpAddress ia3 = new InterfaceIpAddress(addr3, prefix3); + InterfaceIpAddress ia4 = new InterfaceIpAddress(addr4, prefix4); + + Interface intf1 = new Interface(cp, Sets.newHashSet(ia1, ia3), MacAddress.valueOf(2 * i - 1), VlanId.vlanId((short) 1)); - Interface intf2 = new Interface(cp, Sets.newHashSet(ia2), + Interface intf2 = new Interface(cp, Sets.newHashSet(ia2, ia4), MacAddress.valueOf(2 * i), VlanId.NONE); - interfaces.add(intf1); interfaces.add(intf2); @@ -319,6 +347,41 @@ public class ProxyArpManagerTest { verifyPacketOut(arpReply, getLocation(5), packetService.packets.get(0)); } + /** + * Tests {@link ProxyArpManager#reply(Ethernet, ConnectPoint)} in the case where the + * destination host is known. + * Verifies the correct NDP reply is sent out the correct port. + */ + @Test + public void testReplyKnownIpv6() { + //Set the return value of isEdgePoint from the edgemanager. + isEdgePointReturn = true; + + Host replyer = new DefaultHost(PID, HID3, MAC3, VLAN1, getLocation(4), + Collections.singleton(IP3)); + + Host requestor = new DefaultHost(PID, HID4, MAC4, VLAN1, getLocation(5), + Collections.singleton(IP4)); + + expect(hostService.getHostsByIp(IP3)) + .andReturn(Collections.singleton(replyer)); + expect(hostService.getHost(HID4)).andReturn(requestor); + + replay(hostService); + replay(interfaceService); + + Ethernet ndpRequest = buildNDP(ICMP6.NEIGHBOR_SOLICITATION, + MAC4, SOLICITED_MAC3, + IP4, IP3); + + proxyArp.reply(ndpRequest, getLocation(5)); + + assertEquals(1, packetService.packets.size()); + Ethernet ndpReply = buildNDP(ICMP6.NEIGHBOR_ADVERTISEMENT, + MAC3, MAC4, IP3, IP4); + verifyPacketOut(ndpReply, getLocation(5), packetService.packets.get(0)); + } + /** * Tests {@link ProxyArpManager#reply(Ethernet, ConnectPoint)} in the case where the * destination host is not known. @@ -337,7 +400,6 @@ public class ProxyArpManagerTest { .andReturn(Collections.emptySet()); expect(hostService.getHost(HID2)).andReturn(requestor); - replay(hostService); replay(interfaceService); @@ -353,6 +415,41 @@ public class ProxyArpManagerTest { verifyFlood(arpRequest); } + /** + * Tests {@link ProxyArpManager#reply(Ethernet, ConnectPoint)} in the case where the + * destination host is not known. + * Verifies the NDP request is flooded out the correct edge ports. + */ + @Test + public void testReplyUnknownIpv6() { + isEdgePointReturn = true; + + Host requestor = new DefaultHost(PID, HID4, MAC4, VLAN1, getLocation(5), + Collections.singleton(IP4)); + + expect(hostService.getHostsByIp(IP3)) + .andReturn(Collections.emptySet()); + expect(interfaceService.getInterfacesByIp(IP4)) + .andReturn(Collections.emptySet()); + expect(hostService.getHost(HID4)).andReturn(requestor); + + replay(hostService); + replay(interfaceService); + + Ethernet ndpRequest = buildNDP(ICMP6.NEIGHBOR_SOLICITATION, + MAC4, SOLICITED_MAC3, + IP4, IP3); + + //Setup the set of edge ports to be used in the reply method + getEdgePointsNoArg = Lists.newLinkedList(); + getEdgePointsNoArg.add(new ConnectPoint(DeviceId.deviceId("5"), PortNumber.portNumber(1))); + getEdgePointsNoArg.add(new ConnectPoint(DeviceId.deviceId("4"), PortNumber.portNumber(1))); + + proxyArp.reply(ndpRequest, getLocation(6)); + + verifyFlood(ndpRequest); + } + /** * Tests {@link ProxyArpManager#reply(Ethernet, ConnectPoint)} in the case where the * destination host is known for that IP address, but is not on the same @@ -388,6 +485,46 @@ public class ProxyArpManagerTest { verifyFlood(arpRequest); } + /** + * Tests {@link ProxyArpManager#reply(Ethernet, ConnectPoint)} in the case where the + * destination host is known for that IP address, but is not on the same + * VLAN as the source host. + * Verifies the NDP request is flooded out the correct edge ports. + */ + @Test + public void testReplyDifferentVlanIpv6() { + + Host replyer = new DefaultHost(PID, HID3, MAC3, VLAN2, getLocation(4), + Collections.singleton(IP3)); + + Host requestor = new DefaultHost(PID, HID4, MAC4, VLAN1, getLocation(5), + Collections.singleton(IP4)); + + expect(hostService.getHostsByIp(IP3)) + .andReturn(Collections.singleton(replyer)); + expect(interfaceService.getInterfacesByIp(IP4)) + .andReturn(Collections.emptySet()); + expect(hostService.getHost(HID4)).andReturn(requestor); + + replay(hostService); + replay(interfaceService); + + Ethernet ndpRequest = buildNDP(ICMP6.NEIGHBOR_SOLICITATION, + MAC4, SOLICITED_MAC3, + IP4, IP3); + + //Setup for flood test + getEdgePointsNoArg = Lists.newLinkedList(); + getEdgePointsNoArg.add(new ConnectPoint(DeviceId.deviceId("5"), PortNumber.portNumber(1))); + getEdgePointsNoArg.add(new ConnectPoint(DeviceId.deviceId("4"), PortNumber.portNumber(1))); + proxyArp.reply(ndpRequest, getLocation(6)); + + verifyFlood(ndpRequest); + } + + /** + * Test ARP request from external network to an internal host. + */ @Test public void testReplyToRequestForUs() { Ip4Address theirIp = Ip4Address.valueOf("10.0.1.254"); @@ -422,6 +559,63 @@ public class ProxyArpManagerTest { verifyPacketOut(arpReply, LOC1, packetService.packets.get(0)); } + /** + * Test NDP request from external network to an internal host. + */ + @Test + public void testReplyToRequestForUsIpv6() { + Ip6Address theirIp = Ip6Address.valueOf("1000::ffff"); + Ip6Address ourFirstIp = Ip6Address.valueOf("1000::1"); + Ip6Address ourSecondIp = Ip6Address.valueOf("2000::1"); + MacAddress firstMac = MacAddress.valueOf(1L); + MacAddress secondMac = MacAddress.valueOf(2L); + + Host requestor = new DefaultHost(PID, HID2, MAC2, VLAN1, LOC1, + Collections.singleton(theirIp)); + + expect(hostService.getHost(HID2)).andReturn(requestor); + expect(hostService.getHostsByIp(ourFirstIp)) + .andReturn(Collections.singleton(requestor)); + replay(hostService); + replay(interfaceService); + + Ethernet ndpRequest = buildNDP(ICMP6.NEIGHBOR_SOLICITATION, + MAC2, + MacAddress.valueOf("33:33:ff:00:00:01"), + theirIp, + ourFirstIp); + isEdgePointReturn = true; + proxyArp.reply(ndpRequest, LOC1); + assertEquals(1, packetService.packets.size()); + + Ethernet ndpReply = buildNDP(ICMP6.NEIGHBOR_ADVERTISEMENT, + firstMac, + MAC2, + ourFirstIp, + theirIp); + verifyPacketOut(ndpReply, LOC1, packetService.packets.get(0)); + + // Test a request for the second address on that port + packetService.packets.clear(); + ndpRequest = buildNDP(ICMP6.NEIGHBOR_SOLICITATION, + MAC2, + MacAddress.valueOf("33:33:ff:00:00:01"), + theirIp, + ourSecondIp); + proxyArp.reply(ndpRequest, LOC1); + assertEquals(1, packetService.packets.size()); + + ndpReply = buildNDP(ICMP6.NEIGHBOR_ADVERTISEMENT, + secondMac, + MAC2, + ourSecondIp, + theirIp); + verifyPacketOut(ndpReply, LOC1, packetService.packets.get(0)); + } + + /** + * Request for a valid external IPv4 address but coming in the wrong port. + */ @Test public void testReplyExternalPortBadRequest() { replay(hostService); // no further host service expectations @@ -442,6 +636,38 @@ public class ProxyArpManagerTest { assertEquals(0, packetService.packets.size()); } + /** + * Request for a valid external IPv6 address but coming in the wrong port. + */ + @Test + public void testReplyExternalPortBadRequestIpv6() { + replay(hostService); // no further host service expectations + replay(interfaceService); + + Ip6Address theirIp = Ip6Address.valueOf("1000::ffff"); + + Ethernet ndpRequest = buildNDP(ICMP6.NEIGHBOR_SOLICITATION, + MAC1, + MacAddress.valueOf("33:33:ff:00:00:01"), + theirIp, + Ip6Address.valueOf("3000::1")); + proxyArp.reply(ndpRequest, LOC1); + assertEquals(0, packetService.packets.size()); + + // Request for a valid internal IP address but coming in an external port + packetService.packets.clear(); + ndpRequest = buildNDP(ICMP6.NEIGHBOR_SOLICITATION, + MAC1, + MacAddress.valueOf("33:33:ff:00:00:01"), + theirIp, + IP3); + proxyArp.reply(ndpRequest, LOC1); + assertEquals(0, packetService.packets.size()); + } + + /** + * Test ARP request from internal network to an external host. + */ @Test public void testReplyToRequestFromUs() { Ip4Address ourIp = Ip4Address.valueOf("10.0.1.1"); @@ -473,6 +699,48 @@ public class ProxyArpManagerTest { assertEquals(0, packetService.packets.size()); } + /** + * Test NDP request from internal network to an external host. + */ + @Test + public void testReplyToRequestFromUsIpv6() { + Ip6Address ourIp = Ip6Address.valueOf("1000::1"); + MacAddress ourMac = MacAddress.valueOf(1L); + Ip6Address theirIp = Ip6Address.valueOf("1000::100"); + + expect(hostService.getHostsByIp(theirIp)).andReturn(Collections.emptySet()); + expect(interfaceService.getInterfacesByIp(ourIp)) + .andReturn(Collections.singleton(new Interface(getLocation(1), + Collections.singleton(new InterfaceIpAddress( + ourIp, + IpPrefix.valueOf("1000::1/64"))), + ourMac, + VLAN1))); + expect(hostService.getHost(HostId.hostId(ourMac, VLAN1))).andReturn(null); + replay(hostService); + replay(interfaceService); + + // This is a request from something inside our network (like a BGP + // daemon) to an external host. + Ethernet ndpRequest = buildNDP(ICMP6.NEIGHBOR_SOLICITATION, + ourMac, + MacAddress.valueOf("33:33:ff:00:00:01"), + ourIp, + theirIp); + + //Ensure the packet is allowed through (it is not to an internal port) + isEdgePointReturn = true; + + proxyArp.reply(ndpRequest, getLocation(5)); + assertEquals(1, packetService.packets.size()); + verifyPacketOut(ndpRequest, getLocation(1), packetService.packets.get(0)); + + // The same request from a random external port should fail + packetService.packets.clear(); + proxyArp.reply(ndpRequest, getLocation(2)); + assertEquals(0, packetService.packets.size()); + } + /** * Tests {@link ProxyArpManager#forward(Ethernet, ConnectPoint)} in the case where the * destination host is known. @@ -500,6 +768,35 @@ public class ProxyArpManagerTest { verifyPacketOut(arpRequest, LOC1, packet); } + /** + * Tests {@link ProxyArpManager#forward(Ethernet, ConnectPoint)} in the case where the + * destination host is known. + * Verifies the correct ARP request is sent out the correct port. + */ + @Test + public void testForwardToHostIpv6() { + Host host1 = new DefaultHost(PID, HID3, MAC3, VLAN1, LOC1, + Collections.singleton(IP3)); + Host host2 = new DefaultHost(PID, HID4, MAC4, VLAN1, LOC2, + Collections.singleton(IP4)); + + expect(hostService.getHost(SOLICITED_HID3)).andReturn(host1); + expect(hostService.getHost(HID4)).andReturn(host2); + replay(hostService); + replay(interfaceService); + + Ethernet ndpRequest = buildNDP(ICMP6.NEIGHBOR_SOLICITATION, + MAC4, SOLICITED_MAC3, + IP4, IP3); + + proxyArp.forward(ndpRequest, LOC2); + + assertEquals(1, packetService.packets.size()); + OutboundPacket packet = packetService.packets.get(0); + + verifyPacketOut(ndpRequest, LOC1, packet); + } + /** * Tests {@link ProxyArpManager#forward(Ethernet, ConnectPoint)} in the case where the * destination host is not known. @@ -525,6 +822,33 @@ public class ProxyArpManagerTest { verifyFlood(arpRequest); } + /** + * Tests {@link ProxyArpManager#forward(Ethernet, ConnectPoint)} in the case where the + * destination host is not known. + * Verifies the correct NDP request is flooded out the correct edge ports. + */ + @Test + public void testForwardFloodIpv6() { + expect(hostService.getHost(SOLICITED_HID3)).andReturn(null); + replay(hostService); + replay(interfaceService); + + Ethernet ndpRequest = buildNDP(ICMP6.NEIGHBOR_SOLICITATION, + MAC4, SOLICITED_MAC3, + IP4, IP3); + + //populate the list of edges when so that when forward hits flood in the manager it contains the values + //that should continue on + getEdgePointsNoArg = Lists.newLinkedList(); + getEdgePointsNoArg.add(new ConnectPoint(DeviceId.deviceId("3"), PortNumber.portNumber(1))); + getEdgePointsNoArg.add(new ConnectPoint(DeviceId.deviceId("5"), PortNumber.portNumber(1))); + getEdgePointsNoArg.add(new ConnectPoint(DeviceId.deviceId("4"), PortNumber.portNumber(1))); + + proxyArp.forward(ndpRequest, getLocation(6)); + + verifyFlood(ndpRequest); + } + /** * Verifies that the given packet was flooded out all available edge ports, * except for the input port. @@ -625,6 +949,61 @@ public class ProxyArpManagerTest { return eth; } + /** + * Builds an NDP packet with the given parameters. + * + * @param type NeighborSolicitation or NeighborAdvertisement + * @param srcMac source MAC address + * @param dstMac destination MAC address, or null if this is a request + * @param srcIp source IP address + * @param dstIp destination IP address + * @return the NDP packet + */ + private Ethernet buildNDP(byte type, MacAddress srcMac, MacAddress dstMac, + Ip6Address srcIp, Ip6Address dstIp) { + assertThat(type, anyOf( + is(ICMP6.NEIGHBOR_SOLICITATION), + is(ICMP6.NEIGHBOR_ADVERTISEMENT) + )); + assertNotNull(srcMac); + assertNotNull(dstMac); + assertNotNull(srcIp); + assertNotNull(dstIp); + + IPacket ndp; + if (type == ICMP6.NEIGHBOR_SOLICITATION) { + ndp = new NeighborSolicitation().setTargetAddress(dstIp.toOctets()); + } else { + ndp = new NeighborAdvertisement() + .setSolicitedFlag((byte) 1) + .setOverrideFlag((byte) 1) + .setTargetAddress(srcIp.toOctets()) + .addOption(NeighborDiscoveryOptions.TYPE_TARGET_LL_ADDRESS, + srcMac.toBytes()); + } + + ICMP6 icmp6 = new ICMP6(); + icmp6.setIcmpType(type); + icmp6.setIcmpCode((byte) 0); + icmp6.setPayload(ndp); + + IPv6 ipv6 = new IPv6(); + ipv6.setDestinationAddress(dstIp.toOctets()); + ipv6.setSourceAddress(srcIp.toOctets()); + ipv6.setNextHeader(IPv6.PROTOCOL_ICMP6); + ipv6.setHopLimit((byte) 255); + ipv6.setPayload(icmp6); + + Ethernet eth = new Ethernet(); + eth.setDestinationMACAddress(dstMac); + eth.setSourceMACAddress(srcMac); + eth.setEtherType(Ethernet.TYPE_IPV6); + eth.setVlanID(VLAN1.toShort()); + eth.setPayload(ipv6); + + return eth; + } + /** * Test PacketService implementation that simply stores OutboundPackets * passed to {@link #emit(OutboundPacket)} for later verification. diff --git a/framework/src/onos/core/store/dist/pom.xml b/framework/src/onos/core/store/dist/pom.xml index cc293da4..f2ec2a71 100644 --- a/framework/src/onos/core/store/dist/pom.xml +++ b/framework/src/onos/core/store/dist/pom.xml @@ -71,7 +71,7 @@ org.mapdb mapdb - 1.0.7 + 1.0.8 diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/ClusterDefinition.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/ClusterDefinition.java deleted file mode 100644 index 75f05a31..00000000 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/ClusterDefinition.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.onosproject.store.cluster.impl; - -import java.util.Set; - -import com.google.common.collect.ImmutableSet; - -/** - * Cluster definition. - */ -public class ClusterDefinition { - - private Set nodes; - private String ipPrefix; - - /** - * Creates a new cluster definition. - * @param nodes cluster nodes information - * @param ipPrefix ip prefix common to all cluster nodes - * @return cluster definition - */ - public static ClusterDefinition from(Set nodes, String ipPrefix) { - ClusterDefinition definition = new ClusterDefinition(); - definition.ipPrefix = ipPrefix; - definition.nodes = ImmutableSet.copyOf(nodes); - return definition; - } - - /** - * Returns set of cluster nodes info. - * @return cluster nodes info - */ - public Set getNodes() { - return ImmutableSet.copyOf(nodes); - } - - /** - * Returns ipPrefix in dotted decimal notion. - * @return ip prefix - */ - public String getIpPrefix() { - return ipPrefix; - } -} \ No newline at end of file diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/ClusterDefinitionManager.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/ClusterDefinitionManager.java deleted file mode 100644 index 8b0001d8..00000000 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/ClusterDefinitionManager.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.onosproject.store.cluster.impl; - -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Sets; -import org.apache.felix.scr.annotations.Activate; -import org.apache.felix.scr.annotations.Component; -import org.apache.felix.scr.annotations.Deactivate; -import org.apache.felix.scr.annotations.Service; -import org.onlab.packet.IpAddress; -import org.onosproject.cluster.ClusterDefinitionService; -import org.onosproject.cluster.ControllerNode; -import org.onosproject.cluster.DefaultControllerNode; -import org.onosproject.cluster.NodeId; -import org.onosproject.store.consistent.impl.DatabaseDefinition; -import org.onosproject.store.consistent.impl.DatabaseDefinitionStore; -import org.slf4j.Logger; - -import java.io.File; -import java.io.IOException; -import java.net.InetAddress; -import java.net.NetworkInterface; -import java.net.SocketException; -import java.util.Enumeration; -import java.util.Set; -import java.util.stream.Collectors; - -import static java.net.NetworkInterface.getNetworkInterfaces; -import static java.util.Collections.list; -import static org.onosproject.cluster.DefaultControllerNode.DEFAULT_PORT; -import static org.onosproject.store.consistent.impl.DatabaseManager.PARTITION_DEFINITION_FILE; -import static org.slf4j.LoggerFactory.getLogger; - -/** - * Implementation of ClusterDefinitionService. - */ -@Component(immediate = true) -@Service -public class ClusterDefinitionManager implements ClusterDefinitionService { - - public static final String CLUSTER_DEFINITION_FILE = "../config/cluster.json"; - private static final String ONOS_NIC = "ONOS_NIC"; - private static final Logger log = getLogger(ClusterDefinitionManager.class); - private ControllerNode localNode; - private Set seedNodes; - - @Activate - public void activate() { - File clusterDefinitionFile = new File(CLUSTER_DEFINITION_FILE); - ClusterDefinitionStore clusterDefinitionStore = - new ClusterDefinitionStore(clusterDefinitionFile.getPath()); - - if (!clusterDefinitionFile.exists()) { - createDefaultClusterDefinition(clusterDefinitionStore); - } - - try { - ClusterDefinition clusterDefinition = clusterDefinitionStore.read(); - establishSelfIdentity(clusterDefinition); - seedNodes = ImmutableSet - .copyOf(clusterDefinition.getNodes()) - .stream() - .filter(n -> !localNode.id().equals(new NodeId(n.getId()))) - .map(n -> new DefaultControllerNode(new NodeId(n.getId()), - IpAddress.valueOf(n.getIp()), - n.getTcpPort())) - .collect(Collectors.toSet()); - } catch (IOException e) { - throw new IllegalStateException("Failed to read cluster definition.", e); - } - - log.info("Started"); - } - - @Deactivate - public void deactivate() { - log.info("Stopped"); - } - - @Override - public ControllerNode localNode() { - return localNode; - } - - @Override - public Set seedNodes() { - return seedNodes; - } - - @Override - public void formCluster(Set nodes, String ipPrefix) { - try { - Set infos = Sets.newHashSet(); - nodes.forEach(n -> infos.add(NodeInfo.from(n.id().toString(), - n.ip().toString(), - n.tcpPort()))); - - ClusterDefinition cdef = ClusterDefinition.from(infos, ipPrefix); - new ClusterDefinitionStore(CLUSTER_DEFINITION_FILE).write(cdef); - - DatabaseDefinition ddef = DatabaseDefinition.from(infos); - new DatabaseDefinitionStore(PARTITION_DEFINITION_FILE).write(ddef); - } catch (IOException e) { - log.error("Unable to form cluster", e); - } - } - - private IpAddress findLocalIp(ClusterDefinition clusterDefinition) throws SocketException { - Enumeration interfaces = - NetworkInterface.getNetworkInterfaces(); - while (interfaces.hasMoreElements()) { - NetworkInterface iface = interfaces.nextElement(); - Enumeration inetAddresses = iface.getInetAddresses(); - while (inetAddresses.hasMoreElements()) { - IpAddress ip = IpAddress.valueOf(inetAddresses.nextElement()); - if (clusterDefinition.getNodes().stream() - .map(NodeInfo::getIp) - .map(IpAddress::valueOf) - .anyMatch(nodeIp -> ip.equals(nodeIp))) { - return ip; - } - } - } - throw new IllegalStateException("Unable to determine local ip"); - } - - private void establishSelfIdentity(ClusterDefinition clusterDefinition) { - try { - IpAddress ip = findLocalIp(clusterDefinition); - localNode = new DefaultControllerNode(new NodeId(ip.toString()), ip); - } catch (SocketException e) { - throw new IllegalStateException("Cannot determine local IP", e); - } - } - - private void createDefaultClusterDefinition(ClusterDefinitionStore store) { - // Assumes IPv4 is returned. - String ip = getSiteLocalAddress(); - String ipPrefix = ip.replaceFirst("\\.[0-9]*$", ".*"); - NodeInfo node = NodeInfo.from(ip, ip, DEFAULT_PORT); - try { - store.write(ClusterDefinition.from(ImmutableSet.of(node), ipPrefix)); - } catch (IOException e) { - log.warn("Unable to write default cluster definition", e); - } - } - - /** - * Returns the address that matches the IP prefix given in ONOS_NIC - * environment variable if one was specified, or the first site local - * address if one can be found or the loopback address otherwise. - * - * @return site-local address in string form - */ - public static String getSiteLocalAddress() { - try { - String ipPrefix = System.getenv(ONOS_NIC); - for (NetworkInterface nif : list(getNetworkInterfaces())) { - for (InetAddress address : list(nif.getInetAddresses())) { - IpAddress ip = IpAddress.valueOf(address); - if (ipPrefix == null && address.isSiteLocalAddress() || - ipPrefix != null && matchInterface(ip.toString(), ipPrefix)) { - return ip.toString(); - } - } - } - } catch (SocketException e) { - log.error("Unable to get network interfaces", e); - } - - return IpAddress.valueOf(InetAddress.getLoopbackAddress()).toString(); - } - - // Indicates whether the specified interface address matches the given prefix. - // FIXME: Add a facility to IpPrefix to make this more robust - private static boolean matchInterface(String ip, String ipPrefix) { - String s = ipPrefix.replaceAll("\\.\\*", ""); - return ip.startsWith(s); - } -} diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/ClusterDefinitionStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/ClusterDefinitionStore.java deleted file mode 100644 index 2a2f4dc4..00000000 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/ClusterDefinitionStore.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.onosproject.store.cluster.impl; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.common.io.Files; - -import java.io.File; -import java.io.IOException; - -/** - * Allows for reading and writing cluster definition as a JSON file. - */ -public class ClusterDefinitionStore { - - private final File file; - - /** - * Creates a reader/writer of the cluster definition file. - * @param filePath location of the definition file - */ - public ClusterDefinitionStore(String filePath) { - file = new File(filePath); - } - - /** - * Returns the cluster definition. - * @return cluster definition - * @throws IOException when I/O exception of some sort has occurred - */ - public ClusterDefinition read() throws IOException { - ObjectMapper mapper = new ObjectMapper(); - return mapper.readValue(file, ClusterDefinition.class); - } - - /** - * Writes the specified cluster definition to file. - * @param definition cluster definition - * @throws IOException when I/O exception of some sort has occurred - */ - public void write(ClusterDefinition definition) throws IOException { - checkNotNull(definition); - // write back to file - Files.createParentDirs(file); - ObjectMapper mapper = new ObjectMapper(); - mapper.writeValue(file, definition); - } -} diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/DistributedClusterStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/DistributedClusterStore.java index 859efebf..3bb6a708 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/DistributedClusterStore.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/DistributedClusterStore.java @@ -27,8 +27,8 @@ import org.apache.felix.scr.annotations.Service; import org.joda.time.DateTime; import org.onlab.packet.IpAddress; import org.onlab.util.KryoNamespace; -import org.onosproject.cluster.ClusterDefinitionService; import org.onosproject.cluster.ClusterEvent; +import org.onosproject.cluster.ClusterMetadataService; import org.onosproject.cluster.ClusterStore; import org.onosproject.cluster.ClusterStoreDelegate; import org.onosproject.cluster.ControllerNode; @@ -99,14 +99,14 @@ public class DistributedClusterStore private ControllerNode localNode; @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected ClusterDefinitionService clusterDefinitionService; + protected ClusterMetadataService clusterMetadataService; @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected MessagingService messagingService; @Activate public void activate() { - localNode = clusterDefinitionService.localNode(); + localNode = clusterMetadataService.getLocalNode(); messagingService.registerHandler(HEARTBEAT_MESSAGE, new HeartbeatMessageHandler(), heartBeatMessageHandler); @@ -116,9 +116,6 @@ public class DistributedClusterStore heartBeatSender.scheduleWithFixedDelay(this::heartbeat, 0, HEARTBEAT_INTERVAL_MS, TimeUnit.MILLISECONDS); - addNode(localNode); - updateState(localNode.id(), State.ACTIVE); - log.info("Started"); } @@ -188,7 +185,7 @@ public class DistributedClusterStore private void addNode(ControllerNode node) { allNodes.put(node.id(), node); - updateState(node.id(), State.INACTIVE); + updateState(node.id(), node.equals(localNode) ? State.ACTIVE : State.INACTIVE); notifyDelegate(new ClusterEvent(ClusterEvent.Type.INSTANCE_ADDED, node)); } diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/StaticClusterMetadataStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/StaticClusterMetadataStore.java new file mode 100644 index 00000000..9f6c4130 --- /dev/null +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/StaticClusterMetadataStore.java @@ -0,0 +1,221 @@ +package org.onosproject.store.cluster.impl; + +import static com.google.common.base.Preconditions.checkNotNull; +import static java.net.NetworkInterface.getNetworkInterfaces; +import static org.slf4j.LoggerFactory.getLogger; + +import java.io.File; +import java.io.IOException; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; + +import org.apache.felix.scr.annotations.Activate; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Deactivate; +import org.apache.felix.scr.annotations.Service; +import org.onlab.packet.IpAddress; +import org.onosproject.cluster.ClusterMetadata; +import org.onosproject.cluster.ClusterMetadataEvent; +import org.onosproject.cluster.ClusterMetadataStore; +import org.onosproject.cluster.ClusterMetadataStoreDelegate; +import org.onosproject.cluster.ControllerNode; +import org.onosproject.cluster.DefaultControllerNode; +import org.onosproject.cluster.NodeId; +import org.onosproject.cluster.Partition; +import org.onosproject.store.AbstractStore; +import org.onosproject.store.service.Versioned; +import org.slf4j.Logger; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.google.common.base.Throwables; +import com.google.common.collect.Lists; +import com.google.common.io.Files; + +/** + * ClusterMetadataStore backed by a local file. + */ +@Component(immediate = true, enabled = true) +@Service +public class StaticClusterMetadataStore + extends AbstractStore + implements ClusterMetadataStore { + + private final Logger log = getLogger(getClass()); + private static final String CLUSTER_METADATA_FILE = "../config/cluster.json"; + private static final int DEFAULT_ONOS_PORT = 9876; + private final File metadataFile = new File(CLUSTER_METADATA_FILE); + private AtomicReference metadata = new AtomicReference<>(); + private ObjectMapper mapper; + private long version; + + @Activate + public void activate() { + mapper = new ObjectMapper(); + SimpleModule module = new SimpleModule(); + module.addSerializer(NodeId.class, new NodeIdSerializer()); + module.addDeserializer(NodeId.class, new NodeIdDeserializer()); + module.addSerializer(ControllerNode.class, new ControllerNodeSerializer()); + module.addDeserializer(ControllerNode.class, new ControllerNodeDeserializer()); + mapper.registerModule(module); + File metadataFile = new File(CLUSTER_METADATA_FILE); + if (metadataFile.exists()) { + try { + metadata.set(mapper.readValue(metadataFile, ClusterMetadata.class)); + version = metadataFile.lastModified(); + } catch (IOException e) { + Throwables.propagate(e); + } + } else { + String localIp = getSiteLocalAddress(); + ControllerNode localNode = + new DefaultControllerNode(new NodeId(localIp), IpAddress.valueOf(localIp), DEFAULT_ONOS_PORT); + metadata.set(ClusterMetadata.builder() + .withName("default") + .withControllerNodes(Arrays.asList(localNode)) + .withPartitions(Lists.newArrayList(new Partition("p1", Lists.newArrayList(localNode.id())))) + .build()); + version = System.currentTimeMillis(); + } + log.info("Started"); + } + + @Deactivate + public void deactivate() { + log.info("Stopped"); + } + + @Override + public void setDelegate(ClusterMetadataStoreDelegate delegate) { + checkNotNull(delegate, "Delegate cannot be null"); + this.delegate = delegate; + } + + @Override + public void unsetDelegate(ClusterMetadataStoreDelegate delegate) { + this.delegate = null; + } + + @Override + public boolean hasDelegate() { + return this.delegate != null; + } + + @Override + public Versioned getClusterMetadata() { + return new Versioned<>(metadata.get(), version); + } + + @Override + public void setClusterMetadata(ClusterMetadata metadata) { + checkNotNull(metadata); + try { + Files.createParentDirs(metadataFile); + mapper.writeValue(metadataFile, metadata); + this.metadata.set(metadata); + } catch (IOException e) { + Throwables.propagate(e); + } + } + + @Override + public void setActiveReplica(String partitionId, NodeId nodeId) { + throw new UnsupportedOperationException(); + } + + @Override + public void unsetActiveReplica(String partitionId, NodeId nodeId) { + throw new UnsupportedOperationException(); + } + + @Override + public Collection getActiveReplicas(String partitionId) { + return metadata.get().getPartitions() + .stream() + .filter(r -> r.getName().equals(partitionId)) + .findFirst() + .map(r -> r.getMembers()) + .orElse(null); + } + + private static class ControllerNodeSerializer extends JsonSerializer { + @Override + public void serialize(ControllerNode node, JsonGenerator jgen, SerializerProvider provider) + throws IOException, JsonProcessingException { + jgen.writeStartObject(); + jgen.writeStringField("id", node.id().toString()); + jgen.writeStringField("ip", node.ip().toString()); + jgen.writeNumberField("port", node.tcpPort()); + jgen.writeEndObject(); + } + } + + private static class ControllerNodeDeserializer extends JsonDeserializer { + @Override + public ControllerNode deserialize(JsonParser jp, DeserializationContext ctxt) + throws IOException, JsonProcessingException { + JsonNode node = jp.getCodec().readTree(jp); + NodeId nodeId = new NodeId(node.get("id").textValue()); + IpAddress ip = IpAddress.valueOf(node.get("ip").textValue()); + int port = node.get("port").asInt(); + return new DefaultControllerNode(nodeId, ip, port); + } + } + + private static class NodeIdSerializer extends JsonSerializer { + @Override + public void serialize(NodeId nodeId, JsonGenerator jgen, SerializerProvider provider) + throws IOException, JsonProcessingException { + jgen.writeString(nodeId.toString()); + } + } + + private class NodeIdDeserializer extends JsonDeserializer { + @Override + public NodeId deserialize(JsonParser jp, DeserializationContext ctxt) + throws IOException, JsonProcessingException { + JsonNode node = jp.getCodec().readTree(jp); + return new NodeId(node.asText()); + } + } + + + private static String getSiteLocalAddress() { + Function ipLookup = nif -> { + for (InetAddress address : Collections.list(nif.getInetAddresses())) { + if (address.isSiteLocalAddress()) { + return IpAddress.valueOf(address); + } + } + return null; + }; + try { + IpAddress ip = ipLookup.apply(NetworkInterface.getByName("eth0")); + if (ip != null) { + return ip.toString(); + } + for (NetworkInterface nif : Collections.list(getNetworkInterfaces())) { + ip = ipLookup.apply(nif); + if (ip != null) { + return ip.toString(); + } + } + } catch (Exception e) { + throw new IllegalStateException("Unable to get network interfaces", e); + } + return IpAddress.valueOf(InetAddress.getLoopbackAddress()).toString(); + } +} \ No newline at end of file diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/messaging/impl/IOLoopMessagingManager.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/messaging/impl/IOLoopMessagingManager.java index ffdd25f2..ddb45f71 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/messaging/impl/IOLoopMessagingManager.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/messaging/impl/IOLoopMessagingManager.java @@ -22,7 +22,7 @@ import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.ReferenceCardinality; import org.apache.felix.scr.annotations.Service; import org.onlab.nio.service.IOLoopMessaging; -import org.onosproject.cluster.ClusterDefinitionService; +import org.onosproject.cluster.ClusterMetadataService; import org.onosproject.cluster.ControllerNode; import org.onosproject.store.cluster.messaging.Endpoint; import org.slf4j.Logger; @@ -38,11 +38,11 @@ public class IOLoopMessagingManager extends IOLoopMessaging { private final Logger log = LoggerFactory.getLogger(getClass()); @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected ClusterDefinitionService clusterDefinitionService; + protected ClusterMetadataService clusterMetadataService; @Activate public void activate() throws Exception { - ControllerNode localNode = clusterDefinitionService.localNode(); + ControllerNode localNode = clusterMetadataService.getLocalNode(); super.start(new Endpoint(localNode.ip(), localNode.tcpPort())); log.info("Started"); } diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/messaging/impl/NettyMessagingManager.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/messaging/impl/NettyMessagingManager.java index 9328817b..23c81869 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/messaging/impl/NettyMessagingManager.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/messaging/impl/NettyMessagingManager.java @@ -16,6 +16,7 @@ package org.onosproject.store.cluster.messaging.impl; import com.google.common.base.Strings; + import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Deactivate; @@ -23,7 +24,7 @@ import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.ReferenceCardinality; import org.apache.felix.scr.annotations.Service; import org.onlab.netty.NettyMessaging; -import org.onosproject.cluster.ClusterDefinitionService; +import org.onosproject.cluster.ClusterMetadataService; import org.onosproject.cluster.ControllerNode; import org.onosproject.store.cluster.messaging.Endpoint; import org.slf4j.Logger; @@ -41,11 +42,11 @@ public class NettyMessagingManager extends NettyMessaging { private static final short MIN_KS_LENGTH = 6; @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected ClusterDefinitionService clusterDefinitionService; + protected ClusterMetadataService clusterMetadataService; @Activate public void activate() throws Exception { - ControllerNode localNode = clusterDefinitionService.localNode(); + ControllerNode localNode = clusterMetadataService.getLocalNode(); getTLSParameters(); super.start(new Endpoint(localNode.ip(), localNode.tcpPort())); log.info("Started"); diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseDefinition.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseDefinition.java deleted file mode 100644 index 11b56c14..00000000 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseDefinition.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.onosproject.store.consistent.impl; - -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Maps; -import org.onosproject.store.cluster.impl.NodeInfo; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * Partitioned database configuration. - */ -public class DatabaseDefinition { - private Map> partitions; - private Set nodes; - - /** - * Creates a new DatabaseDefinition. - * - * @param partitions partition map - * @param nodes set of nodes - * @return database definition - */ - public static DatabaseDefinition from(Map> partitions, - Set nodes) { - checkNotNull(partitions); - checkNotNull(nodes); - DatabaseDefinition definition = new DatabaseDefinition(); - definition.partitions = ImmutableMap.copyOf(partitions); - definition.nodes = ImmutableSet.copyOf(nodes); - return definition; - } - - /** - * Creates a new DatabaseDefinition using default partitions. - * - * @param nodes set of nodes - * @return database definition - */ - public static DatabaseDefinition from(Set nodes) { - return from(generateDefaultPartitions(nodes), nodes); - } - - /** - * Returns the map of database partitions. - * - * @return db partition map - */ - public Map> getPartitions() { - return partitions; - } - - /** - * Returns the set of nodes. - * - * @return nodes - */ - public Set getNodes() { - return nodes; - } - - - /** - * Generates set of default partitions using permutations of the nodes. - * - * @param nodes information about cluster nodes - * @return default partition map - */ - private static Map> generateDefaultPartitions(Set nodes) { - List sorted = new ArrayList<>(nodes); - Collections.sort(sorted, (o1, o2) -> o1.getId().compareTo(o2.getId())); - Map> partitions = Maps.newHashMap(); - - int length = nodes.size(); - int count = 3; - for (int i = 0; i < length; i++) { - Set set = new HashSet<>(count); - for (int j = 0; j < count; j++) { - set.add(sorted.get((i + j) % length)); - } - partitions.put("p" + (i + 1), set); - } - return partitions; - } - -} \ No newline at end of file diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseDefinitionStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseDefinitionStore.java deleted file mode 100644 index b77667b2..00000000 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseDefinitionStore.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.onosproject.store.consistent.impl; - -import static com.google.common.base.Preconditions.checkNotNull; -import java.io.File; -import java.io.IOException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.common.io.Files; - -/** - * Allows for reading and writing partitioned database definition as a JSON file. - */ -public class DatabaseDefinitionStore { - - private final File file; - - /** - * Creates a reader/writer of the database definition file. - * - * @param filePath location of the definition file - */ - public DatabaseDefinitionStore(String filePath) { - file = new File(checkNotNull(filePath)); - } - - /** - * Creates a reader/writer of the database definition file. - * - * @param filePath location of the definition file - */ - public DatabaseDefinitionStore(File filePath) { - file = checkNotNull(filePath); - } - - /** - * Returns the database definition. - * - * @return database definition - * @throws IOException when I/O exception of some sort has occurred. - */ - public DatabaseDefinition read() throws IOException { - ObjectMapper mapper = new ObjectMapper(); - return mapper.readValue(file, DatabaseDefinition.class); - } - - /** - * Writes the specified database definition to file. - * - * @param definition database definition - * @throws IOException when I/O exception of some sort has occurred. - */ - public void write(DatabaseDefinition definition) throws IOException { - checkNotNull(definition); - // write back to file - Files.createParentDirs(file); - ObjectMapper mapper = new ObjectMapper(); - mapper.writeValue(file, definition); - } -} 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 6ea7c220..3e89635a 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 @@ -18,7 +18,6 @@ package org.onosproject.store.consistent.impl; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; @@ -50,12 +49,12 @@ import org.apache.felix.scr.annotations.Service; import org.onosproject.app.ApplicationEvent; import org.onosproject.app.ApplicationListener; import org.onosproject.app.ApplicationService; +import org.onosproject.cluster.ClusterMetadataService; import org.onosproject.cluster.ClusterService; +import org.onosproject.cluster.ControllerNode; import org.onosproject.cluster.NodeId; import org.onosproject.core.ApplicationId; import org.onosproject.core.IdGenerator; -import org.onosproject.store.cluster.impl.ClusterDefinitionManager; -import org.onosproject.store.cluster.impl.NodeInfo; import org.onosproject.store.cluster.messaging.ClusterCommunicationService; import org.onosproject.store.ecmap.EventuallyConsistentMapBuilderImpl; import org.onosproject.store.service.AtomicCounterBuilder; @@ -73,8 +72,6 @@ import org.onosproject.store.service.Transaction; import org.onosproject.store.service.TransactionContextBuilder; import org.slf4j.Logger; -import java.io.File; -import java.io.IOException; import java.util.Collection; import java.util.List; import java.util.Map; @@ -99,8 +96,6 @@ public class DatabaseManager implements StorageService, StorageAdminService { private final Logger log = getLogger(getClass()); - public static final int COPYCAT_TCP_PORT = 9876; - public static final String PARTITION_DEFINITION_FILE = "../config/tablets.json"; public static final String BASE_PARTITION_NAME = "p0"; private static final int RAFT_ELECTION_TIMEOUT_MILLIS = 3000; @@ -121,6 +116,9 @@ public class DatabaseManager implements StorageService, StorageAdminService { private final Multimap mapsByApplication = Multimaps.synchronizedMultimap(ArrayListMultimap.create()); + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ClusterMetadataService clusterMetadataService; + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected ClusterService clusterService; @@ -130,8 +128,9 @@ public class DatabaseManager implements StorageService, StorageAdminService { @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected ClusterCommunicationService clusterCommunicator; - protected String nodeToUri(NodeInfo node) { - return String.format("onos://%s:%d", node.getIp(), node.getTcpPort()); + protected String nodeIdToUri(NodeId nodeId) { + ControllerNode node = clusterService.getNode(nodeId); + return String.format("onos://%s:%d", node.ip(), node.tcpPort()); } protected void bindApplicationService(ApplicationService service) { @@ -147,30 +146,22 @@ public class DatabaseManager implements StorageService, StorageAdminService { @Activate public void activate() { localNodeId = clusterService.getLocalNode().id(); - // load database configuration - File databaseDefFile = new File(PARTITION_DEFINITION_FILE); - log.info("Loading database definition: {}", databaseDefFile.getAbsolutePath()); - Map> partitionMap; - try { - DatabaseDefinitionStore databaseDefStore = new DatabaseDefinitionStore(databaseDefFile); - if (!databaseDefFile.exists()) { - createDefaultDatabaseDefinition(databaseDefStore); - } - partitionMap = databaseDefStore.read().getPartitions(); - } catch (IOException e) { - throw new IllegalStateException("Failed to load database config", e); - } + Map> partitionMap = Maps.newHashMap(); + clusterMetadataService.getClusterMetadata().getPartitions().forEach(p -> { + partitionMap.put(p.getName(), Sets.newHashSet(p.getMembers())); + }); + String[] activeNodeUris = partitionMap.values() .stream() .reduce((s1, s2) -> Sets.union(s1, s2)) .get() .stream() - .map(this::nodeToUri) + .map(this::nodeIdToUri) .toArray(String[]::new); - String localNodeUri = nodeToUri(NodeInfo.of(clusterService.getLocalNode())); + String localNodeUri = nodeIdToUri(clusterMetadataService.getLocalNode().id()); Protocol protocol = new CopycatCommunicationProtocol(clusterService, clusterCommunicator); ClusterConfig clusterConfig = new ClusterConfig() @@ -198,7 +189,7 @@ public class DatabaseManager implements StorageService, StorageAdminService { List partitions = partitionMap.entrySet() .stream() .map(entry -> { - String[] replicas = entry.getValue().stream().map(this::nodeToUri).toArray(String[]::new); + String[] replicas = entry.getValue().stream().map(this::nodeIdToUri).toArray(String[]::new); return newDatabaseConfig(entry.getKey(), newPersistentLog(), replicas); }) .map(config -> { @@ -229,17 +220,6 @@ public class DatabaseManager implements StorageService, StorageAdminService { log.info("Started"); } - private void createDefaultDatabaseDefinition(DatabaseDefinitionStore store) { - // Assumes IPv4 is returned. - String ip = ClusterDefinitionManager.getSiteLocalAddress(); - NodeInfo node = NodeInfo.from(ip, ip, COPYCAT_TCP_PORT); - try { - store.write(DatabaseDefinition.from(ImmutableSet.of(node))); - } catch (IOException e) { - log.warn("Unable to write default cluster definition", e); - } - } - @Deactivate public void deactivate() { CompletableFuture.allOf(inMemoryDatabase.close(), partitionedDatabase.close()) diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultTransactionContext.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultTransactionContext.java index b66f424b..73888221 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultTransactionContext.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultTransactionContext.java @@ -86,7 +86,7 @@ public class DefaultTransactionContext implements TransactionContext { @SuppressWarnings("unchecked") @Override - public void commit() { + public boolean commit() { // TODO: rework commit implementation to be more intuitive checkState(isOpen, TX_NOT_OPEN_ERROR); CommitResponse response = null; @@ -95,10 +95,11 @@ public class DefaultTransactionContext implements TransactionContext { txMaps.values().forEach(m -> updates.addAll(m.prepareDatabaseUpdates())); Transaction transaction = new DefaultTransaction(transactionId, updates); response = Futures.getUnchecked(database.prepareAndCommit(transaction)); + return response.success(); + } catch (Exception e) { + abort(); + return false; } finally { - if (response != null && !response.success()) { - abort(); - } isOpen = false; } } diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/device/impl/GossipDeviceStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/device/impl/GossipDeviceStore.java index 973db494..687762e0 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/device/impl/GossipDeviceStore.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/device/impl/GossipDeviceStore.java @@ -427,6 +427,7 @@ public class GossipDeviceStore // Primary providers can respond to all changes, but ancillary ones // should respond only to annotation changes. + DeviceEvent event = null; if ((providerId.isAncillary() && annotationsChanged) || (!providerId.isAncillary() && (propertiesChanged || annotationsChanged))) { boolean replaced = devices.replace(newDevice.id(), oldDevice, newDevice); @@ -436,17 +437,18 @@ public class GossipDeviceStore providerId, oldDevice, devices.get(newDevice.id()) , newDevice); } - if (!providerId.isAncillary()) { - boolean wasOnline = availableDevices.contains(newDevice.id()); - markOnline(newDevice.id(), newTimestamp); - if (!wasOnline) { - notifyDelegateIfNotNull(new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, newDevice, null)); - } - } - return new DeviceEvent(DeviceEvent.Type.DEVICE_UPDATED, newDevice, null); + event = new DeviceEvent(DeviceEvent.Type.DEVICE_UPDATED, newDevice, null); } - return null; + + if (!providerId.isAncillary()) { + boolean wasOnline = availableDevices.contains(newDevice.id()); + markOnline(newDevice.id(), newTimestamp); + if (!wasOnline) { + notifyDelegateIfNotNull(new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, newDevice, null)); + } + } + return event; } @Override diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/ecmap/MapDbPersistentStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/ecmap/MapDbPersistentStore.java index e62a2d5c..f5ce47fc 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/ecmap/MapDbPersistentStore.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/ecmap/MapDbPersistentStore.java @@ -100,4 +100,4 @@ class MapDbPersistentStore implements PersistentStore { items.remove(keyBytes); database.commit(); } -} +} \ No newline at end of file diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/newresource/impl/ConsistentResourceStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/newresource/impl/ConsistentResourceStore.java index 10f79eb0..687576c3 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/newresource/impl/ConsistentResourceStore.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/newresource/impl/ConsistentResourceStore.java @@ -52,7 +52,7 @@ import static com.google.common.base.Preconditions.checkNotNull; /** * Implementation of ResourceStore using TransactionalMap. */ -@Component(immediate = true, enabled = false) +@Component(immediate = true) @Service @Beta public class ConsistentResourceStore implements ResourceStore { @@ -238,6 +238,18 @@ public class ConsistentResourceStore implements ResourceStore { .collect(Collectors.toList()); } + @Override + public Collection getChildResources(ResourcePath parent) { + checkNotNull(parent); + + Versioned> children = childMap.get(parent); + if (children == null) { + return Collections.emptyList(); + } + + return children.value(); + } + @Override public Collection getAllocatedResources(ResourcePath parent, Class cls) { checkNotNull(parent); diff --git a/framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/intent/impl/PartitionManagerTest.java b/framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/intent/impl/PartitionManagerTest.java index 25e23d3a..61d1937e 100644 --- a/framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/intent/impl/PartitionManagerTest.java +++ b/framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/intent/impl/PartitionManagerTest.java @@ -325,5 +325,11 @@ public class PartitionManagerTest { return Objects.equals(this.hash(), that.hash()); } + + @Override + public int compareTo(Key o) { + Long thisHash = hash(); + return thisHash.compareTo(o.hash()); + } } } diff --git a/framework/src/onos/core/store/persistence/pom.xml b/framework/src/onos/core/store/persistence/pom.xml new file mode 100644 index 00000000..555de11a --- /dev/null +++ b/framework/src/onos/core/store/persistence/pom.xml @@ -0,0 +1,66 @@ + + + + 4.0.0 + + + repository.springsource.com.release + SpringSource OBR - Release + http://repository.springsource.com/maven/bundles/release + + + repository.springsource.com.external + SpringSource OBR - External + http://repository.springsource.com/maven/bundles/external + + + + + org.onosproject + onos-core-store + 1.4.0-SNAPSHOT + ../pom.xml + + + onos-core-persistence + bundle + + ONOS Core persistent local store subsystem + + + + + + + org.onosproject + onos-api + tests + test + + + org.mapdb + mapdb + 1.0.8 + + + + diff --git a/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/DefaultPersistentMapBuilder.java b/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/DefaultPersistentMapBuilder.java new file mode 100644 index 00000000..88c7d148 --- /dev/null +++ b/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/DefaultPersistentMapBuilder.java @@ -0,0 +1,63 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.persistence.impl; + +import org.mapdb.DB; +import org.onosproject.persistence.PersistentMapBuilder; +import org.onosproject.store.service.Serializer; + +import java.util.Map; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Default builder for persistent maps stored in the mapDB local database via the persistence service. + */ +public class DefaultPersistentMapBuilder implements PersistentMapBuilder { + + private final DB localDB; + + private String name = null; + + private Serializer serializer = null; + + + public DefaultPersistentMapBuilder(DB localDB) { + checkNotNull(localDB, "The local database cannot be null."); + this.localDB = localDB; + } + + public PersistentMapBuilder withName(String name) { + this.name = PersistenceManager.MAP_PREFIX + checkNotNull(name); + return this; + } + + public PersistentMapBuilder withSerializer(Serializer serializer) { + checkArgument(this.serializer == null); + checkNotNull(serializer); + this.serializer = serializer; + return this; + } + + public Map build() { + checkNotNull(name, "The name must be assigned."); + checkNotNull(serializer, "The key serializer must be assigned."); + + return new PersistentMap(serializer, localDB, name); + } +} \ No newline at end of file diff --git a/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/DefaultPersistentSetBuilder.java b/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/DefaultPersistentSetBuilder.java new file mode 100644 index 00000000..e1544fb4 --- /dev/null +++ b/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/DefaultPersistentSetBuilder.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.persistence.impl; + +import org.mapdb.DB; +import org.onosproject.persistence.PersistentSetBuilder; +import org.onosproject.store.service.Serializer; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Default builder for persistent sets stored in the mapDB local database via the persistence service.. + */ +public class DefaultPersistentSetBuilder implements PersistentSetBuilder { + + private final DB localDB; + + private String name = null; + + private Serializer serializer = null; + + public DefaultPersistentSetBuilder(DB localDB) { + this.localDB = checkNotNull(localDB, "The local database cannot be null."); + } + + public PersistentSetBuilder withName(String name) { + this.name = PersistenceManager.SET_PREFIX + checkNotNull(name); + return this; + } + + public PersistentSetBuilder withSerializer(Serializer serializer) { + checkArgument(this.serializer == null); + checkNotNull(serializer); + this.serializer = serializer; + return this; + } + + public PersistentSet build() { + checkNotNull(name, "The name must be assigned."); + checkNotNull(serializer, "The serializer must be assigned."); + + return new PersistentSet(serializer, localDB, name); + } +} \ No newline at end of file diff --git a/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistenceException.java b/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistenceException.java new file mode 100644 index 00000000..f2ba20c2 --- /dev/null +++ b/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistenceException.java @@ -0,0 +1,30 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.persistence.impl; + +/** + * An exception defined for failures of the local persistent store system. + */ + +/** + * Throws an exception with the specified message. + */ +public class PersistenceException extends RuntimeException { + public PersistenceException(String s) { + super(s); + } +} diff --git a/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistenceManager.java b/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistenceManager.java new file mode 100644 index 00000000..64a8683a --- /dev/null +++ b/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistenceManager.java @@ -0,0 +1,138 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.persistence.impl; + +import org.apache.felix.scr.annotations.Activate; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Deactivate; +import org.apache.felix.scr.annotations.Service; +import org.mapdb.DB; +import org.mapdb.DBMaker; +import org.onosproject.persistence.PersistenceService; +import org.onosproject.persistence.PersistentMapBuilder; +import org.onosproject.persistence.PersistentSetBuilder; +import org.slf4j.Logger; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Map; +import java.util.Set; +import java.util.Timer; +import java.util.TimerTask; + +import static org.slf4j.LoggerFactory.getLogger; + +/** + * Service that maintains local disk backed maps and sets. This implementation automatically deletes empty structures + * on shutdown. + */ +@Component(immediate = true) +@Service +public class PersistenceManager implements PersistenceService { + + private static final String DATABASE_PATH = "../data/localDB"; + + private static final String ENCLOSING_FOLDER = "../data"; + + static final String MAP_PREFIX = "map:"; + + static final String SET_PREFIX = "set:"; + + private final Logger log = getLogger(getClass()); + + private DB localDB = null; + + private static final int FLUSH_FREQUENCY_MILLIS = 3000; + + private final Timer timer = new Timer(); + + private final CommitTask commitTask = new CommitTask(); + + @Activate + public void activate() { + Path dbPath = Paths.get(DATABASE_PATH); + Path dbFolderPath = Paths.get(ENCLOSING_FOLDER); + //Make sure the directory exists, if it does not, make it. + if (!dbFolderPath.toFile().isDirectory()) { + log.info("The specified folder location for the database did not exist and will be created."); + try { + Files.createDirectories(dbFolderPath); + } catch (IOException e) { + log.error("Could not create the required folder for the database."); + throw new PersistenceException("Database folder could not be created."); + } + } + //Notify if the database file does not exist. + boolean dbFound = Files.exists(dbPath); + if (!dbFound) { + log.info("The database file could not be located, a new database will be constructed."); + + } else { + log.info("A previous database file has been found."); + } + localDB = DBMaker.newFileDB(dbPath.toFile()) + .asyncWriteEnable() + .closeOnJvmShutdown() + .make(); + timer.schedule(commitTask, FLUSH_FREQUENCY_MILLIS, FLUSH_FREQUENCY_MILLIS); + log.info("Started"); + } + + @Deactivate + public void deactivate() { + for (Map.Entry entry : localDB.getAll().entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + //This is a map implementation to be handled as such + if (value instanceof Map) { + Map asMap = (Map) value; + if (asMap.isEmpty()) { + //the map is empty and may be deleted + localDB.delete(key); + } + //This is a set implementation and can be handled as such + } else if (value instanceof Set) { + Set asSet = (Set) value; + if (asSet.isEmpty()) { + //the set is empty and may be deleted + localDB.delete(key); + } + } + } + localDB.commit(); + localDB.close(); + log.info("Stopped"); + } + + public PersistentMapBuilder persistentMapBuilder() { + return new DefaultPersistentMapBuilder<>(localDB); + } + + public PersistentSetBuilder persistentSetBuilder() { + return new DefaultPersistentSetBuilder<>(localDB); + } + + private class CommitTask extends TimerTask { + + @Override + public void run() { + localDB.commit(); + } + } +} \ No newline at end of file diff --git a/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistentMap.java b/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistentMap.java new file mode 100644 index 00000000..4506bbda --- /dev/null +++ b/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistentMap.java @@ -0,0 +1,192 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.persistence.impl; + +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import org.mapdb.DB; +import org.mapdb.Hasher; +import org.onosproject.store.service.Serializer; + +import java.util.Collection; +import java.util.Map; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; + + +/** + * A map implementation that stores and receives all data from a serialized internal map. + */ +public class PersistentMap implements Map { + + private final Serializer serializer; + + private final org.mapdb.DB database; + + private final Map items; + + private final String name; + + public PersistentMap(Serializer serializer, DB database, String name) { + this.serializer = checkNotNull(serializer); + this.database = checkNotNull(database); + this.name = checkNotNull(name); + + items = database + .createHashMap(name) + .keySerializer(org.mapdb.Serializer.BYTE_ARRAY) + .valueSerializer(org.mapdb.Serializer.BYTE_ARRAY) + .hasher(Hasher.BYTE_ARRAY) + .makeOrGet(); + } + + /** + * Reads this set in deserialized form into the provided map. + * + * @param items the map to be populated + */ + public void readInto(Map items) { + this.items.forEach((keyBytes, valueBytes) -> + items.put(serializer.decode(keyBytes), + serializer.decode(valueBytes))); + } + + @Override + public V remove(Object key) { + checkNotNull(key, "Key can not be null."); + V removed = get(key); + items.remove(serializer.encode(key)); + return removed; + } + + @Override + public int size() { + return items.size(); + } + + @Override + public boolean isEmpty() { + return items.isEmpty(); + } + + @Override + public boolean containsKey(Object key) { + checkNotNull(key, "Key cannot be null."); + return items.containsKey(serializer.encode(key)); + } + + @Override + public boolean containsValue(Object value) { + checkNotNull(value, "Value cannot be null."); + byte[] serialized = serializer.encode(value); + for (byte[] compareValue : items.values()) { + boolean same = true; + if (compareValue == null) { + same = false; + } else if (compareValue.length != serialized.length) { + same = false; + } else { + for (int i = 0; i < serialized.length; i++) { + if (serialized[i] != compareValue[i]) { + same = false; + break; + } + } + } + if (same) { + return true; + } + } + return false; + } + + @Override + public V get(Object key) { + checkNotNull(key, "Key cannot be null."); + return serializer.decode(items.get(serializer.encode(key))); + } + + @Override + public V put(K key, V value) { + checkNotNull(key, "Key cannot be null."); + checkNotNull(value, "Value cannot be null."); + byte[] prevVal = items.put(serializer.encode(key), serializer.encode(value)); + if (prevVal == null) { + return null; + } + return serializer.decode(prevVal); + } + + @Override + public void putAll(Map m) { + checkNotNull(m, "The passed in map cannot be null."); + m.forEach((k, v) -> items.put(serializer.encode(k), serializer.encode(v))); + } + + @Override + public void clear() { + items.clear(); + } + + @Override + public Set keySet() { + Set keys = Sets.newHashSet(); + items.keySet().forEach(k -> keys.add(serializer.decode(k))); + return keys; + } + + @Override + public Collection values() { + Collection values = Sets.newHashSet(); + items.values().forEach(v -> values.add(serializer.decode(v))); + return values; + } + + @Override + public Set> entrySet() { + Set> entries = Sets.newHashSet(); + items.entrySet(). + forEach(e -> entries.add(Maps.immutableEntry(serializer.decode(e.getKey()), + serializer.decode(e.getValue())))); + return entries; + } + + @Override + public boolean equals(Object map) { + //This is not threadsafe and on larger maps incurs a significant processing cost + if (!(map instanceof Map)) { + return false; + } + Map asMap = (Map) map; + if (this.size() != asMap.size()) { + return false; + } + for (Entry entry : this.entrySet()) { + Object key = entry.getKey(); + if (!asMap.containsKey(key) || !asMap.get(key).equals(entry.getValue())) { + return false; + } + } + return true; + } + + @Override + public int hashCode() { + return super.hashCode(); + } +} \ No newline at end of file diff --git a/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistentSet.java b/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistentSet.java new file mode 100644 index 00000000..26118cf6 --- /dev/null +++ b/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistentSet.java @@ -0,0 +1,194 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.persistence.impl; + +import com.google.common.collect.Iterators; +import org.mapdb.DB; +import org.mapdb.Hasher; +import org.mapdb.Serializer; + +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A set implementation that gets and receives all data from a serialized internal set. + */ +//TODO add locking for reads and writes +public class PersistentSet implements Set { + + private final org.onosproject.store.service.Serializer serializer; + + private final org.mapdb.DB database; + + private final Set items; + + private final String name; + + public PersistentSet(org.onosproject.store.service.Serializer serializer, DB database, String name) { + this.serializer = checkNotNull(serializer); + this.database = checkNotNull(database); + this.name = checkNotNull(name); + + items = database + .createHashSet(name) + .serializer(Serializer.BYTE_ARRAY) + .hasher(Hasher.BYTE_ARRAY) + .makeOrGet(); + } + + public void readInto(Set items) { + this.items.forEach(item -> items.add(serializer.decode(item))); + } + + @Override + public int size() { + return items.size(); + } + + @Override + public boolean isEmpty() { + return items.isEmpty(); + } + + @Override + public boolean contains(Object o) { + checkNotNull(o, "The argument cannot be null"); + return items.contains(serializer.encode(o)); + } + + @Override + public Iterator iterator() { + return Iterators.transform(items.iterator(), serializer::decode); + } + + @Override + public Object[] toArray() { + Object[] retArray = new Object[items.size()]; + int index = 0; + Iterator iterator = items.iterator(); + while (iterator.hasNext()) { + retArray[index] = serializer.decode(iterator.next()); + index++; + } + return retArray; + } + + @Override + public T[] toArray(T[] a) { + checkNotNull(a, "The passed in array cannot be null."); + int index = 0; + Iterator iterator = items.iterator(); + T[] retArray; + if (a.length >= items.size()) { + retArray = a; + } else { + retArray = (T[]) new Object[items.size()]; + } + while (iterator.hasNext()) { + retArray[index++] = serializer.decode(iterator.next()); + } + if (retArray.length > items.size()) { + retArray[index] = null; + } + return retArray; + } + + @Override + public boolean add(E item) { + checkNotNull("Item to be added cannot be null."); + return items.add(serializer.encode(item)); + } + + @Override + public boolean remove(Object o) { + checkNotNull(o, "Item to be removed cannot be null."); + return items.remove(serializer.encode(o)); + } + + @Override + public boolean containsAll(Collection c) { + checkNotNull(c, "Collection cannot be internal."); + for (Object item : c) { + if (!items.contains(serializer.encode(item))) { + return false; + } + } + return true; + } + + @Override + public boolean addAll(Collection c) { + checkNotNull(c, "The collection to be added cannot be null."); + boolean changed = false; + for (Object item : c) { + changed = items.add(serializer.encode(item)) || changed; + } + return changed; + } + + @Override + public boolean retainAll(Collection c) { + boolean changed = false; + for (byte[] item : items) { + E deserialized = serializer.decode(item); + if (!c.contains(deserialized)) { + changed = items.remove(item) || changed; + } + } + return changed; + } + + @Override + public boolean removeAll(Collection c) { + boolean changed = false; + for (Object item : c) { + changed = items.remove(serializer.encode(item)) || changed; + } + return changed; + } + + @Override + public void clear() { + items.clear(); + } + + @Override + public boolean equals(Object set) { + //This is not threadsafe and on larger sets incurs a significant processing cost + if (!(set instanceof Set)) { + return false; + } + Set asSet = (Set) set; + if (asSet.size() != this.size()) { + return false; + } + for (Object item : this) { + if (!asSet.contains(item)) { + return false; + } + } + return true; + } + + @Override + public int hashCode() { + return super.hashCode(); + } +} \ No newline at end of file diff --git a/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/package-info.java b/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/package-info.java new file mode 100644 index 00000000..968a5046 --- /dev/null +++ b/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/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. + */ + +/** + * Implementations of core persistence classes. + */ +package org.onosproject.persistence.impl; diff --git a/framework/src/onos/core/store/persistence/src/main/test/test/PersistentMapTest.java b/framework/src/onos/core/store/persistence/src/main/test/test/PersistentMapTest.java new file mode 100644 index 00000000..b059f18e --- /dev/null +++ b/framework/src/onos/core/store/persistence/src/main/test/test/PersistentMapTest.java @@ -0,0 +1,245 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package test; + +import com.google.common.collect.Maps; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mapdb.DB; +import org.mapdb.DBMaker; +import org.onosproject.persistence.impl.PersistentMap; +import org.onosproject.store.service.Serializer; + +import java.nio.file.Paths; +import java.util.Map; +import java.util.Set; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +/** + * Test suite for Persistent Map. + */ +public class PersistentMapTest { + + private Map map = null; + private DB fakeDB = null; + + + /** + * Set up the database, create a map and a direct executor to handle it. + * + * @throws Exception if instantiation fails + */ + @Before + public void setUp() throws Exception { + //Creates a db, a map within it and a basic integer serializer (async writing is off) + fakeDB = DBMaker + .newFileDB(Paths.get("../testDb").toFile()) + .asyncWriteEnable() + .closeOnJvmShutdown() + .make(); + map = new PersistentMap(new Serializer() { + @Override + public byte[] encode(T object) { + if (object == null) { + return null; + } + int num = (Integer) object; + byte[] result = new byte[4]; + + result[0] = (byte) (num >> 24); + result[1] = (byte) (num >> 16); + result[2] = (byte) (num >> 8); + result[3] = (byte) num; + return result; + } + + @Override + public T decode(byte[] bytes) { + if (bytes == null) { + return null; + } + int num = 0x00000000; + + num = num | bytes[0] << 24; + num = num | bytes[1] << 16; + num = num | bytes[2] << 8; + num = num | bytes[3]; + + return (T) new java.lang.Integer(num); + } + }, fakeDB, "map"); + } + + /** + * Clears and deletes the map, closes the datbase and deletes the file. + * + * @throws Exception if shutdown fails + */ + @After + public void tearDown() throws Exception { + map.clear(); + fakeDB.delete("map:map"); + fakeDB.commit(); + fakeDB.close(); + //This is key to prevent artifacts persisting between tests. + Paths.get("../testDB").toFile().delete(); + + + } + + @Test + public void testRemove() throws Exception { + //Checks removal and return values + fillMap(10); + assertEquals(10, map.size()); + for (int i = 0; i < 10; i++) { + assertEquals("The previous value was wrong.", new Integer(i), map.remove(i)); + assertNull("The previous value was wrong.", map.remove(i)); + //(i+1) compensates for base zero. + assertEquals("The size was wrong.", 10 - (i + 1), map.size()); + } + } + + @Test + public void testSize() throws Exception { + //Checks size values throughout addition and removal + for (int i = 0; i < 10; i++) { + map.put(i, i); + assertEquals("The map size is wrong.", i + 1, map.size()); + } + for (int i = 0; i < 10; i++) { + map.remove(i); + assertEquals("The map size is wrong.", 9 - i, map.size()); + } + } + + @Test + public void testIsEmpty() throws Exception { + //Checks empty condition + //asserts that the map starts out empty + assertTrue("Map should be empty", map.isEmpty()); + map.put(1, 1); + assertFalse("Map shouldn't be empty.", map.isEmpty()); + map.remove(1); + assertTrue("Map should be empty", map.isEmpty()); + } + + @Test + public void testContains() throws Exception { + //Checks both containsKey and containsValue be aware the implementations vary widely (value does not use mapDB + //due to object '=='being an insufficient check) + for (int i = 0; i < 10; i++) { + assertFalse("Map should not contain the key", map.containsKey(i)); + assertFalse("Map should not contain the value", map.containsValue(i)); + map.put(i, i); + assertTrue("Map should contain the key", map.containsKey(i)); + assertTrue("Map should contain the value", map.containsValue(i)); + } + } + + @Test + public void testGet() throws Exception { + //Tests value retrieval and nonexistent key return values + for (int i = 0; i < 10; i++) { + map.put(i, i); + for (int j = 0; j <= i; j++) { + assertEquals("The value was wrong.", new Integer(j), map.get(j)); + } + } + assertNull("Null return value for nonexistent keys.", map.get(10)); + } + + @Test + public void testPutAll() throws Exception { + //Tests adding of an outside map + Map testMap = Maps.newHashMap(); + fillMap(10); + map.putAll(testMap); + for (int i = 0; i < 10; i++) { + assertTrue("The map should contain the current 'i' value.", map.containsKey(i)); + assertTrue("The map should contain the current 'i' value.", map.containsValue(i)); + } + } + + @Test + public void testClear() throws Exception { + //Tests clearing the map + assertTrue("Map was initialized incorrectly, should be empty.", map.isEmpty()); + fillMap(10); + assertFalse("Map should contain entries now.", map.isEmpty()); + map.clear(); + assertTrue("Map should have been cleared of entries.", map.isEmpty()); + + } + + @Test + public void testKeySet() throws Exception { + //Tests key set generation + fillMap(10); + Set keys = map.keySet(); + for (int i = 0; i < 10; i++) { + assertTrue("The key set doesn't contain all keys 0-9", keys.contains(i)); + } + assertEquals("The key set has an incorrect number of entries", 10, keys.size()); + } + + @Test + public void testValues() throws Exception { + //Tests value set generation + fillMap(10); + Set values = (Set) map.values(); + for (int i = 0; i < 10; i++) { + assertTrue("The key set doesn't contain all keys 0-9", values.contains(i)); + } + assertEquals("The key set has an incorrect number of entries", 10, values.size()); + } + + @Test + public void testEntrySet() throws Exception { + //Test entry set generation (violates abstraction by knowing the type of the returned entries) + fillMap(10); + Set> entries = map.entrySet(); + for (int i = 0; i < 10; i++) { + assertTrue("The key set doesn't contain all keys 0-9", entries.contains(Maps.immutableEntry(i, i))); + } + assertEquals("The key set has an incorrect number of entries", 10, entries.size()); + } + + @Test public void testPut() throws Exception { + //Tests insertion behavior (particularly the returning of previous value) + fillMap(10); + for (int i = 0; i < 10; i++) { + assertEquals("Put should return the previous value", new Integer(i), map.put(i, i + 1)); + } + assertNull(map.put(11, 11)); + } + + /** + * Populated the map with pairs of integers from (0, 0) up to (numEntries - 1, numEntries -1). + * @param numEntries number of entries to add + */ + private void fillMap(int numEntries) { + for (int i = 0; i < numEntries; i++) { + map.put(i, i); + } + } +} diff --git a/framework/src/onos/core/store/persistence/src/main/test/test/PersistentSetTest.java b/framework/src/onos/core/store/persistence/src/main/test/test/PersistentSetTest.java new file mode 100644 index 00000000..3107ab30 --- /dev/null +++ b/framework/src/onos/core/store/persistence/src/main/test/test/PersistentSetTest.java @@ -0,0 +1,274 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package test; + +import com.google.common.collect.Sets; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mapdb.DB; +import org.mapdb.DBMaker; +import org.onosproject.persistence.impl.PersistentSet; +import org.onosproject.store.service.Serializer; + +import java.nio.file.Paths; +import java.util.HashSet; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +/** + * Test suite for Persistent Set. + */ +public class PersistentSetTest { + + private Set set = null; + private DB fakeDB = null; + + @Before + public void setUp() throws Exception { + //Creates a db, a set within it and a basic integer serializer (async writing is off) + fakeDB = DBMaker + .newFileDB(Paths.get("../testDb").toFile()) + .asyncWriteEnable() + .closeOnJvmShutdown() + .make(); + set = new PersistentSet(new Serializer() { + @Override + public byte[] encode(T object) { + if (object == null) { + return null; + } + int num = (Integer) object; + byte[] result = new byte[4]; + + result[0] = (byte) (num >> 24); + result[1] = (byte) (num >> 16); + result[2] = (byte) (num >> 8); + result[3] = (byte) num; + return result; + } + + @Override + public T decode(byte[] bytes) { + if (bytes == null) { + return null; + } + int num = 0x00000000; + + num = num | bytes[0] << 24; + num = num | bytes[1] << 16; + num = num | bytes[2] << 8; + num = num | bytes[3]; + + return (T) new java.lang.Integer(num); + } + }, fakeDB, "set"); + + } + + @After + public void tearDown() throws Exception { + set.clear(); + fakeDB.delete("map:map"); + fakeDB.commit(); + fakeDB.close(); + //This is key to prevent artifacts persisting between tests. + Paths.get("../testDB").toFile().delete(); + } + + @Test + public void testSize() throws Exception { + //Check correct sizing throughout population + for (int i = 0; i < 10; i++) { + set.add(i); + assertEquals("The set should have i + 1 entries.", i + 1, set.size()); + } + } + + @Test + public void testIsEmpty() throws Exception { + //test empty condition + assertTrue("The set should be initialized empty.", set.isEmpty()); + fillSet(5, this.set); + assertFalse("The set should no longer be empty.", set.isEmpty()); + set.clear(); + assertTrue("The set should have been cleared.", set.isEmpty()); + } + + @Test + public void testContains() throws Exception { + //Test contains + assertFalse("The set should not contain anything", set.contains(1)); + fillSet(10, this.set); + for (int i = 0; i < 10; i++) { + assertTrue("The set should contain all values 0-9.", set.contains(i)); + } + } + + @Test + public void testIterator() throws Exception { + //Test iterator behavior (no order guarantees are made) + Set validationSet = Sets.newHashSet(); + fillSet(10, this.set); + fillSet(10, validationSet); + set.iterator().forEachRemaining(item -> assertTrue("Items were mismatched.", validationSet.remove(item))); + //All values should have been seen and removed + assertTrue("All entries in the validation set should have been removed.", validationSet.isEmpty()); + } + + @Test + public void testToArray() throws Exception { + //Test creation of a new array of the values + fillSet(10, set); + Object[] arr = set.toArray(); + assertEquals("The array should be of length 10.", 10, arr.length); + for (int i = 0; i < 10; i++) { + assertTrue("All elements of the array should be in the set.", set.contains((Integer) arr[i])); + } + } + + @Test + public void testToArray1() throws Exception { + //Test creation of a new array with the possibility of populating passed array if space allows + Integer[] originalArray = new Integer[9]; + fillSet(9, set); + //Test the case where the array and set match in size + Object[] retArray = set.toArray(originalArray); + assertEquals("If the set can fit the array should be the one passed in.", originalArray, retArray); + //Test the case where the passe array is too small to fit the set + set.add(9); + assertNotEquals("A new set should be generated if the contents will not fit in the passed set", + set.toArray(originalArray), originalArray); + //Now test the case where there should be a null terminator + set.clear(); + fillSet(5, set); + assertNull("The character one after last should be null if the array is larger than the set.", + set.toArray(originalArray)[5]); + } + + @Test + public void testAdd() throws Exception { + //Test of add + for (int i = 0; i < 10; i++) { + assertEquals("The size of the set is wrong.", i, set.size()); + assertTrue("The first add of an element should be true.", set.add(i)); + assertFalse("The second add of an element should be false.", set.add(i)); + } + } + + @Test + public void testRemove() throws Exception { + //Test removal + fillSet(10, set); + for (int i = 0; i < 10; i++) { + assertEquals("The size of the set is wrong.", 10 - i, set.size()); + assertTrue("The first removal should be true.", set.remove(i)); + assertFalse("The second removal should be false (item no longer contained).", set.remove(i)); + } + assertTrue("All elements should have been removed.", set.isEmpty()); + } + + @Test + public void testContainsAll() throws Exception { + //Test contains with short circuiting + Set integersToCheck = Sets.newHashSet(); + fillSet(10, integersToCheck); + fillSet(10, set); + assertTrue("The sets should be identical so mutual subsets.", set.containsAll(integersToCheck)); + set.remove(9); + assertFalse("The set should contain one fewer value.", set.containsAll(integersToCheck)); + } + + @Test + public void testAddAll() throws Exception { + //Test multi-adds with change checking + Set integersToCheck = Sets.newHashSet(); + fillSet(10, integersToCheck); + assertFalse("Set should be empty and so integers to check should not be a subset.", + set.containsAll(integersToCheck)); + assertTrue("The set should have changed as a result of add all.", set.addAll(integersToCheck)); + assertFalse("The set should not have changed as a result of add all a second time.", + set.addAll(integersToCheck)); + assertTrue("The sets should now be equivalent.", set.containsAll(integersToCheck)); + assertTrue("The sets should now be equivalent.", integersToCheck.containsAll(set)); + } + + @Test + public void testRetainAll() throws Exception { + //Test ability to generate the intersection set + Set retainSet = Sets.newHashSet(); + fillSet(10, set); + assertTrue("The set should have changed.", set.retainAll(retainSet)); + assertTrue("The set should have been emptied.", set.isEmpty()); + fillSet(10, set); + fillSet(10, retainSet); + Set duplicateSet = new HashSet<>(set); + assertFalse("The set should not have changed.", set.retainAll(retainSet)); + assertEquals("The set should be the same as the duplicate.", duplicateSet, set); + retainSet.remove(9); + assertTrue("The set should have changed.", set.retainAll(retainSet)); + duplicateSet.remove(9); + assertEquals("The set should have had the nine element removed.", duplicateSet, set); + } + + @Test + public void testRemoveAll() throws Exception { + //Test for mass removal and change checking + Set removeSet = Sets.newHashSet(); + fillSet(10, set); + Set duplicateSet = Sets.newHashSet(set); + assertFalse("No elements should change.", set.removeAll(removeSet)); + assertEquals("Set should not have diverged from the duplicate.", duplicateSet, set); + fillSet(5, removeSet); + assertTrue("Elements should have been removed.", set.removeAll(removeSet)); + assertNotEquals("Duplicate set should no longer be equivalent.", duplicateSet, set); + assertEquals("Five elements should have been removed from set.", 5, set.size()); + for (Integer item : removeSet) { + assertFalse("No element of remove set should remain.", set.contains(item)); + } + } + + @Test + public void testClear() throws Exception { + //Test set emptying + assertTrue("The set should be initialized empty.", set.isEmpty()); + set.clear(); + assertTrue("Clear should have no effect on an empty set.", set.isEmpty()); + fillSet(10, set); + assertFalse("The set should no longer be empty.", set.isEmpty()); + set.clear(); + assertTrue("The set should be empty after clear.", set.isEmpty()); + } + + /** + * Populated the map with integers from (0) up to (numEntries - 1). + * + * @param numEntries number of entries to add + */ + private void fillSet(int numEntries, Set set) { + checkNotNull(set); + for (int i = 0; i < numEntries; i++) { + set.add(i); + } + } +} diff --git a/framework/src/onos/core/store/pom.xml b/framework/src/onos/core/store/pom.xml index 2b246b83..219ae5d0 100644 --- a/framework/src/onos/core/store/pom.xml +++ b/framework/src/onos/core/store/pom.xml @@ -33,7 +33,8 @@ dist - serializers + persistence + serializers diff --git a/framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/ExtensionInstructionSerializer.java b/framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/ExtensionInstructionSerializer.java new file mode 100644 index 00000000..6b12df96 --- /dev/null +++ b/framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/ExtensionInstructionSerializer.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.store.serializers; + +import com.esotericsoftware.kryo.Kryo; +import com.esotericsoftware.kryo.Serializer; +import com.esotericsoftware.kryo.io.Input; +import com.esotericsoftware.kryo.io.Output; +import org.onlab.osgi.DefaultServiceDirectory; +import org.onosproject.net.DeviceId; +import org.onosproject.net.behaviour.ExtensionResolver; +import org.onosproject.net.driver.DefaultDriverData; +import org.onosproject.net.driver.DefaultDriverHandler; +import org.onosproject.net.driver.DriverHandler; +import org.onosproject.net.driver.DriverService; +import org.onosproject.net.flow.instructions.ExtensionInstruction; +import org.onosproject.net.flow.instructions.ExtensionType; +import org.onosproject.net.flow.instructions.Instructions; + +/** + * Created by jono on 10/29/15. + */ +public class ExtensionInstructionSerializer extends + Serializer { + + public ExtensionInstructionSerializer() { + super(false, true); + } + + @Override + public void write(Kryo kryo, Output output, Instructions.ExtensionInstructionWrapper object) { + kryo.writeClassAndObject(output, object.extensionInstruction().type()); + kryo.writeClassAndObject(output, object.deviceId()); + + kryo.writeClassAndObject(output, object.extensionInstruction().serialize()); + + } + + @Override + public Instructions.ExtensionInstructionWrapper read(Kryo kryo, Input input, + Class type) { + ExtensionType exType = (ExtensionType) kryo.readClassAndObject(input); + DeviceId deviceId = (DeviceId) kryo.readClassAndObject(input); + + DriverService driverService = DefaultServiceDirectory.getService(DriverService.class); + DriverHandler handler = new DefaultDriverHandler( + new DefaultDriverData(driverService.getDriver(deviceId), deviceId)); + + ExtensionResolver resolver = handler.behaviour(ExtensionResolver.class); + + ExtensionInstruction instruction = resolver.getExtensionInstruction(exType); + + byte[] bytes = (byte[]) kryo.readClassAndObject(input); + + instruction.deserialize(bytes); + + return Instructions.extension(instruction, deviceId); + } +} 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 5b5056cb..0312bafd 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 @@ -70,6 +70,7 @@ import org.onosproject.net.OchPort; import org.onosproject.net.OchSignal; import org.onosproject.net.OchSignalType; import org.onosproject.net.OduCltPort; +import org.onosproject.net.OduSignalId; import org.onosproject.net.OduSignalType; import org.onosproject.net.OmsPort; import org.onosproject.net.Port; @@ -118,6 +119,8 @@ import org.onosproject.net.flow.criteria.MetadataCriterion; import org.onosproject.net.flow.criteria.MplsCriterion; import org.onosproject.net.flow.criteria.OchSignalCriterion; import org.onosproject.net.flow.criteria.OchSignalTypeCriterion; +import org.onosproject.net.flow.criteria.OduSignalIdCriterion; +import org.onosproject.net.flow.criteria.OduSignalTypeCriterion; import org.onosproject.net.flow.criteria.PortCriterion; import org.onosproject.net.flow.criteria.SctpPortCriterion; import org.onosproject.net.flow.criteria.TcpPortCriterion; @@ -125,8 +128,10 @@ import org.onosproject.net.flow.criteria.TunnelIdCriterion; import org.onosproject.net.flow.criteria.UdpPortCriterion; import org.onosproject.net.flow.criteria.VlanIdCriterion; import org.onosproject.net.flow.criteria.VlanPcpCriterion; +import org.onosproject.net.flow.instructions.ExtensionType; import org.onosproject.net.flow.instructions.Instructions; import org.onosproject.net.flow.instructions.L0ModificationInstruction; +import org.onosproject.net.flow.instructions.L1ModificationInstruction; import org.onosproject.net.flow.instructions.L2ModificationInstruction; import org.onosproject.net.flow.instructions.L3ModificationInstruction; import org.onosproject.net.flow.instructions.L4ModificationInstruction; @@ -337,6 +342,8 @@ public final class KryoNamespaces { IndexedLambdaCriterion.class, OchSignalCriterion.class, OchSignalTypeCriterion.class, + OduSignalIdCriterion.class, + OduSignalTypeCriterion.class, Criterion.class, Criterion.Type.class, DefaultTrafficTreatment.class, @@ -349,6 +356,9 @@ public final class KryoNamespaces { L0ModificationInstruction.L0SubType.class, L0ModificationInstruction.ModLambdaInstruction.class, L0ModificationInstruction.ModOchSignalInstruction.class, + L1ModificationInstruction.class, + L1ModificationInstruction.L1SubType.class, + L1ModificationInstruction.ModOduSignalIdInstruction.class, L2ModificationInstruction.class, L2ModificationInstruction.L2SubType.class, L2ModificationInstruction.ModEtherInstruction.class, @@ -441,6 +451,8 @@ public final class KryoNamespaces { .register(new HostLocationSerializer(), HostLocation.class) .register(new DefaultOutboundPacketSerializer(), DefaultOutboundPacket.class) .register(new AnnotationsSerializer(), DefaultAnnotations.class) + .register(new ExtensionInstructionSerializer(), Instructions.ExtensionInstructionWrapper.class) + .register(ExtensionType.class) .register(Versioned.class) .register(MapEvent.class) .register(MapEvent.Type.class) @@ -458,6 +470,7 @@ public final class KryoNamespaces { .register(OduCltPort.SignalType.class) .register(IndexedLambda.class) .register(OchSignal.class) + .register(OduSignalId.class) .register(OduCltPortDescription.class) .register(OchPortDescription.class) .register(OmsPortDescription.class) diff --git a/framework/src/onos/docs/internal-bgpls b/framework/src/onos/docs/internal-bgpls new file mode 100644 index 00000000..f264c7db --- /dev/null +++ b/framework/src/onos/docs/internal-bgpls @@ -0,0 +1,2 @@ +org.onosproject.bgp.controller* +org.onosproject.bgpio* diff --git a/framework/src/onos/docs/internal-stores b/framework/src/onos/docs/internal-stores index 13c00431..1f1f05ab 100644 --- a/framework/src/onos/docs/internal-stores +++ b/framework/src/onos/docs/internal-stores @@ -1 +1,2 @@ org.onosproject.store.* +org.onosproject.persistence.impl diff --git a/framework/src/onos/docs/internal.xml b/framework/src/onos/docs/internal.xml index de9c1c64..602479eb 100644 --- a/framework/src/onos/docs/internal.xml +++ b/framework/src/onos/docs/internal.xml @@ -89,6 +89,10 @@ PCEP Providers @internal-pcep + + BGP-LS Providers + @internal-bgpls + Other Providers @internal-providers diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraExtensionInterpreter.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraExtensionInterpreter.java new file mode 100644 index 00000000..082c5a6d --- /dev/null +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraExtensionInterpreter.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.driver.extensions; + +import org.onlab.packet.Ip4Address; +import org.onosproject.net.behaviour.ExtensionResolver; +import org.onosproject.net.driver.AbstractHandlerBehaviour; +import org.onosproject.net.flow.instructions.ExtensionInstruction; +import org.onosproject.net.flow.instructions.ExtensionType; +import org.onosproject.openflow.controller.ExtensionInterpreter; +import org.projectfloodlight.openflow.protocol.OFActionType; +import org.projectfloodlight.openflow.protocol.OFFactory; +import org.projectfloodlight.openflow.protocol.action.OFAction; +import org.projectfloodlight.openflow.protocol.action.OFActionSetField; +import org.projectfloodlight.openflow.protocol.oxm.OFOxm; +import org.projectfloodlight.openflow.protocol.oxm.OFOxmTunnelIpv4Dst; +import org.projectfloodlight.openflow.types.IPv4Address; + +/** + * Interpreter for Nicira OpenFlow extensions. + */ +public class NiciraExtensionInterpreter extends AbstractHandlerBehaviour + implements ExtensionInterpreter, ExtensionResolver { + + @Override + public boolean supported(ExtensionType extensionType) { + if (extensionType.equals(ExtensionType.ExtensionTypes.NICIRA_SET_TUNNEL_DST)) { + return true; + } + + return false; + } + + @Override + public OFAction mapInstruction(OFFactory factory, ExtensionInstruction extensionInstruction) { + ExtensionType type = extensionInstruction.type(); + if (type.equals(ExtensionType.ExtensionTypes.NICIRA_SET_TUNNEL_DST.type())) { + NiciraSetTunnelDst tunnelDst = (NiciraSetTunnelDst) extensionInstruction; + return factory.actions().setField(factory.oxms().tunnelIpv4Dst( + IPv4Address.of(tunnelDst.tunnelDst().toInt()))); + } + return null; + } + + @Override + public ExtensionInstruction mapAction(OFAction action) { + if (action.getType().equals(OFActionType.SET_FIELD)) { + OFActionSetField setFieldAction = (OFActionSetField) action; + OFOxm oxm = setFieldAction.getField(); + switch (oxm.getMatchField().id) { + case TUNNEL_IPV4_DST: + OFOxmTunnelIpv4Dst tunnelIpv4Dst = (OFOxmTunnelIpv4Dst) oxm; + return new NiciraSetTunnelDst(Ip4Address.valueOf(tunnelIpv4Dst.getValue().getInt())); + default: + throw new UnsupportedOperationException( + "Driver does not support extension type " + oxm.getMatchField().id); + } + } + return null; + } + + @Override + public ExtensionInstruction getExtensionInstruction(ExtensionType type) { + if (type.equals(ExtensionType.ExtensionTypes.NICIRA_SET_TUNNEL_DST.type())) { + return new NiciraSetTunnelDst(); + } + throw new UnsupportedOperationException( + "Driver does not support extension type " + type.toString()); + } +} diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraSetTunnelDst.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraSetTunnelDst.java new file mode 100644 index 00000000..16aa1b07 --- /dev/null +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraSetTunnelDst.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.driver.extensions; + +import com.google.common.base.MoreObjects; +import org.onlab.packet.Ip4Address; +import org.onlab.util.KryoNamespace; +import org.onosproject.net.flow.instructions.AbstractExtensionInstruction; +import org.onosproject.net.flow.instructions.ExtensionType; +import org.onosproject.store.serializers.Ip4AddressSerializer; + +import java.util.Objects; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Nicira set tunnel destination extension instruction. + */ +public class NiciraSetTunnelDst extends AbstractExtensionInstruction { + + private Ip4Address tunnelDst; + + private final KryoNamespace appKryo = new KryoNamespace.Builder() + .register(new Ip4AddressSerializer(), Ip4Address.class) + .register(byte[].class) + .build(); + + /** + * Creates a new set tunnel destination instruction. + */ + NiciraSetTunnelDst() { + tunnelDst = null; + } + + /** + * Creates a new set tunnel destination instruction with a particular IPv4 + * address. + */ + NiciraSetTunnelDst(Ip4Address tunnelDst) { + checkNotNull(tunnelDst); + this.tunnelDst = tunnelDst; + } + + /** + * Gets the tunnel destination IPv4 address. + * + * @return tunnel destination IPv4 address + */ + public Ip4Address tunnelDst() { + return tunnelDst; + } + + @Override + public ExtensionType type() { + return ExtensionType.ExtensionTypes.NICIRA_SET_TUNNEL_DST.type(); + } + + @Override + public void deserialize(byte[] data) { + tunnelDst = appKryo.deserialize(data); + } + + @Override + public byte[] serialize() { + return appKryo.serialize(tunnelDst); + } + + @Override + public int hashCode() { + return Objects.hash(tunnelDst); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof NiciraSetTunnelDst) { + NiciraSetTunnelDst that = (NiciraSetTunnelDst) obj; + return Objects.equals(tunnelDst, that.tunnelDst); + + } + return false; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("tunnelDst", tunnelDst) + .toString(); + } +} diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/package-info.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/package-info.java new file mode 100644 index 00000000..d9d2460d --- /dev/null +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Processing of Nicira extensions. + */ +package org.onosproject.driver.extensions; diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/ovsdb/OvsdbBridgeConfig.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/ovsdb/OvsdbBridgeConfig.java index 524163a1..77b48298 100644 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/ovsdb/OvsdbBridgeConfig.java +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/ovsdb/OvsdbBridgeConfig.java @@ -22,11 +22,13 @@ import java.util.Set; import java.util.stream.Collectors; import org.onlab.packet.IpAddress; +import org.onosproject.net.DefaultAnnotations; import org.onosproject.net.DeviceId; import org.onosproject.net.PortNumber; import org.onosproject.net.behaviour.BridgeConfig; import org.onosproject.net.behaviour.BridgeDescription; import org.onosproject.net.behaviour.BridgeName; +import org.onosproject.net.behaviour.ControllerInfo; import org.onosproject.net.behaviour.DefaultBridgeDescription; import org.onosproject.net.device.DefaultPortDescription; import org.onosproject.net.device.PortDescription; @@ -51,6 +53,13 @@ public class OvsdbBridgeConfig extends AbstractHandlerBehaviour clientService.createBridge(bridgeName.name()); } + @Override + public boolean addBridge(BridgeName bridgeName, String dpid, List controllers) { + DriverHandler handler = handler(); + OvsdbClientService clientService = getOvsdbClientService(handler); + return clientService.createBridge(bridgeName.name(), dpid, controllers); + } + @Override public void deleteBridge(BridgeName bridgeName) { DriverHandler handler = handler(); @@ -108,22 +117,22 @@ public class OvsdbBridgeConfig extends AbstractHandlerBehaviour return ports.stream() .map(x -> new DefaultPortDescription( PortNumber.portNumber(x.portNumber().value()), - true - ) - ) + true, + DefaultAnnotations.builder() + .set("portName", x.portName().value()) + .build())) .collect(Collectors.toSet()); } - // OvsdbNodeId(IP:port) is used in the adaptor while DeviceId(ovsdb:IP:port) + // OvsdbNodeId(IP) is used in the adaptor while DeviceId(ovsdb:IP) // is used in the core. So DeviceId need be changed to OvsdbNodeId. private OvsdbNodeId changeDeviceIdToNodeId(DeviceId deviceId) { - int lastColon = deviceId.toString().lastIndexOf(":"); - int fistColon = deviceId.toString().indexOf(":"); - String ip = deviceId.toString().substring(fistColon + 1, lastColon); - String port = deviceId.toString().substring(lastColon + 1); - IpAddress ipAddress = IpAddress.valueOf(ip); - long portL = Long.parseLong(port); - return new OvsdbNodeId(ipAddress, portL); + String[] splits = deviceId.toString().split(":"); + if (splits == null || splits.length < 1) { + return null; + } + IpAddress ipAddress = IpAddress.valueOf(splits[1]); + return new OvsdbNodeId(ipAddress, 0); } // Used for getting OvsdbClientService. diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/ovsdb/OvsdbTunnelConfig.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/ovsdb/OvsdbTunnelConfig.java index d32fb6be..a32553ad 100644 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/ovsdb/OvsdbTunnelConfig.java +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/ovsdb/OvsdbTunnelConfig.java @@ -16,12 +16,14 @@ package org.onosproject.driver.ovsdb; import java.util.Collection; - +import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import org.onlab.packet.IpAddress; +import org.onosproject.net.DefaultAnnotations; import org.onosproject.net.DeviceId; +import org.onosproject.net.behaviour.BridgeName; import org.onosproject.net.behaviour.DefaultTunnelDescription; import org.onosproject.net.behaviour.IpTunnelEndPoint; import org.onosproject.net.behaviour.TunnelConfig; @@ -41,6 +43,8 @@ public class OvsdbTunnelConfig extends AbstractHandlerBehaviour implements TunnelConfig { private static final String DEFAULT_ADDRESS = "0.0.0.0"; + private static final String OPTION_LOCAL_IP = "local_ip"; + private static final String OPTION_REMOTE_IP = "remote_ip"; @Override public void createTunnel(TunnelDescription tunnel) { @@ -60,6 +64,22 @@ public class OvsdbTunnelConfig extends AbstractHandlerBehaviour ovsdbNode.createTunnel(ipSrc.ip(), ipDst.ip()); } + @Override + public boolean createTunnelInterface(BridgeName bridgeName, TunnelDescription tunnel) { + Map options = ((DefaultAnnotations) tunnel.annotations()).asMap(); + if (tunnel.src() != null) { + options.put(OPTION_LOCAL_IP, tunnel.src().toString()); + } + if (tunnel.dst() != null) { + options.put(OPTION_REMOTE_IP, tunnel.dst().toString()); + } + + DriverHandler handler = handler(); + OvsdbClientService ovsdbClient = getOvsdbNode(handler); + return ovsdbClient.createTunnel(bridgeName.name(), tunnel.tunnelName().toString(), + tunnel.type().toString().toLowerCase(), options); + } + @Override public void removeTunnel(TunnelDescription tunnel) { DriverHandler handler = handler(); @@ -102,16 +122,15 @@ public class OvsdbTunnelConfig extends AbstractHandlerBehaviour .collect(Collectors.toSet()); } - // OvsdbNodeId(IP:port) is used in the adaptor while DeviceId(ovsdb:IP:port) + // OvsdbNodeId(IP) is used in the adaptor while DeviceId(ovsdb:IP) // is used in the core. So DeviceId need be changed to OvsdbNodeId. private OvsdbNodeId changeDeviceIdToNodeId(DeviceId deviceId) { - int lastColon = deviceId.toString().lastIndexOf(":"); - int fistColon = deviceId.toString().indexOf(":"); - String ip = deviceId.toString().substring(fistColon + 1, lastColon); - String port = deviceId.toString().substring(lastColon + 1); - IpAddress ipAddress = IpAddress.valueOf(ip); - long portL = Long.parseLong(port); - return new OvsdbNodeId(ipAddress, portL); + String[] splits = deviceId.toString().split(":"); + if (splits == null || splits.length < 1) { + return null; + } + IpAddress ipAddress = IpAddress.valueOf(splits[1]); + return new OvsdbNodeId(ipAddress, 0); } private OvsdbClientService getOvsdbNode(DriverHandler handler) { diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA1Pipeline.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA1Pipeline.java deleted file mode 100644 index c9ef451e..00000000 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA1Pipeline.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.onosproject.driver.pipeline; - -import static org.slf4j.LoggerFactory.getLogger; - -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.FlowRuleOperations; -import org.onosproject.net.flow.FlowRuleOperationsContext; -import org.onosproject.net.flow.TrafficSelector; -import org.onosproject.net.flow.TrafficTreatment; -import org.slf4j.Logger; - - -/** - * Driver for software switch emulation of the OFDPA 1.0 pipeline. - * The software switch is the CPqD OF 1.3 switch. - */ -public class CpqdOFDPA1Pipeline extends OFDPA1Pipeline { - - private final Logger log = getLogger(getClass()); - - @Override - protected void initializePipeline() { - processPortTable(); - //processVlanTable(); - processTmacTable(); - processIpTable(); - //processMcastTable(); - processBridgingTable(); - processAclTable(); - //processGroupTable(); - } - - @Override - protected void processPortTable() { - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - treatment.transition(VLAN_TABLE); - FlowRule tmisse = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(LOWEST_PRIORITY) - .fromApp(driverId) - .makePermanent() - .forTable(PORT_TABLE).build(); - ops = ops.add(tmisse); - - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Initialized port table"); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to initialize port table"); - } - })); - } - - @Override - protected void processTmacTable() { - //table miss entry - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - selector = DefaultTrafficSelector.builder(); - treatment = DefaultTrafficTreatment.builder(); - treatment.transition(BRIDGING_TABLE); - FlowRule rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(LOWEST_PRIORITY) - .fromApp(driverId) - .makePermanent() - .forTable(TMAC_TABLE).build(); - ops = ops.add(rule); - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Initialized tmac table"); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to initialize tmac table"); - } - })); - } - - @Override - protected void processIpTable() { - //table miss entry - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - selector = DefaultTrafficSelector.builder(); - treatment = DefaultTrafficTreatment.builder(); - treatment.transition(ACL_TABLE); - FlowRule rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(LOWEST_PRIORITY) - .fromApp(driverId) - .makePermanent() - .forTable(UNICAST_ROUTING_TABLE).build(); - ops = ops.add(rule); - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Initialized IP table"); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to initialize unicast IP table"); - } - })); - } - - private void processBridgingTable() { - //table miss entry - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - selector = DefaultTrafficSelector.builder(); - treatment = DefaultTrafficTreatment.builder(); - treatment.transition(ACL_TABLE); - FlowRule rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(LOWEST_PRIORITY) - .fromApp(driverId) - .makePermanent() - .forTable(BRIDGING_TABLE).build(); - ops = ops.add(rule); - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Initialized Bridging table"); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to initialize Bridging table"); - } - })); - } - - protected void processAclTable() { - //table miss entry - catch all to executed action-set - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - selector = DefaultTrafficSelector.builder(); - treatment = DefaultTrafficTreatment.builder(); - FlowRule rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(LOWEST_PRIORITY) - .fromApp(driverId) - .makePermanent() - .forTable(ACL_TABLE).build(); - ops = ops.add(rule); - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Initialized Acl table"); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to initialize Acl table"); - } - })); - } - -} diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA2Pipeline.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA2Pipeline.java new file mode 100644 index 00000000..a830ed49 --- /dev/null +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA2Pipeline.java @@ -0,0 +1,203 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.pipeline; + +import static org.slf4j.LoggerFactory.getLogger; + +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.FlowRuleOperations; +import org.onosproject.net.flow.FlowRuleOperationsContext; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; +import org.slf4j.Logger; + + +/** + * Driver for software switch emulation of the OFDPA 2.0 pipeline. + * The software switch is the CPqD OF 1.3 switch. + */ +public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { + + private final Logger log = getLogger(getClass()); + + @Override + protected void initializePipeline() { + processPortTable(); + processTmacTable(); + processIpTable(); + processBridgingTable(); + processAclTable(); + // XXX implement table miss entries and default groups + //processVlanTable(); + //processMPLSTable(); + //processGroupTable(); + } + + @Override + protected void processPortTable() { + FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); + treatment.transition(VLAN_TABLE); + FlowRule tmisse = DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(selector.build()) + .withTreatment(treatment.build()) + .withPriority(LOWEST_PRIORITY) + .fromApp(driverId) + .makePermanent() + .forTable(PORT_TABLE).build(); + ops = ops.add(tmisse); + + flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { + @Override + public void onSuccess(FlowRuleOperations ops) { + log.info("Initialized port table"); + } + + @Override + public void onError(FlowRuleOperations ops) { + log.info("Failed to initialize port table"); + } + })); + } + + @Override + protected void processTmacTable() { + //table miss entry + FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); + selector = DefaultTrafficSelector.builder(); + treatment = DefaultTrafficTreatment.builder(); + treatment.transition(BRIDGING_TABLE); + FlowRule rule = DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(selector.build()) + .withTreatment(treatment.build()) + .withPriority(LOWEST_PRIORITY) + .fromApp(driverId) + .makePermanent() + .forTable(TMAC_TABLE).build(); + ops = ops.add(rule); + flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { + @Override + public void onSuccess(FlowRuleOperations ops) { + log.info("Initialized tmac table"); + } + + @Override + public void onError(FlowRuleOperations ops) { + log.info("Failed to initialize tmac table"); + } + })); + } + + @Override + protected void processIpTable() { + //table miss entry + FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); + selector = DefaultTrafficSelector.builder(); + treatment = DefaultTrafficTreatment.builder(); + treatment.transition(ACL_TABLE); + FlowRule rule = DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(selector.build()) + .withTreatment(treatment.build()) + .withPriority(LOWEST_PRIORITY) + .fromApp(driverId) + .makePermanent() + .forTable(UNICAST_ROUTING_TABLE).build(); + ops = ops.add(rule); + flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { + @Override + public void onSuccess(FlowRuleOperations ops) { + log.info("Initialized IP table"); + } + + @Override + public void onError(FlowRuleOperations ops) { + log.info("Failed to initialize unicast IP table"); + } + })); + } + + private void processBridgingTable() { + //table miss entry + FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); + selector = DefaultTrafficSelector.builder(); + treatment = DefaultTrafficTreatment.builder(); + treatment.transition(ACL_TABLE); + FlowRule rule = DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(selector.build()) + .withTreatment(treatment.build()) + .withPriority(LOWEST_PRIORITY) + .fromApp(driverId) + .makePermanent() + .forTable(BRIDGING_TABLE).build(); + ops = ops.add(rule); + flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { + @Override + public void onSuccess(FlowRuleOperations ops) { + log.info("Initialized Bridging table"); + } + + @Override + public void onError(FlowRuleOperations ops) { + log.info("Failed to initialize Bridging table"); + } + })); + } + + @Override + protected void processAclTable() { + //table miss entry - catch all to executed action-set + FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); + selector = DefaultTrafficSelector.builder(); + treatment = DefaultTrafficTreatment.builder(); + FlowRule rule = DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(selector.build()) + .withTreatment(treatment.build()) + .withPriority(LOWEST_PRIORITY) + .fromApp(driverId) + .makePermanent() + .forTable(ACL_TABLE).build(); + ops = ops.add(rule); + flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { + @Override + public void onSuccess(FlowRuleOperations ops) { + log.info("Initialized Acl table"); + } + + @Override + public void onError(FlowRuleOperations ops) { + log.info("Failed to initialize Acl table"); + } + })); + } + +} diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA1Pipeline.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA1Pipeline.java deleted file mode 100644 index f17309e1..00000000 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA1Pipeline.java +++ /dev/null @@ -1,887 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.onosproject.driver.pipeline; - -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.List; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; - -import org.onlab.osgi.ServiceDirectory; -import org.onlab.packet.Ethernet; -import org.onlab.packet.MplsLabel; -import org.onlab.packet.VlanId; -import org.onlab.util.KryoNamespace; -import org.onosproject.core.ApplicationId; -import org.onosproject.core.CoreService; -import org.onosproject.core.DefaultGroupId; -import org.onosproject.net.DeviceId; -import org.onosproject.net.PortNumber; -import org.onosproject.net.behaviour.NextGroup; -import org.onosproject.net.behaviour.Pipeliner; -import org.onosproject.net.behaviour.PipelinerContext; -import org.onosproject.net.driver.AbstractHandlerBehaviour; -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.FlowRuleOperations; -import org.onosproject.net.flow.FlowRuleOperationsContext; -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.criteria.Criterion; -import org.onosproject.net.flow.criteria.EthCriterion; -import org.onosproject.net.flow.criteria.EthTypeCriterion; -import org.onosproject.net.flow.criteria.IPCriterion; -import org.onosproject.net.flow.criteria.PortCriterion; -import org.onosproject.net.flow.criteria.VlanIdCriterion; -import org.onosproject.net.flow.instructions.Instruction; -import org.onosproject.net.flow.instructions.Instructions.OutputInstruction; -import org.onosproject.net.flow.instructions.L2ModificationInstruction; -import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction; -import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction; -import org.onosproject.net.flowobjective.FilteringObjective; -import org.onosproject.net.flowobjective.FlowObjectiveStore; -import org.onosproject.net.flowobjective.ForwardingObjective; -import org.onosproject.net.flowobjective.NextObjective; -import org.onosproject.net.flowobjective.Objective; -import org.onosproject.net.flowobjective.ObjectiveError; -import org.onosproject.net.group.DefaultGroupBucket; -import org.onosproject.net.group.DefaultGroupDescription; -import org.onosproject.net.group.DefaultGroupKey; -import org.onosproject.net.group.Group; -import org.onosproject.net.group.GroupBucket; -import org.onosproject.net.group.GroupBuckets; -import org.onosproject.net.group.GroupDescription; -import org.onosproject.net.group.GroupEvent; -import org.onosproject.net.group.GroupKey; -import org.onosproject.net.group.GroupListener; -import org.onosproject.net.group.GroupService; -import org.onosproject.store.serializers.KryoNamespaces; -import org.slf4j.Logger; - -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.RemovalCause; -import com.google.common.cache.RemovalNotification; - -/** - * Driver for Broadcom's OF-DPA v1.0 TTP. - * - */ -public class OFDPA1Pipeline extends AbstractHandlerBehaviour implements Pipeliner { - - protected static final int PORT_TABLE = 0; - protected static final int VLAN_TABLE = 10; - protected static final int TMAC_TABLE = 20; - protected static final int UNICAST_ROUTING_TABLE = 30; - protected static final int MULTICAST_ROUTING_TABLE = 40; - protected static final int BRIDGING_TABLE = 50; - protected static final int ACL_TABLE = 60; - protected static final int MAC_LEARNING_TABLE = 254; - - private static final int HIGHEST_PRIORITY = 0xffff; - private static final int DEFAULT_PRIORITY = 0x8000; - protected static final int LOWEST_PRIORITY = 0x0; - - /* - * Group keys are normally generated by using the next Objective id. In the - * case of a next objective resulting in a group chain, each group derives a - * group key from the next objective id in the following way: - * The upper 4 bits of the group-key are used to denote the position of the - * group in the group chain. For example, in the chain - * group0 --> group1 --> group2 --> port - * group0's group key would have the upper 4 bits as 0, group1's upper four - * bits would be 1, and so on - */ - private static final int GROUP0MASK = 0x0; - private static final int GROUP1MASK = 0x10000000; - - /* - * OFDPA requires group-id's to have a certain form. - * L2 Interface Groups have <4bits-0><12bits-vlanid><16bits-portid> - * L3 Unicast Groups have <4bits-2><28bits-index> - */ - private static final int L2INTERFACEMASK = 0x0; - private static final int L3UNICASTMASK = 0x20000000; - - private final Logger log = getLogger(getClass()); - private ServiceDirectory serviceDirectory; - protected FlowRuleService flowRuleService; - private CoreService coreService; - private GroupService groupService; - private FlowObjectiveStore flowObjectiveStore; - protected DeviceId deviceId; - protected ApplicationId driverId; - - private KryoNamespace appKryo = new KryoNamespace.Builder() - .register(KryoNamespaces.API) - .register(GroupKey.class) - .register(DefaultGroupKey.class) - .register(OfdpaGroupChain.class) - .register(byte[].class) - .build(); - - private Cache pendingNextObjectives; - private ConcurrentHashMap pendingGroups; - - private ScheduledExecutorService groupChecker = - Executors.newScheduledThreadPool(2, groupedThreads("onos/pipeliner", - "ofdpa1-%d")); - - @Override - public void init(DeviceId deviceId, PipelinerContext context) { - this.serviceDirectory = context.directory(); - this.deviceId = deviceId; - - pendingNextObjectives = CacheBuilder.newBuilder() - .expireAfterWrite(20, TimeUnit.SECONDS) - .removalListener((RemovalNotification notification) -> { - if (notification.getCause() == RemovalCause.EXPIRED) { - fail(notification.getValue().nextObjective(), - ObjectiveError.GROUPINSTALLATIONFAILED); - } - }).build(); - - groupChecker.scheduleAtFixedRate(new GroupChecker(), 0, 500, TimeUnit.MILLISECONDS); - pendingGroups = new ConcurrentHashMap(); - - coreService = serviceDirectory.get(CoreService.class); - flowRuleService = serviceDirectory.get(FlowRuleService.class); - groupService = serviceDirectory.get(GroupService.class); - flowObjectiveStore = context.store(); - - groupService.addListener(new InnerGroupListener()); - - driverId = coreService.registerApplication( - "org.onosproject.driver.OFDPA1Pipeline"); - - initializePipeline(); - - } - - @Override - public void filter(FilteringObjective filteringObjective) { - if (filteringObjective.type() == FilteringObjective.Type.PERMIT) { - processFilter(filteringObjective, - filteringObjective.op() == Objective.Operation.ADD, - filteringObjective.appId()); - } else { - fail(filteringObjective, ObjectiveError.UNSUPPORTED); - } - } - - @Override - public void forward(ForwardingObjective fwd) { - Collection rules; - FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder(); - - rules = processForward(fwd); - switch (fwd.op()) { - case ADD: - rules.stream() - .filter(rule -> rule != null) - .forEach(flowOpsBuilder::add); - break; - case REMOVE: - rules.stream() - .filter(rule -> rule != null) - .forEach(flowOpsBuilder::remove); - break; - default: - fail(fwd, ObjectiveError.UNKNOWN); - log.warn("Unknown forwarding type {}", fwd.op()); - } - - - flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - pass(fwd); - } - - @Override - public void onError(FlowRuleOperations ops) { - fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED); - } - })); - - } - - @Override - public void next(NextObjective nextObjective) { - switch (nextObjective.type()) { - case SIMPLE: - Collection treatments = nextObjective.next(); - if (treatments.size() != 1) { - log.error("Next Objectives of type Simple should only have a " - + "single Traffic Treatment. Next Objective Id:{}", nextObjective.id()); - fail(nextObjective, ObjectiveError.BADPARAMS); - return; - } - processSimpleNextObjective(nextObjective); - break; - case HASHED: - case BROADCAST: - case FAILOVER: - fail(nextObjective, ObjectiveError.UNSUPPORTED); - log.warn("Unsupported next objective type {}", nextObjective.type()); - break; - default: - fail(nextObjective, ObjectiveError.UNKNOWN); - log.warn("Unknown next objective type {}", nextObjective.type()); - } - } - - /** - * As per OFDPA 1.0 TTP, filtering of VLAN ids, MAC addresses (for routing) - * and IP addresses configured on switch ports happen in different tables. - * Note that IP filtering rules need to be added to the ACL table, as there - * is no mechanism to send to controller via IP table. - * - * @param filt - * @param install - * @param applicationId - */ - private void processFilter(FilteringObjective filt, - boolean install, ApplicationId applicationId) { - // This driver only processes filtering criteria defined with switch - // ports as the key - PortCriterion p = null; EthCriterion e = null; VlanIdCriterion v = null; - Collection ips = new ArrayList(); - if (!filt.key().equals(Criteria.dummy()) && - filt.key().type() == Criterion.Type.IN_PORT) { - p = (PortCriterion) filt.key(); - } else { - log.warn("No key defined in filtering objective from app: {}. Not" - + "processing filtering objective", applicationId); - fail(filt, ObjectiveError.UNKNOWN); - return; - } - // convert filtering conditions for switch-intfs into flowrules - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - for (Criterion c : filt.conditions()) { - if (c.type() == Criterion.Type.ETH_DST) { - e = (EthCriterion) c; - } else if (c.type() == Criterion.Type.VLAN_VID) { - v = (VlanIdCriterion) c; - } else if (c.type() == Criterion.Type.IPV4_DST) { - ips.add((IPCriterion) c); - } else { - log.error("Unsupported filter {}", c); - fail(filt, ObjectiveError.UNSUPPORTED); - return; - } - } - - log.debug("adding VLAN filtering rule in VLAN table: {}", e.mac()); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - selector.matchInPort(p.port()); - selector.matchVlanId(v.vlanId()); - treatment.transition(TMAC_TABLE); - FlowRule rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(DEFAULT_PRIORITY) - .fromApp(applicationId) - .makePermanent() - .forTable(VLAN_TABLE).build(); - ops = ops.add(rule); - - log.debug("adding MAC filtering rules in TMAC table: {}", e.mac()); - selector = DefaultTrafficSelector.builder(); - treatment = DefaultTrafficTreatment.builder(); - selector.matchInPort(p.port()); - selector.matchVlanId(v.vlanId()); - selector.matchEthType(Ethernet.TYPE_IPV4); - selector.matchEthDst(e.mac()); - treatment.transition(UNICAST_ROUTING_TABLE); - rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(DEFAULT_PRIORITY) - .fromApp(applicationId) - .makePermanent() - .forTable(TMAC_TABLE).build(); - ops = ops.add(rule); - - log.debug("adding IP filtering rules in ACL table"); - for (IPCriterion ipaddr : ips) { - selector = DefaultTrafficSelector.builder(); - treatment = DefaultTrafficTreatment.builder(); - selector.matchEthType(Ethernet.TYPE_IPV4); - selector.matchIPDst(ipaddr.ip()); - treatment.setOutput(PortNumber.CONTROLLER); - rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(HIGHEST_PRIORITY) - .fromApp(applicationId) - .makePermanent() - .forTable(ACL_TABLE).build(); - ops = ops.add(rule); - } - - ops = install ? ops.add(rule) : ops.remove(rule); - // apply filtering flow rules - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Applied filtering rules"); - pass(filt); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to apply filtering rules"); - fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED); - } - })); - - } - - - /** - * As per the OFDPA 1.0 TTP, packets are sent out of ports by using - * a chain of groups, namely an L3 Unicast Group that points to an L2 Interface - * Group which in turns points to an output port. The Next Objective passed - * in by the application has to be broken up into a group chain - * to satisfy this TTP. - * - * @param nextObj the nextObjective of type SIMPLE - */ - private void processSimpleNextObjective(NextObjective nextObj) { - // break up simple next objective to GroupChain objects - TrafficTreatment treatment = nextObj.next().iterator().next(); - // for the l2interface group, get vlan and port info - // for the l3unicast group, get the src/dst mac and vlan info - TrafficTreatment.Builder l3utt = DefaultTrafficTreatment.builder(); - TrafficTreatment.Builder l2itt = DefaultTrafficTreatment.builder(); - VlanId vlanid = null; - long portNum = 0; - for (Instruction ins : treatment.allInstructions()) { - if (ins.type() == Instruction.Type.L2MODIFICATION) { - L2ModificationInstruction l2ins = (L2ModificationInstruction) ins; - switch (l2ins.subtype()) { - case ETH_DST: - l3utt.setEthDst(((ModEtherInstruction) l2ins).mac()); - break; - case ETH_SRC: - l3utt.setEthSrc(((ModEtherInstruction) l2ins).mac()); - break; - case VLAN_ID: - vlanid = ((ModVlanIdInstruction) l2ins).vlanId(); - l3utt.setVlanId(vlanid); - break; - case DEC_MPLS_TTL: - case MPLS_LABEL: - case MPLS_POP: - case MPLS_PUSH: - case VLAN_PCP: - case VLAN_POP: - case VLAN_PUSH: - default: - break; - } - } else if (ins.type() == Instruction.Type.OUTPUT) { - portNum = ((OutputInstruction) ins).port().toLong(); - l2itt.add(ins); - } else { - log.warn("Driver does not handle this type of TrafficTreatment" - + " instruction in nextObjectives: {}", ins.type()); - } - } - - // assemble information for ofdpa l2interface group - int l2gk = nextObj.id() | GROUP1MASK; - final GroupKey l2groupkey = new DefaultGroupKey(appKryo.serialize(l2gk)); - Integer l2groupId = L2INTERFACEMASK | (vlanid.toShort() << 16) | (int) portNum; - - // assemble information for ofdpa l3unicast group - int l3gk = nextObj.id() | GROUP0MASK; - final GroupKey l3groupkey = new DefaultGroupKey(appKryo.serialize(l3gk)); - Integer l3groupId = L3UNICASTMASK | (int) portNum; - l3utt.group(new DefaultGroupId(l2groupId)); - GroupChainElem gce = new GroupChainElem(l3groupkey, l3groupId, - l3utt.build(), nextObj.appId()); - - // create object for local and distributed storage - List gkeys = new ArrayList(); - gkeys.add(l3groupkey); // group0 in chain - gkeys.add(l2groupkey); // group1 in chain - OfdpaGroupChain ofdpaGrp = new OfdpaGroupChain(gkeys, nextObj); - - // store l2groupkey with the groupChainElem for the l3group that depends on it - pendingGroups.put(l2groupkey, gce); - - // store l3groupkey with the ofdpaGroupChain for the nextObjective that depends on it - pendingNextObjectives.put(l3groupkey, ofdpaGrp); - - // create group description for the ofdpa l2interfacegroup and send to groupservice - GroupBucket bucket = - DefaultGroupBucket.createIndirectGroupBucket(l2itt.build()); - GroupDescription groupDescription = new DefaultGroupDescription(deviceId, - GroupDescription.Type.INDIRECT, - new GroupBuckets(Collections.singletonList(bucket)), - l2groupkey, - l2groupId, - nextObj.appId()); - groupService.addGroup(groupDescription); - } - - /** - * Processes next element of a group chain. Assumption is that if this - * group points to another group, the latter has already been created - * and this driver has received notification for it. A second assumption is - * that if there is another group waiting for this group then the appropriate - * stores already have the information to act upon the notification for the - * creating of this group. - * - * @param gce the group chain element to be processed next - */ - private void processGroupChain(GroupChainElem gce) { - GroupBucket bucket = DefaultGroupBucket - .createIndirectGroupBucket(gce.getBucketActions()); - GroupDescription groupDesc = new DefaultGroupDescription(deviceId, - GroupDescription.Type.INDIRECT, - new GroupBuckets(Collections.singletonList(bucket)), - gce.getGkey(), - gce.getGivenGroupId(), - gce.getAppId()); - groupService.addGroup(groupDesc); - } - - private Collection processForward(ForwardingObjective fwd) { - switch (fwd.flag()) { - case SPECIFIC: - return processSpecific(fwd); - case VERSATILE: - return processVersatile(fwd); - default: - fail(fwd, ObjectiveError.UNKNOWN); - log.warn("Unknown forwarding flag {}", fwd.flag()); - } - return Collections.emptySet(); - } - - /** - * In the OF-DPA 1.0 pipeline, versatile forwarding objectives go to the - * ACL table. - * @param fwd the forwarding objective of type 'versatile' - * @return a collection of flow rules to be sent to the switch. An empty - * collection may be returned if there is a problem in processing - * the flow rule - */ - private Collection processVersatile(ForwardingObjective fwd) { - log.info("Processing versatile forwarding objective"); - TrafficSelector selector = fwd.selector(); - - EthTypeCriterion ethType = - (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE); - if (ethType == null) { - log.error("Versatile forwarding objective must include ethType"); - fail(fwd, ObjectiveError.UNKNOWN); - return Collections.emptySet(); - } - if (ethType.ethType().toShort() == Ethernet.TYPE_ARP) { - log.warn("Installing ARP rule to table 60"); - - // currently need to punt from ACL table should use: - // OF apply-actions-instruction - // To use OF write-actions-instruction - /*TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder(); - fwd.treatment().allInstructions().stream() - .forEach(ti -> tb.deferred().add(ti));*/ - - FlowRule.Builder ruleBuilder = DefaultFlowRule.builder() - .fromApp(fwd.appId()) - .withPriority(fwd.priority()) - .forDevice(deviceId) - .withSelector(fwd.selector()) - .withTreatment(fwd.treatment()) - .makePermanent() - .forTable(ACL_TABLE); - - return Collections.singletonList(ruleBuilder.build()); - } - - // XXX not handling other versatile flows yet - return Collections.emptySet(); - } - - /** - * In the OF-DPA 1.0 pipeline, specific forwarding refers to the IP table - * (unicast or multicast) or the L2 table (mac + vlan). - * - * @param fwd the forwarding objective of type 'specific' - * @return a collection of flow rules. Typically there will be only one - * for this type of forwarding objective. An empty set may be - * returned if there is an issue in processing the objective. - */ - private Collection processSpecific(ForwardingObjective fwd) { - log.debug("Processing specific forwarding objective"); - TrafficSelector selector = fwd.selector(); - EthTypeCriterion ethType = - (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE); - // XXX currently supporting only the L3 unicast table - if (ethType == null || ethType.ethType().toShort() != Ethernet.TYPE_IPV4) { - fail(fwd, ObjectiveError.UNSUPPORTED); - return Collections.emptySet(); - } - - TrafficSelector filteredSelector = - DefaultTrafficSelector.builder() - .matchEthType(Ethernet.TYPE_IPV4) - .matchIPDst( - ((IPCriterion) - selector.getCriterion(Criterion.Type.IPV4_DST)).ip()) - .build(); - - TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder(); - - if (fwd.nextId() != null) { - NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId()); - List gkeys = appKryo.deserialize(next.data()); - Group group = groupService.getGroup(deviceId, gkeys.get(0)); - if (group == null) { - log.warn("The group left!"); - fail(fwd, ObjectiveError.GROUPMISSING); - return Collections.emptySet(); - } - tb.deferred().group(group.id()); - } - tb.transition(ACL_TABLE); - FlowRule.Builder ruleBuilder = DefaultFlowRule.builder() - .fromApp(fwd.appId()) - .withPriority(fwd.priority()) - .forDevice(deviceId) - .withSelector(filteredSelector) - .withTreatment(tb.build()); - - if (fwd.permanent()) { - ruleBuilder.makePermanent(); - } else { - ruleBuilder.makeTemporary(fwd.timeout()); - } - - ruleBuilder.forTable(UNICAST_ROUTING_TABLE); - return Collections.singletonList(ruleBuilder.build()); - } - - private void pass(Objective obj) { - if (obj.context().isPresent()) { - obj.context().get().onSuccess(obj); - } - } - - - private void fail(Objective obj, ObjectiveError error) { - if (obj.context().isPresent()) { - obj.context().get().onError(obj, error); - } - } - - - protected void initializePipeline() { - processPortTable(); - processVlanTable(); - processTmacTable(); - processIpTable(); - //processMcastTable(); - //processBridgingTable(); - //processAclTable(); - //processGroupTable(); - //processMplsTable(); - } - - protected void processMplsTable() { - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - selector.matchEthType(Ethernet.MPLS_UNICAST); - selector.matchMplsLabel(MplsLabel.mplsLabel(0xff)); - selector.matchMplsBos(true); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - treatment.popMpls(Ethernet.TYPE_IPV4); - treatment.transition(ACL_TABLE); - FlowRule test = DefaultFlowRule.builder().forDevice(deviceId) - .withSelector(selector.build()).withTreatment(treatment.build()) - .withPriority(LOWEST_PRIORITY).fromApp(driverId).makePermanent() - .forTable(25).build(); - ops = ops.add(test); - - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Initialized mpls table"); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to initialize mpls table"); - } - })); - - } - - protected void processPortTable() { - //XXX is table miss entry enough or do we need to do the maskable in-port 0? - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - selector.matchInPort(PortNumber.portNumber(0)); // should be maskable? - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - treatment.transition(VLAN_TABLE); - FlowRule tmisse = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(LOWEST_PRIORITY) - .fromApp(driverId) - .makePermanent() - .forTable(PORT_TABLE).build(); - /*ops = ops.add(tmisse); - - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Initialized port table"); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to initialize port table"); - } - }));*/ - - } - - private void processVlanTable() { - // Table miss entry is not required as ofdpa default is to drop - // In OF terms, the absence of a t.m.e. also implies drop - } - - - protected void processTmacTable() { - //table miss entry - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - selector = DefaultTrafficSelector.builder(); - treatment = DefaultTrafficTreatment.builder(); - treatment.transition(BRIDGING_TABLE); - FlowRule rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(LOWEST_PRIORITY) - .fromApp(driverId) - .makePermanent() - .forTable(TMAC_TABLE).build(); - /*ops = ops.add(rule); // XXX bug in ofdpa - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Initialized tmac table"); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to initialize tmac table"); - } - }));*/ - } - - protected void processIpTable() { - //table miss entry - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - selector = DefaultTrafficSelector.builder(); - treatment = DefaultTrafficTreatment.builder(); - treatment.transition(ACL_TABLE); - FlowRule rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(LOWEST_PRIORITY) - .fromApp(driverId) - .makePermanent() - .forTable(UNICAST_ROUTING_TABLE).build(); - /*ops = ops.add(rule); - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Initialized IP table"); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to initialize unicast IP table"); - } - }));*/ - } - - private class GroupChecker implements Runnable { - @Override - public void run() { - Set keys = pendingGroups.keySet().stream() - .filter(key -> groupService.getGroup(deviceId, key) != null) - .collect(Collectors.toSet()); - Set otherkeys = pendingNextObjectives.asMap().keySet().stream() - .filter(otherkey -> groupService.getGroup(deviceId, otherkey) != null) - .collect(Collectors.toSet()); - keys.addAll(otherkeys); - - keys.stream().forEach(key -> { - //first check for group chain - GroupChainElem gce = pendingGroups.remove(key); - if (gce != null) { - log.info("Group service processed group key {}. Processing next " - + "group in group chain with group key {}", - appKryo.deserialize(key.key()), - appKryo.deserialize(gce.getGkey().key())); - processGroupChain(gce); - } else { - OfdpaGroupChain obj = pendingNextObjectives.getIfPresent(key); - log.info("Group service processed group key {}. Done implementing " - + "next objective: {}", appKryo.deserialize(key.key()), - obj.nextObjective().id()); - if (obj != null) { - pass(obj.nextObjective()); - pendingNextObjectives.invalidate(key); - flowObjectiveStore.putNextGroup(obj.nextObjective().id(), obj); - } - } - }); - } - } - - private class InnerGroupListener implements GroupListener { - @Override - public void event(GroupEvent event) { - log.debug("received group event of type {}", event.type()); - if (event.type() == GroupEvent.Type.GROUP_ADDED) { - GroupKey key = event.subject().appCookie(); - // first check for group chain - GroupChainElem gce = pendingGroups.remove(key); - if (gce != null) { - log.info("group ADDED with group key {} .. " - + "Processing next group in group chain with group key {}", - appKryo.deserialize(key.key()), - appKryo.deserialize(gce.getGkey().key())); - processGroupChain(gce); - } else { - OfdpaGroupChain obj = pendingNextObjectives.getIfPresent(key); - if (obj != null) { - log.info("group ADDED with key {}.. Done implementing next " - + "objective: {}", - appKryo.deserialize(key.key()), obj.nextObjective().id()); - pass(obj.nextObjective()); - pendingNextObjectives.invalidate(key); - flowObjectiveStore.putNextGroup(obj.nextObjective().id(), obj); - } - } - } - } - } - - /** - * Represents a group-chain that implements a Next-Objective from - * the application. Includes information about the next objective Id, and the - * group keys for the groups in the group chain. The chain is expected to - * look like group0 --> group 1 --> outPort. Information about the groups - * themselves can be fetched from the Group Service using the group keys from - * objects instantiating this class. - */ - private class OfdpaGroupChain implements NextGroup { - private final NextObjective nextObj; - private final List gkeys; - - /** expected group chain: group0 --> group1 --> port. */ - public OfdpaGroupChain(List gkeys, NextObjective nextObj) { - this.gkeys = gkeys; - this.nextObj = nextObj; - } - - @SuppressWarnings("unused") - public List groupKeys() { - return gkeys; - } - - public NextObjective nextObjective() { - return nextObj; - } - - @Override - public byte[] data() { - return appKryo.serialize(gkeys); - } - - } - - /** - * Represents a group element that is part of a chain of groups. - * Stores enough information to create a Group Description to add the group - * to the switch by requesting the Group Service. Objects instantiating this - * class are meant to be temporary and live as long as it is needed to wait for - * preceding groups in the group chain to be created. - */ - private class GroupChainElem { - private TrafficTreatment bucketActions; - private Integer givenGroupId; - private GroupKey gkey; - private ApplicationId appId; - - public GroupChainElem(GroupKey gkey, Integer givenGroupId, - TrafficTreatment tr, ApplicationId appId) { - this.bucketActions = tr; - this.givenGroupId = givenGroupId; - this.gkey = gkey; - this.appId = appId; - } - - public TrafficTreatment getBucketActions() { - return bucketActions; - } - - public Integer getGivenGroupId() { - return givenGroupId; - } - - public GroupKey getGkey() { - return gkey; - } - - public ApplicationId getAppId() { - return appId; - } - - } -} diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA2Pipeline.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA2Pipeline.java new file mode 100644 index 00000000..b1a1256a --- /dev/null +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA2Pipeline.java @@ -0,0 +1,1369 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.pipeline; + +import static org.onlab.util.Tools.groupedThreads; +import static org.slf4j.LoggerFactory.getLogger; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import org.onlab.osgi.ServiceDirectory; +import org.onlab.packet.Data; +import org.onlab.packet.Ethernet; +import org.onlab.packet.IPv4; +import org.onlab.packet.IpPrefix; +import org.onlab.packet.MPLS; +import org.onlab.packet.MacAddress; +import org.onlab.packet.MplsLabel; +import org.onlab.packet.UDP; +import org.onlab.packet.VlanId; +import org.onlab.util.KryoNamespace; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.CoreService; +import org.onosproject.core.DefaultGroupId; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Port; +import org.onosproject.net.PortNumber; +import org.onosproject.net.behaviour.NextGroup; +import org.onosproject.net.behaviour.Pipeliner; +import org.onosproject.net.behaviour.PipelinerContext; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.driver.AbstractHandlerBehaviour; +import org.onosproject.net.flow.DefaultFlowRule; +import org.onosproject.net.flow.DefaultTrafficSelector; +import org.onosproject.net.flow.DefaultTrafficTreatment; +import org.onosproject.net.flow.FlowRule; +import org.onosproject.net.flow.FlowRuleOperations; +import org.onosproject.net.flow.FlowRuleOperationsContext; +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.criteria.Criterion; +import org.onosproject.net.flow.criteria.EthCriterion; +import org.onosproject.net.flow.criteria.EthTypeCriterion; +import org.onosproject.net.flow.criteria.IPCriterion; +import org.onosproject.net.flow.criteria.PortCriterion; +import org.onosproject.net.flow.criteria.VlanIdCriterion; +import org.onosproject.net.flow.instructions.Instruction; +import org.onosproject.net.flow.instructions.Instructions.OutputInstruction; +import org.onosproject.net.flow.instructions.L2ModificationInstruction; +import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction; +import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction; +import org.onosproject.net.flowobjective.FilteringObjective; +import org.onosproject.net.flowobjective.FlowObjectiveStore; +import org.onosproject.net.flowobjective.ForwardingObjective; +import org.onosproject.net.flowobjective.NextObjective; +import org.onosproject.net.flowobjective.Objective; +import org.onosproject.net.flowobjective.ObjectiveError; +import org.onosproject.net.group.DefaultGroupBucket; +import org.onosproject.net.group.DefaultGroupDescription; +import org.onosproject.net.group.DefaultGroupKey; +import org.onosproject.net.group.Group; +import org.onosproject.net.group.GroupBucket; +import org.onosproject.net.group.GroupBuckets; +import org.onosproject.net.group.GroupDescription; +import org.onosproject.net.group.GroupEvent; +import org.onosproject.net.group.GroupKey; +import org.onosproject.net.group.GroupListener; +import org.onosproject.net.group.GroupService; +import org.onosproject.net.packet.DefaultOutboundPacket; +import org.onosproject.net.packet.OutboundPacket; +import org.onosproject.net.packet.PacketContext; +import org.onosproject.net.packet.PacketProcessor; +import org.onosproject.net.packet.PacketService; +import org.onosproject.store.serializers.KryoNamespaces; +import org.slf4j.Logger; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.RemovalCause; +import com.google.common.cache.RemovalNotification; + +/** + * Driver for Broadcom's OF-DPA v2.0 TTP. + * + */ +public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeliner { + + protected static final int PORT_TABLE = 0; + protected static final int VLAN_TABLE = 10; + protected static final int TMAC_TABLE = 20; + protected static final int UNICAST_ROUTING_TABLE = 30; + protected static final int MULTICAST_ROUTING_TABLE = 40; + protected static final int MPLS_TABLE_0 = 23; + protected static final int MPLS_TABLE_1 = 24; + protected static final int BRIDGING_TABLE = 50; + protected static final int ACL_TABLE = 60; + protected static final int MAC_LEARNING_TABLE = 254; + protected static final long OFPP_MAX = 0xffffff00L; + + private static final int HIGHEST_PRIORITY = 0xffff; + private static final int DEFAULT_PRIORITY = 0x8000; + protected static final int LOWEST_PRIORITY = 0x0; + + /* + * Group keys are normally generated by using the next Objective id. In the + * case of a next objective resulting in a group chain, each group derives a + * group key from the next objective id in the following way: + * The upper 4 bits of the group-key are used to denote the position of the + * group in the group chain. For example, in the chain + * group0 --> group1 --> group2 --> port + * group0's group key would have the upper 4 bits as 0, group1's upper four + * bits would be 1, and so on + */ + private static final int GROUP0MASK = 0x0; + private static final int GROUP1MASK = 0x10000000; + + /* + * OFDPA requires group-id's to have a certain form. + * L2 Interface Groups have <4bits-0><12bits-vlanid><16bits-portid> + * L3 Unicast Groups have <4bits-2><28bits-index> + */ + private static final int L2INTERFACEMASK = 0x0; + private static final int L3UNICASTMASK = 0x20000000; + //private static final int MPLSINTERFACEMASK = 0x90000000; + private static final int L3ECMPMASK = 0x70000000; + + private final Logger log = getLogger(getClass()); + private ServiceDirectory serviceDirectory; + protected FlowRuleService flowRuleService; + private CoreService coreService; + private GroupService groupService; + private FlowObjectiveStore flowObjectiveStore; + protected DeviceId deviceId; + protected ApplicationId driverId; + protected PacketService packetService; + protected DeviceService deviceService; + private InternalPacketProcessor processor = new InternalPacketProcessor(); + private KryoNamespace appKryo = new KryoNamespace.Builder() + .register(KryoNamespaces.API) + .register(GroupKey.class) + .register(DefaultGroupKey.class) + .register(OfdpaGroupChain.class) + .register(byte[].class) + .build(); + + private Cache pendingNextObjectives; + private ConcurrentHashMap pendingGroups; + + private ScheduledExecutorService groupChecker = + Executors.newScheduledThreadPool(2, groupedThreads("onos/pipeliner", + "ofdpa2-%d")); + private Set sentIpFilters = Collections.newSetFromMap( + new ConcurrentHashMap()); + + @Override + public void init(DeviceId deviceId, PipelinerContext context) { + this.serviceDirectory = context.directory(); + this.deviceId = deviceId; + + pendingNextObjectives = CacheBuilder.newBuilder() + .expireAfterWrite(20, TimeUnit.SECONDS) + .removalListener((RemovalNotification notification) -> { + if (notification.getCause() == RemovalCause.EXPIRED) { + fail(notification.getValue().nextObjective(), + ObjectiveError.GROUPINSTALLATIONFAILED); + } + }).build(); + + groupChecker.scheduleAtFixedRate(new GroupChecker(), 0, 500, TimeUnit.MILLISECONDS); + pendingGroups = new ConcurrentHashMap(); + + coreService = serviceDirectory.get(CoreService.class); + flowRuleService = serviceDirectory.get(FlowRuleService.class); + groupService = serviceDirectory.get(GroupService.class); + flowObjectiveStore = context.store(); + packetService = serviceDirectory.get(PacketService.class); + deviceService = serviceDirectory.get(DeviceService.class); + packetService.addProcessor(processor, PacketProcessor.director(2)); + groupService.addListener(new InnerGroupListener()); + + driverId = coreService.registerApplication( + "org.onosproject.driver.OFDPA2Pipeline"); + + // OF-DPA does not require initializing the pipeline as it puts default + // rules automatically in the hardware. However emulation of OFDPA in + // software switches does require table-miss-entries. + initializePipeline(); + + } + + protected void initializePipeline() { + + } + + ////////////////////////////////////// + // Flow Objectives + ////////////////////////////////////// + + @Override + public void filter(FilteringObjective filteringObjective) { + if (filteringObjective.type() == FilteringObjective.Type.PERMIT) { + processFilter(filteringObjective, + filteringObjective.op() == Objective.Operation.ADD, + filteringObjective.appId()); + } else { + // Note that packets that don't match the PERMIT filter are + // automatically denied. The DENY filter is used to deny packets + // that are otherwise permitted by the PERMIT filter. + // Use ACL table flow rules here for DENY filtering objectives + log.debug("filter objective other than PERMIT currently not supported"); + fail(filteringObjective, ObjectiveError.UNSUPPORTED); + } + } + + @Override + public void forward(ForwardingObjective fwd) { + Collection rules; + FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder(); + + rules = processForward(fwd); + switch (fwd.op()) { + case ADD: + rules.stream() + .filter(rule -> rule != null) + .forEach(flowOpsBuilder::add); + break; + case REMOVE: + rules.stream() + .filter(rule -> rule != null) + .forEach(flowOpsBuilder::remove); + break; + default: + fail(fwd, ObjectiveError.UNKNOWN); + log.warn("Unknown forwarding type {}", fwd.op()); + } + + + flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() { + @Override + public void onSuccess(FlowRuleOperations ops) { + pass(fwd); + } + + @Override + public void onError(FlowRuleOperations ops) { + fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED); + } + })); + + } + + @Override + public void next(NextObjective nextObjective) { + switch (nextObjective.type()) { + case SIMPLE: + Collection treatments = nextObjective.next(); + if (treatments.size() != 1) { + log.error("Next Objectives of type Simple should only have a " + + "single Traffic Treatment. Next Objective Id:{}", nextObjective.id()); + fail(nextObjective, ObjectiveError.BADPARAMS); + return; + } + processSimpleNextObjective(nextObjective); + break; + case HASHED: + case BROADCAST: + case FAILOVER: + fail(nextObjective, ObjectiveError.UNSUPPORTED); + log.warn("Unsupported next objective type {}", nextObjective.type()); + break; + default: + fail(nextObjective, ObjectiveError.UNKNOWN); + log.warn("Unknown next objective type {}", nextObjective.type()); + } + } + + ////////////////////////////////////// + // Flow handling + ////////////////////////////////////// + + /** + * As per OFDPA 2.0 TTP, filtering of VLAN ids, MAC addresses (for routing) + * and IP addresses configured on switch ports happen in different tables. + * Note that IP filtering rules need to be added to the ACL table, as there + * is no mechanism to send to controller via IP table. + * + * @param filt the filtering objective + * @param install indicates whether to add or remove the objective + * @param applicationId the application that sent this objective + */ + private void processFilter(FilteringObjective filt, + boolean install, ApplicationId applicationId) { + // This driver only processes filtering criteria defined with switch + // ports as the key + PortCriterion portCriterion = null; + EthCriterion ethCriterion = null; + VlanIdCriterion vidCriterion = null; + Collection ips = new ArrayList(); + if (!filt.key().equals(Criteria.dummy()) && + filt.key().type() == Criterion.Type.IN_PORT) { + portCriterion = (PortCriterion) filt.key(); + } else { + log.warn("No key defined in filtering objective from app: {}. Not" + + "processing filtering objective", applicationId); + fail(filt, ObjectiveError.UNKNOWN); + return; + } + // convert filtering conditions for switch-intfs into flowrules + FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); + for (Criterion criterion : filt.conditions()) { + if (criterion.type() == Criterion.Type.ETH_DST) { + ethCriterion = (EthCriterion) criterion; + } else if (criterion.type() == Criterion.Type.VLAN_VID) { + vidCriterion = (VlanIdCriterion) criterion; + } else if (criterion.type() == Criterion.Type.IPV4_DST) { + ips.add((IPCriterion) criterion); + } else { + log.error("Unsupported filter {}", criterion); + fail(filt, ObjectiveError.UNSUPPORTED); + return; + } + } + + VlanId assignedVlan = null; + if (vidCriterion != null && vidCriterion.vlanId() == VlanId.NONE) { + // untagged packets are assigned vlans in OF-DPA + if (filt.meta() == null) { + log.error("Missing metadata in filtering objective required " + + "for vlan assignment in dev {}", deviceId); + fail(filt, ObjectiveError.BADPARAMS); + return; + } + for (Instruction i : filt.meta().allInstructions()) { + if (i instanceof ModVlanIdInstruction) { + assignedVlan = ((ModVlanIdInstruction) i).vlanId(); + } + } + if (assignedVlan == null) { + log.error("Driver requires an assigned vlan-id to tag incoming " + + "untagged packets. Not processing vlan filters on " + + "device {}", deviceId); + fail(filt, ObjectiveError.BADPARAMS); + return; + } + } + + if (ethCriterion == null) { + log.debug("filtering objective missing dstMac, cannot program TMAC table"); + } else { + for (FlowRule tmacRule : processEthDstFilter(portCriterion, ethCriterion, + vidCriterion, assignedVlan, + applicationId)) { + log.debug("adding MAC filtering rules in TMAC table: {} for dev: {}", + tmacRule, deviceId); + ops = install ? ops.add(tmacRule) : ops.remove(tmacRule); + } + } + + if (ethCriterion == null || vidCriterion == null) { + log.debug("filtering objective missing dstMac or vlan, cannot program" + + "Vlan Table"); + } else { + for (FlowRule vlanRule : processVlanIdFilter(portCriterion, vidCriterion, + assignedVlan, + applicationId)) { + log.debug("adding VLAN filtering rule in VLAN table: {} for dev: {}", + vlanRule, deviceId); + ops = install ? ops.add(vlanRule) : ops.remove(vlanRule); + } + } + + for (IPCriterion ipaddr : ips) { + // since we ignore port information for IP rules, and the same (gateway) IP + // can be configured on multiple ports, we make sure that we send + // only a single rule to the switch. + if (!sentIpFilters.contains(ipaddr)) { + sentIpFilters.add(ipaddr); + log.debug("adding IP filtering rules in ACL table {} for dev: {}", + ipaddr, deviceId); + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); + selector.matchEthType(Ethernet.TYPE_IPV4); + selector.matchIPDst(ipaddr.ip()); + treatment.setOutput(PortNumber.CONTROLLER); + FlowRule rule = DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(selector.build()) + .withTreatment(treatment.build()) + .withPriority(HIGHEST_PRIORITY) + .fromApp(applicationId) + .makePermanent() + .forTable(ACL_TABLE).build(); + ops = install ? ops.add(rule) : ops.remove(rule); + } + } + + // apply filtering flow rules + flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { + @Override + public void onSuccess(FlowRuleOperations ops) { + log.info("Applied {} filtering rules in device {}", + ops.stages().get(0).size(), deviceId); + pass(filt); + } + + @Override + public void onError(FlowRuleOperations ops) { + log.info("Failed to apply all filtering rules in dev {}", deviceId); + fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED); + } + })); + + } + + /** + * Allows untagged packets into pipeline by assigning a vlan id. + * Vlan assignment is done by the application. + * Allows tagged packets into pipeline as per configured port-vlan info. + * + * @param portCriterion port on device for which this filter is programmed + * @param vidCriterion vlan assigned to port, or NONE for untagged + * @param assignedVlan assigned vlan-id for untagged packets + * @param applicationId for application programming this filter + * @return list of FlowRule for port-vlan filters + */ + protected List processVlanIdFilter(PortCriterion portCriterion, + VlanIdCriterion vidCriterion, + VlanId assignedVlan, + ApplicationId applicationId) { + List rules = new ArrayList(); + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); + selector.matchVlanId(vidCriterion.vlanId()); + if (vidCriterion.vlanId() == VlanId.NONE) { + // untagged packets are assigned vlans + treatment.pushVlan().setVlanId(assignedVlan); + // XXX ofdpa may require an additional vlan match on the assigned vlan + // and it may not require the push. + } + treatment.transition(TMAC_TABLE); + + // ofdpa cannot match on ALL portnumber, so we need to use separate + // rules for each port. + List portnums = new ArrayList(); + if (portCriterion.port() == PortNumber.ALL) { + for (Port port : deviceService.getPorts(deviceId)) { + if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) { + portnums.add(port.number()); + } + } + } else { + portnums.add(portCriterion.port()); + } + for (PortNumber pnum : portnums) { + selector.matchInPort(pnum); + FlowRule rule = DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(selector.build()) + .withTreatment(treatment.build()) + .withPriority(DEFAULT_PRIORITY) + .fromApp(applicationId) + .makePermanent() + .forTable(VLAN_TABLE).build(); + rules.add(rule); + } + return rules; + } + + /** + * Allows routed packets with correct destination MAC to be directed + * to unicast-IP routing table or MPLS forwarding table. + * XXX need to add rule for multicast routing. + * + * @param portCriterion port on device for which this filter is programmed + * @param ethCriterion dstMac of device for which is filter is programmed + * @param vidCriterion vlan assigned to port, or NONE for untagged + * @param assignedVlan assigned vlan-id for untagged packets + * @param applicationId for application programming this filter + * @return list of FlowRule for port-vlan filters + + */ + protected List processEthDstFilter(PortCriterion portCriterion, + EthCriterion ethCriterion, + VlanIdCriterion vidCriterion, + VlanId assignedVlan, + ApplicationId applicationId) { + //handling untagged packets via assigned VLAN + if (vidCriterion.vlanId() == VlanId.NONE) { + vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan); + } + // ofdpa cannot match on ALL portnumber, so we need to use separate + // rules for each port. + List portnums = new ArrayList(); + if (portCriterion.port() == PortNumber.ALL) { + for (Port port : deviceService.getPorts(deviceId)) { + if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) { + portnums.add(port.number()); + } + } + } else { + portnums.add(portCriterion.port()); + } + + List rules = new ArrayList(); + for (PortNumber pnum : portnums) { + // for unicast IP packets + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); + selector.matchInPort(pnum); + selector.matchVlanId(vidCriterion.vlanId()); + selector.matchEthType(Ethernet.TYPE_IPV4); + selector.matchEthDst(ethCriterion.mac()); + treatment.transition(UNICAST_ROUTING_TABLE); + FlowRule rule = DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(selector.build()) + .withTreatment(treatment.build()) + .withPriority(DEFAULT_PRIORITY) + .fromApp(applicationId) + .makePermanent() + .forTable(TMAC_TABLE).build(); + rules.add(rule); + //for MPLS packets + selector = DefaultTrafficSelector.builder(); + treatment = DefaultTrafficTreatment.builder(); + selector.matchInPort(pnum); + selector.matchVlanId(vidCriterion.vlanId()); + selector.matchEthType(Ethernet.MPLS_UNICAST); + selector.matchEthDst(ethCriterion.mac()); + treatment.transition(MPLS_TABLE_0); + rule = DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(selector.build()) + .withTreatment(treatment.build()) + .withPriority(DEFAULT_PRIORITY) + .fromApp(applicationId) + .makePermanent() + .forTable(TMAC_TABLE).build(); + rules.add(rule); + } + return rules; + } + + private Collection processForward(ForwardingObjective fwd) { + switch (fwd.flag()) { + case SPECIFIC: + return processSpecific(fwd); + case VERSATILE: + return processVersatile(fwd); + default: + fail(fwd, ObjectiveError.UNKNOWN); + log.warn("Unknown forwarding flag {}", fwd.flag()); + } + return Collections.emptySet(); + } + + /** + * In the OF-DPA 2.0 pipeline, versatile forwarding objectives go to the + * ACL table. + * @param fwd the forwarding objective of type 'versatile' + * @return a collection of flow rules to be sent to the switch. An empty + * collection may be returned if there is a problem in processing + * the flow rule + */ + private Collection processVersatile(ForwardingObjective fwd) { + log.info("Processing versatile forwarding objective"); + TrafficSelector selector = fwd.selector(); + + EthTypeCriterion ethType = + (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE); + if (ethType == null) { + log.error("Versatile forwarding objective must include ethType"); + fail(fwd, ObjectiveError.BADPARAMS); + return Collections.emptySet(); + } + if (fwd.nextId() == null && fwd.treatment() == null) { + log.error("Forwarding objective {} from {} must contain " + + "nextId or Treatment", fwd.selector(), fwd.appId()); + return Collections.emptySet(); + } + // XXX driver does not currently do type checking as per Tables 65-67 in + // OFDPA 2.0 spec. The only allowed treatment is a punt to the controller. + if (fwd.treatment() != null && + fwd.treatment().allInstructions().size() == 1 && + fwd.treatment().allInstructions().get(0).type() == Instruction.Type.OUTPUT) { + OutputInstruction o = (OutputInstruction) fwd.treatment().allInstructions().get(0); + if (o.port() == PortNumber.CONTROLLER) { + FlowRule.Builder ruleBuilder = DefaultFlowRule.builder() + .fromApp(fwd.appId()) + .withPriority(fwd.priority()) + .forDevice(deviceId) + .withSelector(fwd.selector()) + .withTreatment(fwd.treatment()) + .makePermanent() + .forTable(ACL_TABLE); + return Collections.singletonList(ruleBuilder.build()); + } else { + log.warn("Only allowed treatments in versatile forwarding " + + "objectives are punts to the controller"); + return Collections.emptySet(); + } + } + + if (fwd.nextId() != null) { + // XXX overide case + log.warn("versatile objective --> next Id not yet implemeted"); + } + return Collections.emptySet(); + } + + /** + * In the OF-DPA 2.0 pipeline, specific forwarding refers to the IP table + * (unicast or multicast) or the L2 table (mac + vlan). + * + * @param fwd the forwarding objective of type 'specific' + * @return a collection of flow rules. Typically there will be only one + * for this type of forwarding objective. An empty set may be + * returned if there is an issue in processing the objective. + */ + private Collection processSpecific(ForwardingObjective fwd) { + log.debug("Processing specific forwarding objective"); + TrafficSelector selector = fwd.selector(); + EthTypeCriterion ethType = + (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE); + // XXX currently supporting only the L3 unicast table + if (ethType == null || ethType.ethType().toShort() != Ethernet.TYPE_IPV4) { + fail(fwd, ObjectiveError.UNSUPPORTED); + return Collections.emptySet(); + } + + TrafficSelector filteredSelector = + DefaultTrafficSelector.builder() + .matchEthType(Ethernet.TYPE_IPV4) + .matchIPDst( + ((IPCriterion) + selector.getCriterion(Criterion.Type.IPV4_DST)).ip()) + .build(); + + TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder(); + + if (fwd.nextId() != null) { + NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId()); + List gkeys = appKryo.deserialize(next.data()); + Group group = groupService.getGroup(deviceId, gkeys.get(0)); + if (group == null) { + log.warn("The group left!"); + fail(fwd, ObjectiveError.GROUPMISSING); + return Collections.emptySet(); + } + tb.deferred().group(group.id()); + } + tb.transition(ACL_TABLE); + FlowRule.Builder ruleBuilder = DefaultFlowRule.builder() + .fromApp(fwd.appId()) + .withPriority(fwd.priority()) + .forDevice(deviceId) + .withSelector(filteredSelector) + .withTreatment(tb.build()); + + if (fwd.permanent()) { + ruleBuilder.makePermanent(); + } else { + ruleBuilder.makeTemporary(fwd.timeout()); + } + + ruleBuilder.forTable(UNICAST_ROUTING_TABLE); + return Collections.singletonList(ruleBuilder.build()); + } + + private void pass(Objective obj) { + if (obj.context().isPresent()) { + obj.context().get().onSuccess(obj); + } + } + + private void fail(Objective obj, ObjectiveError error) { + if (obj.context().isPresent()) { + obj.context().get().onError(obj, error); + } + } + + ////////////////////////////////////// + // Group handling + ////////////////////////////////////// + + /** + * As per the OFDPA 2.0 TTP, packets are sent out of ports by using + * a chain of groups, namely an L3 Unicast Group that points to an L2 Interface + * Group which in turns points to an output port. The Next Objective passed + * in by the application has to be broken up into a group chain + * to satisfy this TTP. + * + * @param nextObj the nextObjective of type SIMPLE + */ + private void processSimpleNextObjective(NextObjective nextObj) { + // break up simple next objective to GroupChain objects + TrafficTreatment treatment = nextObj.next().iterator().next(); + // for the l2interface group, get vlan and port info + // for the l3unicast group, get the src/dst mac and vlan info + TrafficTreatment.Builder l3utt = DefaultTrafficTreatment.builder(); + TrafficTreatment.Builder l2itt = DefaultTrafficTreatment.builder(); + VlanId vlanid = null; + long portNum = 0; + for (Instruction ins : treatment.allInstructions()) { + if (ins.type() == Instruction.Type.L2MODIFICATION) { + L2ModificationInstruction l2ins = (L2ModificationInstruction) ins; + switch (l2ins.subtype()) { + case ETH_DST: + l3utt.setEthDst(((ModEtherInstruction) l2ins).mac()); + break; + case ETH_SRC: + l3utt.setEthSrc(((ModEtherInstruction) l2ins).mac()); + break; + case VLAN_ID: + vlanid = ((ModVlanIdInstruction) l2ins).vlanId(); + l3utt.setVlanId(vlanid); + break; + case DEC_MPLS_TTL: + case MPLS_LABEL: + case MPLS_POP: + case MPLS_PUSH: + case VLAN_PCP: + case VLAN_POP: + case VLAN_PUSH: + default: + break; + } + } else if (ins.type() == Instruction.Type.OUTPUT) { + portNum = ((OutputInstruction) ins).port().toLong(); + l2itt.add(ins); + } else { + log.warn("Driver does not handle this type of TrafficTreatment" + + " instruction in nextObjectives: {}", ins.type()); + } + } + + // assemble information for ofdpa l2interface group + int l2gk = nextObj.id() | GROUP1MASK; + final GroupKey l2groupkey = new DefaultGroupKey(appKryo.serialize(l2gk)); + Integer l2groupId = L2INTERFACEMASK | (vlanid.toShort() << 16) | (int) portNum; + + // assemble information for ofdpa l3unicast group + int l3gk = nextObj.id() | GROUP0MASK; + final GroupKey l3groupkey = new DefaultGroupKey(appKryo.serialize(l3gk)); + Integer l3groupId = L3UNICASTMASK | (int) portNum; + l3utt.group(new DefaultGroupId(l2groupId)); + GroupChainElem gce = new GroupChainElem(l3groupkey, l3groupId, + l3utt.build(), nextObj.appId()); + + // create object for local and distributed storage + List gkeys = new ArrayList(); + gkeys.add(l3groupkey); // group0 in chain + gkeys.add(l2groupkey); // group1 in chain + OfdpaGroupChain ofdpaGrp = new OfdpaGroupChain(gkeys, nextObj); + + // store l2groupkey with the groupChainElem for the l3group that depends on it + pendingGroups.put(l2groupkey, gce); + + // store l3groupkey with the ofdpaGroupChain for the nextObjective that depends on it + pendingNextObjectives.put(l3groupkey, ofdpaGrp); + + // create group description for the ofdpa l2interfacegroup and send to groupservice + GroupBucket bucket = + DefaultGroupBucket.createIndirectGroupBucket(l2itt.build()); + GroupDescription groupDescription = new DefaultGroupDescription(deviceId, + GroupDescription.Type.INDIRECT, + new GroupBuckets(Collections.singletonList(bucket)), + l2groupkey, + l2groupId, + nextObj.appId()); + groupService.addGroup(groupDescription); + } + + /** + * Processes next element of a group chain. Assumption is that if this + * group points to another group, the latter has already been created + * and this driver has received notification for it. A second assumption is + * that if there is another group waiting for this group then the appropriate + * stores already have the information to act upon the notification for the + * creating of this group. + * + * @param gce the group chain element to be processed next + */ + private void processGroupChain(GroupChainElem gce) { + GroupBucket bucket = DefaultGroupBucket + .createIndirectGroupBucket(gce.getBucketActions()); + GroupDescription groupDesc = new DefaultGroupDescription(deviceId, + GroupDescription.Type.INDIRECT, + new GroupBuckets(Collections.singletonList(bucket)), + gce.getGkey(), + gce.getGivenGroupId(), + gce.getAppId()); + groupService.addGroup(groupDesc); + } + + + private class GroupChecker implements Runnable { + @Override + public void run() { + Set keys = pendingGroups.keySet().stream() + .filter(key -> groupService.getGroup(deviceId, key) != null) + .collect(Collectors.toSet()); + Set otherkeys = pendingNextObjectives.asMap().keySet().stream() + .filter(otherkey -> groupService.getGroup(deviceId, otherkey) != null) + .collect(Collectors.toSet()); + keys.addAll(otherkeys); + + keys.stream().forEach(key -> { + //first check for group chain + GroupChainElem gce = pendingGroups.remove(key); + if (gce != null) { + log.info("Group service processed group key {}. Processing next " + + "group in group chain with group key {}", + appKryo.deserialize(key.key()), + appKryo.deserialize(gce.getGkey().key())); + processGroupChain(gce); + } else { + OfdpaGroupChain obj = pendingNextObjectives.getIfPresent(key); + log.info("Group service processed group key {}. Done implementing " + + "next objective: {}", appKryo.deserialize(key.key()), + obj.nextObjective().id()); + if (obj != null) { + pass(obj.nextObjective()); + pendingNextObjectives.invalidate(key); + flowObjectiveStore.putNextGroup(obj.nextObjective().id(), obj); + } + } + }); + } + } + + private class InnerGroupListener implements GroupListener { + @Override + public void event(GroupEvent event) { + log.debug("received group event of type {}", event.type()); + if (event.type() == GroupEvent.Type.GROUP_ADDED) { + GroupKey key = event.subject().appCookie(); + // first check for group chain + GroupChainElem gce = pendingGroups.remove(key); + if (gce != null) { + log.info("group ADDED with group key {} .. " + + "Processing next group in group chain with group key {}", + appKryo.deserialize(key.key()), + appKryo.deserialize(gce.getGkey().key())); + processGroupChain(gce); + } else { + OfdpaGroupChain obj = pendingNextObjectives.getIfPresent(key); + if (obj != null) { + log.info("group ADDED with key {}.. Done implementing next " + + "objective: {}", + appKryo.deserialize(key.key()), obj.nextObjective().id()); + pass(obj.nextObjective()); + pendingNextObjectives.invalidate(key); + flowObjectiveStore.putNextGroup(obj.nextObjective().id(), obj); + } + } + } + } + } + + /** + * Represents a group-chain that implements a Next-Objective from + * the application. Includes information about the next objective Id, and the + * group keys for the groups in the group chain. The chain is expected to + * look like group0 --> group 1 --> outPort. Information about the groups + * themselves can be fetched from the Group Service using the group keys from + * objects instantiating this class. + */ + private class OfdpaGroupChain implements NextGroup { + private final NextObjective nextObj; + private final List gkeys; + + /** expected group chain: group0 --> group1 --> port. */ + public OfdpaGroupChain(List gkeys, NextObjective nextObj) { + this.gkeys = gkeys; + this.nextObj = nextObj; + } + + @SuppressWarnings("unused") + public List groupKeys() { + return gkeys; + } + + public NextObjective nextObjective() { + return nextObj; + } + + @Override + public byte[] data() { + return appKryo.serialize(gkeys); + } + + } + + /** + * Represents a group element that is part of a chain of groups. + * Stores enough information to create a Group Description to add the group + * to the switch by requesting the Group Service. Objects instantiating this + * class are meant to be temporary and live as long as it is needed to wait for + * preceding groups in the group chain to be created. + */ + private class GroupChainElem { + private TrafficTreatment bucketActions; + private Integer givenGroupId; + private GroupKey gkey; + private ApplicationId appId; + + public GroupChainElem(GroupKey gkey, Integer givenGroupId, + TrafficTreatment tr, ApplicationId appId) { + this.bucketActions = tr; + this.givenGroupId = givenGroupId; + this.gkey = gkey; + this.appId = appId; + } + + public TrafficTreatment getBucketActions() { + return bucketActions; + } + + public Integer getGivenGroupId() { + return givenGroupId; + } + + public GroupKey getGkey() { + return gkey; + } + + public ApplicationId getAppId() { + return appId; + } + + } + + ////////////////////////////////////// + // Test code to be used for future + // static-flow-pusher app + ////////////////////////////////////// + + public void processStaticFlows() { + //processPortTable(); + processGroupTable(); + processVlanTable(); + processTmacTable(); + processIpTable(); + //processMcastTable(); + //processBridgingTable(); + processAclTable(); + sendPackets(); + processMplsTable(); + } + + protected void processGroupTable() { + TrafficTreatment.Builder act = DefaultTrafficTreatment.builder(); + + act.popVlan(); // to send out untagged packets + act.setOutput(PortNumber.portNumber(24)); + GroupBucket bucket = + DefaultGroupBucket.createIndirectGroupBucket(act.build()); + final GroupKey groupkey = new DefaultGroupKey(appKryo.serialize(500)); + Integer groupId = 0x00c80018; //l2 interface, vlan 200, port 24 + GroupDescription groupDescription = new DefaultGroupDescription(deviceId, + GroupDescription.Type.INDIRECT, + new GroupBuckets(Collections.singletonList(bucket)), + groupkey, + groupId, + driverId); + groupService.addGroup(groupDescription); + + TrafficTreatment.Builder act2 = DefaultTrafficTreatment.builder(); + act2.setOutput(PortNumber.portNumber(40)); + GroupBucket bucket2 = DefaultGroupBucket.createIndirectGroupBucket(act2.build()); + final GroupKey groupkey2 = new DefaultGroupKey(appKryo.serialize(502)); + Integer groupId2 = 0x00c50028; //l2 interface, vlan 197, port 40 + GroupDescription groupDescription2 = new DefaultGroupDescription(deviceId, + GroupDescription.Type.INDIRECT, + new GroupBuckets(Collections.singletonList(bucket2)), + groupkey2, + groupId2, + driverId); + groupService.addGroup(groupDescription2); + + while (groupService.getGroup(deviceId, groupkey2) == null) { + try { + Thread.sleep(500); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + //Now for L3 Unicast group + TrafficTreatment.Builder act3 = DefaultTrafficTreatment.builder(); + act3.setEthDst(MacAddress.valueOf(0x2020)); + act3.setEthSrc(MacAddress.valueOf(0x1010)); + act3.setVlanId(VlanId.vlanId((short) 200)); + act3.group(new DefaultGroupId(0x00c80018)); // point to L2 interface + // MPLS interface group - does not work for popping single label + //Integer secGroupId = MPLSINTERFACEMASK | 38; // 0x90000026 + Integer groupId3 = L3UNICASTMASK | 1; // 0x20000001 + GroupBucket bucket3 = + DefaultGroupBucket.createIndirectGroupBucket(act3.build()); + final GroupKey groupkey3 = new DefaultGroupKey(appKryo.serialize(503)); + GroupDescription groupDescription3 = new DefaultGroupDescription(deviceId, + GroupDescription.Type.INDIRECT, + new GroupBuckets(Collections.singletonList(bucket3)), + groupkey3, + groupId3, + driverId); + groupService.addGroup(groupDescription3); + + //Another L3 Unicast group + TrafficTreatment.Builder act4 = DefaultTrafficTreatment.builder(); + act4.setEthDst(MacAddress.valueOf(0x3030)); + act4.setEthSrc(MacAddress.valueOf(0x1010)); + act4.setVlanId(VlanId.vlanId((short) 197)); + act4.group(new DefaultGroupId(0x00c50028)); // point to L2 interface + Integer groupId4 = L3UNICASTMASK | 2; // 0x20000002 + GroupBucket bucket4 = + DefaultGroupBucket.createIndirectGroupBucket(act4.build()); + final GroupKey groupkey4 = new DefaultGroupKey(appKryo.serialize(504)); + GroupDescription groupDescription4 = new DefaultGroupDescription(deviceId, + GroupDescription.Type.INDIRECT, + new GroupBuckets(Collections.singletonList(bucket4)), + groupkey4, + groupId4, + driverId); + groupService.addGroup(groupDescription4); + + while (groupService.getGroup(deviceId, groupkey4) == null) { + try { + Thread.sleep(500); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + // L3 ecmp group + TrafficTreatment.Builder act5 = DefaultTrafficTreatment.builder(); + act5.group(new DefaultGroupId(0x20000001)); + TrafficTreatment.Builder act6 = DefaultTrafficTreatment.builder(); + act6.group(new DefaultGroupId(0x20000002)); + GroupBucket buckete1 = + DefaultGroupBucket.createSelectGroupBucket(act5.build()); + GroupBucket buckete2 = + DefaultGroupBucket.createSelectGroupBucket(act6.build()); + List bktlist = new ArrayList(); + bktlist.add(buckete1); + bktlist.add(buckete2); + final GroupKey groupkey5 = new DefaultGroupKey(appKryo.serialize(505)); + Integer groupId5 = L3ECMPMASK | 5; // 0x70000005 + GroupDescription groupDescription5 = new DefaultGroupDescription(deviceId, + GroupDescription.Type.SELECT, + new GroupBuckets(bktlist), + groupkey5, + groupId5, + driverId); + groupService.addGroup(groupDescription5); + + + } + + @SuppressWarnings("deprecation") + protected void processMplsTable() { + FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + selector.matchEthType(Ethernet.MPLS_UNICAST); + selector.matchMplsLabel(MplsLabel.mplsLabel(0xff)); //255 + selector.matchMplsBos(true); + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); + treatment.decMplsTtl(); // nw_ttl does not work + treatment.copyTtlIn(); + treatment.popMpls(Ethernet.TYPE_IPV4); + treatment.deferred().group(new DefaultGroupId(0x20000001)); // point to L3 Unicast + //treatment.deferred().group(new DefaultGroupId(0x70000005)); // point to L3 ECMP + treatment.transition(ACL_TABLE); + FlowRule test = DefaultFlowRule.builder().forDevice(deviceId) + .withSelector(selector.build()).withTreatment(treatment.build()) + .withPriority(DEFAULT_PRIORITY).fromApp(driverId).makePermanent() + .forTable(24).build(); + ops = ops.add(test); + + flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { + @Override + public void onSuccess(FlowRuleOperations ops) { + log.info("Initialized mpls table"); + } + + @Override + public void onError(FlowRuleOperations ops) { + log.info("Failed to initialize mpls table"); + } + })); + + } + + protected void processPortTable() { + FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + selector.matchInPort(PortNumber.portNumber(0)); // should be maskable? + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); + treatment.transition(VLAN_TABLE); + FlowRule tmisse = DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(selector.build()) + .withTreatment(treatment.build()) + .withPriority(LOWEST_PRIORITY) + .fromApp(driverId) + .makePermanent() + .forTable(PORT_TABLE).build(); + ops = ops.add(tmisse); + + flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { + @Override + public void onSuccess(FlowRuleOperations ops) { + log.info("Initialized port table"); + } + + @Override + public void onError(FlowRuleOperations ops) { + log.info("Failed to initialize port table"); + } + })); + + } + + private void processVlanTable() { + // Table miss entry is not required as ofdpa default is to drop + // In OF terms, the absence of a t.m.e. also implies drop + FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); + selector.matchInPort(PortNumber.portNumber(12)); + selector.matchVlanId(VlanId.vlanId((short) 100)); + treatment.transition(TMAC_TABLE); + FlowRule rule = DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(selector.build()) + .withTreatment(treatment.build()) + .withPriority(DEFAULT_PRIORITY) + .fromApp(driverId) + .makePermanent() + .forTable(VLAN_TABLE).build(); + ops = ops.add(rule); + flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { + @Override + public void onSuccess(FlowRuleOperations ops) { + log.info("Initialized vlan table"); + } + + @Override + public void onError(FlowRuleOperations ops) { + log.info("Failed to initialize vlan table"); + } + })); + } + + protected void processTmacTable() { + //table miss entry + FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); + selector.matchInPort(PortNumber.portNumber(12)); + selector.matchVlanId(VlanId.vlanId((short) 100)); + selector.matchEthType(Ethernet.TYPE_IPV4); + selector.matchEthDst(MacAddress.valueOf("00:00:00:00:00:02")); + treatment.transition(UNICAST_ROUTING_TABLE); + FlowRule rule = DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(selector.build()) + .withTreatment(treatment.build()) + .withPriority(DEFAULT_PRIORITY) + .fromApp(driverId) + .makePermanent() + .forTable(TMAC_TABLE).build(); + ops = ops.add(rule); + + selector.matchEthType(Ethernet.MPLS_UNICAST); + treatment.transition(MPLS_TABLE_0); + FlowRule rulempls = DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(selector.build()) + .withTreatment(treatment.build()) + .withPriority(DEFAULT_PRIORITY) + .fromApp(driverId) + .makePermanent() + .forTable(TMAC_TABLE).build(); + ops = ops.add(rulempls); + + flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { + @Override + public void onSuccess(FlowRuleOperations ops) { + log.info("Initialized tmac table"); + } + + @Override + public void onError(FlowRuleOperations ops) { + log.info("Failed to initialize tmac table"); + } + })); + } + + protected void processIpTable() { + //table miss entry + FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); + selector.matchEthType(Ethernet.TYPE_IPV4); + selector.matchIPDst(IpPrefix.valueOf("2.0.0.0/16")); + treatment.deferred().group(new DefaultGroupId(0x20000001)); + treatment.transition(ACL_TABLE); + FlowRule rule = DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(selector.build()) + .withTreatment(treatment.build()) + .withPriority(30000) + .fromApp(driverId) + .makePermanent() + .forTable(UNICAST_ROUTING_TABLE).build(); + ops = ops.add(rule); + flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { + @Override + public void onSuccess(FlowRuleOperations ops) { + log.info("Initialized IP table"); + } + + @Override + public void onError(FlowRuleOperations ops) { + log.info("Failed to initialize unicast IP table"); + } + })); + } + + protected void processAclTable() { + //table miss entry + FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); + selector.matchEthDst(MacAddress.valueOf("00:00:00:00:00:02")); + treatment.deferred().group(new DefaultGroupId(0x20000001)); + FlowRule rule = DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(selector.build()) + .withTreatment(treatment.build()) + .withPriority(60000) + .fromApp(driverId) + .makePermanent() + .forTable(ACL_TABLE).build(); + ops = ops.add(rule); + flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { + @Override + public void onSuccess(FlowRuleOperations ops) { + log.info("Initialized Acl table"); + } + + @Override + public void onError(FlowRuleOperations ops) { + log.info("Failed to initialize Acl table"); + } + })); + } + + private void sendPackets() { + Ethernet eth = new Ethernet(); + eth.setDestinationMACAddress("00:00:00:00:00:02"); + eth.setSourceMACAddress("00:00:00:11:22:33"); + eth.setVlanID((short) 100); + eth.setEtherType(Ethernet.MPLS_UNICAST); + MPLS mplsPkt = new MPLS(); + mplsPkt.setLabel(255); + mplsPkt.setTtl((byte) 5); + + IPv4 ipv4 = new IPv4(); + + ipv4.setDestinationAddress("4.0.5.6"); + ipv4.setSourceAddress("1.0.2.3"); + ipv4.setTtl((byte) 64); + ipv4.setChecksum((short) 0); + + UDP udp = new UDP(); + udp.setDestinationPort(666); + udp.setSourcePort(333); + udp.setPayload(new Data(new byte[]{(byte) 1, (byte) 2})); + udp.setChecksum((short) 0); + + ipv4.setPayload(udp); + mplsPkt.setPayload(ipv4); + eth.setPayload(mplsPkt); + + TrafficTreatment treatment = DefaultTrafficTreatment.builder() + .setOutput(PortNumber.portNumber(24)) + .build(); + OutboundPacket packet = new DefaultOutboundPacket(deviceId, + treatment, + ByteBuffer.wrap(eth.serialize())); + + + Ethernet eth2 = new Ethernet(); + eth2.setDestinationMACAddress("00:00:00:00:00:02"); + eth2.setSourceMACAddress("00:00:00:11:22:33"); + eth2.setVlanID((short) 100); + eth2.setEtherType(Ethernet.TYPE_IPV4); + + IPv4 ipv42 = new IPv4(); + ipv42.setDestinationAddress("2.0.0.2"); + ipv42.setSourceAddress("1.0.9.9"); + ipv42.setTtl((byte) 64); + ipv42.setChecksum((short) 0); + + UDP udp2 = new UDP(); + udp2.setDestinationPort(999); + udp2.setSourcePort(333); + udp2.setPayload(new Data(new byte[]{(byte) 1, (byte) 2})); + udp2.setChecksum((short) 0); + + ipv42.setPayload(udp2); + eth2.setPayload(ipv42); + + TrafficTreatment treatment2 = DefaultTrafficTreatment.builder() + .setOutput(PortNumber.portNumber(26)) + .build(); + OutboundPacket packet2 = new DefaultOutboundPacket(deviceId, + treatment2, + ByteBuffer.wrap(eth2.serialize())); + + + log.info("Emitting packets now"); + packetService.emit(packet); + packetService.emit(packet); + packetService.emit(packet2); + packetService.emit(packet); + packetService.emit(packet); + log.info("Done emitting packets"); + } + + private class InternalPacketProcessor implements PacketProcessor { + + @Override + public void process(PacketContext context) { + + + } + } + +} diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java index c02ba3ca..31297ff4 100644 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java @@ -53,6 +53,7 @@ import org.onosproject.net.flow.criteria.MplsCriterion; import org.onosproject.net.flow.criteria.PortCriterion; import org.onosproject.net.flow.criteria.VlanIdCriterion; import org.onosproject.net.flow.instructions.Instruction; +import org.onosproject.net.flow.instructions.Instructions.OutputInstruction; import org.onosproject.net.flowobjective.FilteringObjective; import org.onosproject.net.flowobjective.FlowObjectiveStore; import org.onosproject.net.flowobjective.ForwardingObjective; @@ -246,6 +247,7 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour private void addGroup(NextObjective nextObjective) { log.debug("addGroup with type{} for nextObjective id {}", nextObjective.type(), nextObjective.id()); + List buckets; switch (nextObjective.type()) { case SIMPLE: log.debug("processing SIMPLE next objective"); @@ -273,7 +275,7 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour break; case HASHED: log.debug("processing HASHED next objective"); - List buckets = nextObjective + buckets = nextObjective .next() .stream() .map((treatment) -> DefaultGroupBucket @@ -297,8 +299,32 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour } break; case BROADCAST: + log.debug("processing BROADCAST next objective"); + buckets = nextObjective + .next() + .stream() + .map((treatment) -> DefaultGroupBucket + .createAllGroupBucket(treatment)) + .collect(Collectors.toList()); + if (!buckets.isEmpty()) { + final GroupKey key = new DefaultGroupKey( + appKryo.serialize(nextObjective + .id())); + GroupDescription groupDescription = new DefaultGroupDescription( + deviceId, + GroupDescription.Type.ALL, + new GroupBuckets(buckets), + key, + null, + nextObjective.appId()); + log.debug("Creating BROADCAST group for next objective id {}", + nextObjective.id()); + groupService.addGroup(groupDescription); + pendingGroups.put(key, nextObjective); + } + break; case FAILOVER: - log.debug("BROADCAST and FAILOVER next objectives not supported"); + log.debug("FAILOVER next objectives not supported"); fail(nextObjective, ObjectiveError.UNSUPPORTED); log.warn("Unsupported next objective type {}", nextObjective.type()); break; @@ -326,6 +352,8 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour bucket = DefaultGroupBucket.createIndirectGroupBucket(treatment); } else if (group.type() == GroupDescription.Type.SELECT) { bucket = DefaultGroupBucket.createSelectGroupBucket(treatment); + } else if (group.type() == GroupDescription.Type.ALL) { + bucket = DefaultGroupBucket.createAllGroupBucket(treatment); } else { log.warn("Unsupported Group type {}", group.type()); return; @@ -356,6 +384,8 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour bucket = DefaultGroupBucket.createIndirectGroupBucket(treatment); } else if (group.type() == GroupDescription.Type.SELECT) { bucket = DefaultGroupBucket.createSelectGroupBucket(treatment); + } else if (group.type() == GroupDescription.Type.ALL) { + bucket = DefaultGroupBucket.createAllGroupBucket(treatment); } else { log.warn("Unsupported Group type {}", group.type()); return; @@ -383,7 +413,7 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour private Collection processVersatile(ForwardingObjective fwd) { log.debug("Processing versatile forwarding objective"); TrafficSelector selector = fwd.selector(); - + TrafficTreatment treatment = null; EthTypeCriterion ethType = (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE); if (ethType == null) { @@ -410,15 +440,26 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour return Collections.emptySet(); } treatmentBuilder.deferred().group(group.id()); + treatment = treatmentBuilder.build(); log.debug("Adding OUTGROUP action"); } + } else if (fwd.treatment() != null) { + if (fwd.treatment().allInstructions().size() == 1 && + fwd.treatment().allInstructions().get(0).type() == Instruction.Type.OUTPUT) { + OutputInstruction o = (OutputInstruction) fwd.treatment().allInstructions().get(0); + if (o.port() == PortNumber.CONTROLLER) { + log.warn("Punts to the controller are handled by misses in" + + " the TMAC, IP and MPLS tables."); + return Collections.emptySet(); + } + } + treatment = fwd.treatment(); } else { - log.warn("VERSATILE forwarding objective need next objective ID."); + log.warn("VERSATILE forwarding objective needs next objective ID " + + "or treatment."); return Collections.emptySet(); } - TrafficTreatment treatment = treatmentBuilder.build(); - FlowRule.Builder ruleBuilder = DefaultFlowRule.builder() .fromApp(fwd.appId()).withPriority(fwd.priority()) .forDevice(deviceId).withSelector(fwd.selector()) @@ -527,7 +568,7 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour protected List processEthDstFilter(Criterion c, FilteringObjective filt, ApplicationId applicationId) { - List rules = new ArrayList(); + List rules = new ArrayList<>(); EthCriterion e = (EthCriterion) c; TrafficSelector.Builder selectorIp = DefaultTrafficSelector .builder(); @@ -565,7 +606,7 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour protected List processVlanIdFilter(Criterion c, FilteringObjective filt, ApplicationId applicationId) { - List rules = new ArrayList(); + List rules = new ArrayList<>(); VlanIdCriterion v = (VlanIdCriterion) c; log.debug("adding rule for VLAN: {}", v.vlanId()); TrafficSelector.Builder selector = DefaultTrafficSelector @@ -616,21 +657,8 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour ops = install ? ops.add(rule) : ops.remove(rule); } } else if (c.type() == Criterion.Type.IPV4_DST) { - IPCriterion ip = (IPCriterion) c; - log.debug("adding rule for IP: {}", ip.ip()); - TrafficSelector.Builder selector = DefaultTrafficSelector - .builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment - .builder(); - selector.matchEthType(Ethernet.TYPE_IPV4); - selector.matchIPDst(ip.ip()); - treatment.transition(aclTableId); - FlowRule rule = DefaultFlowRule.builder().forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(filt.priority()).fromApp(applicationId) - .makePermanent().forTable(ipv4UnicastTableId).build(); - ops = install ? ops.add(rule) : ops.remove(rule); + log.debug("driver does not process IP filtering rules as it " + + "sends all misses in the IP table to the controller"); } else { log.warn("Driver does not currently process filtering condition" + " of type: {}", c.type()); @@ -762,6 +790,7 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour this.key = key; } + @SuppressWarnings("unused") public GroupKey key() { return key; } 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 5059d4bf..af498832 100644 --- a/framework/src/onos/drivers/src/main/resources/onos-drivers.xml +++ b/framework/src/onos/drivers/src/main/resources/onos-drivers.xml @@ -32,12 +32,19 @@ impl="org.onosproject.driver.handshaker.NiciraSwitchHandshaker"/> + + + @@ -66,7 +73,7 @@ + impl="org.onosproject.driver.pipeline.OFDPA2Pipeline"/> @@ -109,7 +116,7 @@ manufacturer="ONF" hwVersion="OF1.3 Software Switch from CPqD" swVersion="for Group Chaining"> + impl="org.onosproject.driver.pipeline.CpqdOFDPA2Pipeline"/> mvn:org.onosproject/onos-core-net/@ONOS-VERSION mvn:org.onosproject/onos-core-common/@ONOS-VERSION mvn:org.onosproject/onos-core-dist/@ONOS-VERSION + mvn:org.onosproject/onos-core-persistence/@ONOS-VERSION mvn:org.onosproject/onos-core-serializers/@ONOS-VERSION mvn:org.onosproject/onlab-netty/@ONOS-VERSION diff --git a/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/intf/package-info.java b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/intf/package-info.java new file mode 100644 index 00000000..6cea24d1 --- /dev/null +++ b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/intf/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. + */ + +/** + * Interface Service. + */ +package org.onosproject.incubator.net.intf; diff --git a/framework/src/onos/netconf/api/src/main/java/org/onosproject/netconf/package-info.java b/framework/src/onos/netconf/api/src/main/java/org/onosproject/netconf/package-info.java new file mode 100644 index 00000000..5562bd33 --- /dev/null +++ b/framework/src/onos/netconf/api/src/main/java/org/onosproject/netconf/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. + */ + +/** + * Created by ray on 10/30/15. + */ +package org.onosproject.netconf; diff --git a/framework/src/onos/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/package-info.java b/framework/src/onos/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/package-info.java new file mode 100644 index 00000000..84992bf2 --- /dev/null +++ b/framework/src/onos/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/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. + */ + +/** + * Created by ray on 10/30/15. + */ +package org.onosproject.netconf.ctl; diff --git a/framework/src/onos/netconf/rfc/src/main/java/org/onosproject/netconf/rfc/package-info.java b/framework/src/onos/netconf/rfc/src/main/java/org/onosproject/netconf/rfc/package-info.java new file mode 100644 index 00000000..616a7ce5 --- /dev/null +++ b/framework/src/onos/netconf/rfc/src/main/java/org/onosproject/netconf/rfc/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. + */ + +/** + * Created by ray on 10/30/15. + */ +package org.onosproject.netconf.rfc; diff --git a/framework/src/onos/openflow/api/src/main/java/org/onosproject/openflow/controller/ExtensionInterpreter.java b/framework/src/onos/openflow/api/src/main/java/org/onosproject/openflow/controller/ExtensionInterpreter.java new file mode 100644 index 00000000..44b121ac --- /dev/null +++ b/framework/src/onos/openflow/api/src/main/java/org/onosproject/openflow/controller/ExtensionInterpreter.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.openflow.controller; + +import com.google.common.annotations.Beta; +import org.onosproject.net.driver.HandlerBehaviour; +import org.onosproject.net.flow.instructions.ExtensionInstruction; +import org.onosproject.net.flow.instructions.ExtensionType; +import org.projectfloodlight.openflow.protocol.OFFactory; +import org.projectfloodlight.openflow.protocol.action.OFAction; + +/** + * Interprets extension instructions and converts them to/from OpenFlow objects. + */ +@Beta +public interface ExtensionInterpreter extends HandlerBehaviour { + + /** + * Returns true if the given extension instruction is supported by this + * driver. + * + * @param extensionType extension instruction type + * @return true if the instruction is supported, otherwise false + */ + boolean supported(ExtensionType extensionType); + + /** + * Maps an extension instruction to an OpenFlow action. + * + * @param factory OpenFlow factory + * @param extensionInstruction extension instruction + * @return OpenFlow action + */ + OFAction mapInstruction(OFFactory factory, ExtensionInstruction extensionInstruction); + + /** + * Maps an OpenFlow action to an extension instruction. + * + * @param action OpenFlow action + * @return extension instruction + */ + ExtensionInstruction mapAction(OFAction action); + +} diff --git a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/EventSubject.java b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/EventSubject.java index 6a067244..d8aaef65 100644 --- a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/EventSubject.java +++ b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/EventSubject.java @@ -16,8 +16,7 @@ package org.onosproject.ovsdb.controller; /** - * Represents for a entity that carry important information for listener. + * Representation for an entity that carries important information for a listener. */ public interface EventSubject { - } diff --git a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbBridge.java b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbBridge.java index 1ee0a367..18c59e14 100644 --- a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbBridge.java +++ b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbBridge.java @@ -21,7 +21,8 @@ import static com.google.common.base.Preconditions.checkNotNull; import java.util.Objects; /** - * The class representing a ovsdb bridge. This class is immutable. + * The class representing an ovsdb bridge. + * This class is immutable. */ public final class OvsdbBridge { @@ -29,7 +30,7 @@ public final class OvsdbBridge { private final OvsdbDatapathId datapathId; /** - * Constructor from a OvsdbBridgeName bridgeName and a OvsdbDatapathId + * Constructor from an OvsdbBridgeName bridgeName and an OvsdbDatapathId * datapathId. * * @param bridgeName the bridgeName to use @@ -43,16 +44,16 @@ public final class OvsdbBridge { } /** - * Gets the bridge name of the bridge. + * Gets the bridge name of bridge. * - * @return the bridge name of the bridge + * @return the bridge name of bridge */ public OvsdbBridgeName bridgeName() { return bridgeName; } /** - * Gets the datapathId of the bridge. + * Gets the datapathId of bridge. * * @return datapathId the datapathId to use */ diff --git a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbBridgeName.java b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbBridgeName.java index daedff5f..899799fa 100644 --- a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbBridgeName.java +++ b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbBridgeName.java @@ -21,14 +21,15 @@ import static com.google.common.base.Preconditions.checkNotNull; import java.util.Objects; /** - * The class representing a bridge name. This class is immutable. + * The class representing a bridge name. + * This class is immutable. */ public final class OvsdbBridgeName { private final String value; /** - * Constructor from a String bridge name. + * Constructor from a String. * * @param value the bridge name to use */ @@ -38,7 +39,7 @@ public final class OvsdbBridgeName { } /** - * Gets the value of the bridge name. + * Gets the value of bridge name. * * @return the value of the bridge name */ 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 e619f8e0..edd25ac6 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 @@ -43,7 +43,7 @@ public interface OvsdbClientService extends OvsdbRPC { OvsdbNodeId nodeId(); /** - * Creates the configuration for the tunnel. + * Creates the configuration for tunnel. * * @param srcIp source IP address * @param dstIp destination IP address @@ -62,7 +62,7 @@ public interface OvsdbClientService extends OvsdbRPC { boolean createTunnel(String bridgeName, String portName, String tunnelType, Map options); /** - * Drops the configuration for the tunnel. + * Drops the configuration for tunnel. * * @param srcIp source IP address * @param dstIp destination IP address @@ -70,7 +70,7 @@ public interface OvsdbClientService extends OvsdbRPC { void dropTunnel(IpAddress srcIp, IpAddress dstIp); /** - * Gets tunnels of the node. + * Gets tunnels of node. * * @return set of tunnels; empty if no tunnel is find */ @@ -102,14 +102,14 @@ public interface OvsdbClientService extends OvsdbRPC { void dropBridge(String bridgeName); /** - * Gets bridges of the node. + * Gets bridges of node. * * @return set of bridges; empty if no bridge is find */ Set getBridges(); /** - * Gets controllers of the node. + * Gets controllers of node. * * @param openflowDeviceId target device id * @return set of controllers; empty if no controller is find @@ -155,7 +155,7 @@ public interface OvsdbClientService extends OvsdbRPC { void dropPort(String bridgeName, String portName); /** - * Gets ports of the bridge. + * Gets ports of bridge. * * @return set of ports; empty if no ports is find */ @@ -247,7 +247,7 @@ public interface OvsdbClientService extends OvsdbRPC { DatabaseSchema getDatabaseSchema(String dbName); /** - * Gets the ovsdb row from the local ovsdb store. + * Gets the ovsdb row from local ovsdb store. * * @param dbName database name * @param tableName table name @@ -257,7 +257,7 @@ public interface OvsdbClientService extends OvsdbRPC { Row getRow(String dbName, String tableName, String uuid); /** - * Removes the ovsdb row from the local ovsdb store. + * Removes the ovsdb row from local ovsdb store. * * @param dbName database name * @param tableName table name 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 24bfeae9..f22a5787 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 @@ -21,7 +21,7 @@ import org.onlab.packet.TpPort; import java.util.List; /** - * Abstraction of an ovsdb controller. Serves as a one stop shop for obtaining + * Abstraction of an ovsdb controller. Serves as an one stop shop for obtaining * OvsdbNode and (un)register listeners on ovsdb events and ovsdb node events. */ public interface OvsdbController { @@ -62,7 +62,7 @@ public interface OvsdbController { List getNodeIds(); /** - * Gets a ovsdb client by node identifier. + * Gets an ovsdb client by node identifier. * * @param nodeId node identifier * @return OvsdbClient ovsdb node information diff --git a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbDatapathId.java b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbDatapathId.java index 1a2d8366..8ccf45f2 100644 --- a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbDatapathId.java +++ b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbDatapathId.java @@ -20,13 +20,14 @@ import static com.google.common.base.Preconditions.checkNotNull; import java.util.Objects; /** - * The class representing a datapathid. This class is immutable. + * The class representing a datapathid. + * This class is immutable. */ public final class OvsdbDatapathId { private final String value; /** - * Constructor from a String datapathid. + * Constructor from a String. * * @param value the datapathid to use */ @@ -36,9 +37,9 @@ public final class OvsdbDatapathId { } /** - * Gets the value of the datapathid. + * Gets the value of datapathid. * - * @return the value of the datapathid + * @return the value of datapathid */ public String value() { return value; diff --git a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbEventSubject.java b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbEventSubject.java index 263027f2..226a26e6 100644 --- a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbEventSubject.java +++ b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbEventSubject.java @@ -21,7 +21,7 @@ import org.onlab.packet.IpAddress; import org.onlab.packet.MacAddress; /** - * Represents for a entity that carry important information for listener. + * Represents for an entity that carry important information for listener. */ public interface OvsdbEventSubject extends EventSubject { /** diff --git a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbIfaceId.java b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbIfaceId.java index b0535d21..10ba80bc 100644 --- a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbIfaceId.java +++ b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbIfaceId.java @@ -20,13 +20,14 @@ import static com.google.common.base.Preconditions.checkNotNull; import java.util.Objects; /** - * The class representing a ifaceid. This class is immutable. + * The class representing an ifaceid. + * This class is immutable. */ public class OvsdbIfaceId { private final String value; /** - * Constructor from a String ifaceid. + * Constructor from a String. * * @param value the ifaceid to use */ @@ -36,9 +37,9 @@ public class OvsdbIfaceId { } /** - * Gets the value of the ifaceid. + * Gets the value of ifaceid. * - * @return the value of the ifaceid + * @return the value of ifaceid */ public String value() { return value; diff --git a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbNodeId.java b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbNodeId.java index 2c1a440b..f3bba4b8 100644 --- a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbNodeId.java +++ b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbNodeId.java @@ -39,7 +39,7 @@ public final class OvsdbNodeId { public OvsdbNodeId(IpAddress ipAddress, long port) { checkNotNull(ipAddress, "ipAddress is not null"); this.ipAddress = ipAddress.toString(); - this.nodeId = ipAddress + ":" + port; + this.nodeId = ipAddress.toString(); } @Override diff --git a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbPort.java b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbPort.java index 3c04f6a5..deea42d7 100644 --- a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbPort.java +++ b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbPort.java @@ -29,7 +29,7 @@ public final class OvsdbPort { private final OvsdbPortName portName; /** - * Constructor from a OvsdbPortNumber portNumber, OvsdbPortName portName. + * Constructor from OvsdbPortNumber portNumber, OvsdbPortName portName. * * @param portNumber the portNumber to use * @param portName the portName to use @@ -42,18 +42,18 @@ public final class OvsdbPort { } /** - * Gets the port number of the port. + * Gets the port number of port. * - * @return the port number of the port + * @return the port number of port */ public OvsdbPortNumber portNumber() { return portNumber; } /** - * Gets the port name of the port. + * Gets the port name of port. * - * @return the port name of the port + * @return the port name of port */ public OvsdbPortName portName() { return portName; diff --git a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbPortName.java b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbPortName.java index aa0f55b0..d9c7c2da 100644 --- a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbPortName.java +++ b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbPortName.java @@ -21,14 +21,15 @@ import static com.google.common.base.Preconditions.checkNotNull; import java.util.Objects; /** - * The class representing a port number. This class is immutable. + * The class representing a port number. + * This class is immutable. */ public final class OvsdbPortName { private final String value; /** - * Constructor from a String port name. + * Constructor from a String. * * @param value the port name to use */ @@ -38,9 +39,9 @@ public final class OvsdbPortName { } /** - * Gets the value of the port name. + * Gets the value of port name. * - * @return the value of the port name + * @return the value of port name */ public String value() { return value; diff --git a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbPortNumber.java b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbPortNumber.java index 9c57b5df..bd094d04 100644 --- a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbPortNumber.java +++ b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbPortNumber.java @@ -20,14 +20,15 @@ import static com.google.common.base.MoreObjects.toStringHelper; import java.util.Objects; /** - * The class representing a port number. This class is immutable. + * The class representing a port number. + * This class is immutable. */ public final class OvsdbPortNumber { private final long value; /** - * Constructor from a long port number. + * Constructor from a long value. * * @param value the port number to use */ @@ -36,9 +37,9 @@ public final class OvsdbPortNumber { } /** - * Gets the value of the port number. + * Gets the value of port number. * - * @return the value of the port number + * @return the value of port number */ public long value() { return value; diff --git a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbTableStore.java b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbTableStore.java index 1d9146eb..72b64f32 100644 --- a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbTableStore.java +++ b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbTableStore.java @@ -29,18 +29,18 @@ public class OvsdbTableStore { /** * Gets the ovsdbRowStore. * - * @param tableName a ovsdb table name - * @return OvsdbRowStore the data of the table + * @param tableName an ovsdb table name + * @return OvsdbRowStore the data of table */ public OvsdbRowStore getRows(String tableName) { return tableStore.get(tableName); } /** - * Create or update a value to tableStore. + * Creates or updates a value to tableStore. * - * @param tableName key of the tableName - * @param rowStore a row of the table + * @param tableName key of tableName + * @param rowStore a row of table */ public void createOrUpdateTable(String tableName, OvsdbRowStore rowStore) { tableStore.put(tableName, rowStore); @@ -49,14 +49,14 @@ public class OvsdbTableStore { /** * Drops a value to table data. * - * @param tableName key of the tableName + * @param tableName key of tableName */ public void dropTable(String tableName) { tableStore.remove(tableName); } /** - * Gets the tableStore. + * Gets tableStore. * * @return tableStore */ diff --git a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbTunnel.java b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbTunnel.java index e1c5c7fd..8c857da4 100644 --- a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbTunnel.java +++ b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbTunnel.java @@ -23,7 +23,8 @@ import java.util.Objects; import org.onlab.packet.IpAddress; /** - * The class representing a ovsdb tunnel. This class is immutable. + * The class representing an ovsdb tunnel. + * This class is immutable. */ public final class OvsdbTunnel { @@ -38,7 +39,7 @@ public final class OvsdbTunnel { private final OvsdbTunnelName tunnelName; /** - * Constructor from a IpAddress localIp, IpAddress remoteIp Type tunnelType, + * Constructor from an IpAddress localIp, IpAddress remoteIp Type tunnelType, * OvsdbTunnelName tunnelName. * * @param localIp the localIp to use @@ -58,36 +59,36 @@ public final class OvsdbTunnel { } /** - * Gets the local IP of the tunnel. + * Gets the local IP of tunnel. * - * @return the local IP of the tunnel + * @return the local IP of tunnel */ public IpAddress localIp() { return localIp; } /** - * Gets the remote IP of the tunnel. + * Gets the remote IP of tunnel. * - * @return the remote IP of the tunnel + * @return the remote IP of tunnel */ public IpAddress remoteIp() { return remoteIp; } /** - * Gets the tunnel type of the tunnel. + * Gets the tunnel type of tunnel. * - * @return the tunnel type of the tunnel + * @return the tunnel type of tunnel */ public Type tunnelType() { return tunnelType; } /** - * Gets the tunnel name of the tunnel. + * Gets the tunnel name of tunnel. * - * @return the tunnel name of the tunnel + * @return the tunnel name of tunnel */ public OvsdbTunnelName tunnelName() { return tunnelName; diff --git a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbTunnelName.java b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbTunnelName.java index 116f6217..80befab3 100644 --- a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbTunnelName.java +++ b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbTunnelName.java @@ -21,13 +21,14 @@ import static com.google.common.base.Preconditions.checkNotNull; import java.util.Objects; /** - * The class representing a tunnel name. This class is immutable. + * The class representing a tunnel name. + * This class is immutable. */ public final class OvsdbTunnelName { private final String value; /** - * Constructor from a String tunnel name. + * Constructor from a String. * * @param value the tunnel name to use */ @@ -37,9 +38,9 @@ public final class OvsdbTunnelName { } /** - * Gets the value of the tunnel name. + * Gets the value of tunnel name. * - * @return the value of the tunnel name + * @return the value of tunnel name */ public String value() { return value; diff --git a/framework/src/onos/pom.xml b/framework/src/onos/pom.xml index b9fdfe22..4686e3f3 100644 --- a/framework/src/onos/pom.xml +++ b/framework/src/onos/pom.xml @@ -58,6 +58,7 @@ tools/package/archetypes tools/package/branding + tools/build/conf bgp @@ -79,7 +80,7 @@ UTF-8 - 1.0 + 1.1-SNAPSHOT 4.0.23.Final 0.5.0.onos 0.9.0.onos 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 a840f856..98442033 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 @@ -27,6 +27,7 @@ import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.ReferenceCardinality; import org.onlab.packet.Ethernet; import org.onosproject.cfg.ComponentConfigService; +import org.onosproject.cluster.ClusterService; import org.onosproject.core.ApplicationId; import org.onosproject.core.CoreService; import org.onosproject.mastership.MastershipEvent; @@ -37,6 +38,7 @@ import org.onosproject.net.Device; import org.onosproject.net.DeviceId; import org.onosproject.net.LinkKey; import org.onosproject.net.Port; +import org.onosproject.net.config.NetworkConfigRegistry; import org.onosproject.net.device.DeviceEvent; import org.onosproject.net.device.DeviceListener; import org.onosproject.net.device.DeviceService; @@ -60,6 +62,7 @@ import java.io.IOException; import java.util.Dictionary; import java.util.EnumSet; import java.util.Map; +import java.util.Optional; import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ScheduledExecutorService; @@ -86,6 +89,10 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { "Settings: enabled={}, useBDDP={}, probeRate={}, " + "staleLinkAge={}, lldpSuppression={}"; + // When a Device/Port has this annotation, do not send out LLDP/BDDP + public static final String NO_LLDP = "no-lldp"; + + private final Logger log = getLogger(getClass()); @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) @@ -109,6 +116,12 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected ComponentConfigService cfgService; + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ClusterService clusterService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected NetworkConfigRegistry cfgRegistry; + private LinkProviderService providerService; private ScheduledExecutorService executor; @@ -207,7 +220,7 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { newLldpSuppression = isNullOrEmpty(s) ? DEFAULT_LLDP_SUPPRESSION_CONFIG : s; } catch (NumberFormatException e) { - log.warn(e.getMessage()); + log.warn("Component configuration had invalid values", e); newEnabled = enabled; newUseBddp = useBDDP; newProbeRate = probeRate; @@ -227,6 +240,14 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { enable(); } else if (wasEnabled && !enabled) { disable(); + } else { + // reflect changes in suppression rules to discovery helpers + // FIXME: After migrating to Network Configuration Subsystem, + // it should be possible to update only changed subset + if (enabled) { + // update all discovery helper state + loadDevices(); + } } log.info(FORMAT, enabled, useBDDP, probeRate, staleLinkAge, lldpSuppression); @@ -277,31 +298,96 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { * Loads available devices and registers their ports to be probed. */ private void loadDevices() { - for (Device device : deviceService.getAvailableDevices()) { - if (rules.isSuppressed(device)) { - log.debug("LinkDiscovery from {} disabled by configuration", device.id()); - continue; - } - LinkDiscovery ld = new LinkDiscovery(device, context); - discoverers.put(device.id(), ld); - addPorts(ld, device.id()); + deviceService.getAvailableDevices() + .forEach(d -> updateDevice(d) + .ifPresent(ld -> updatePorts(ld, d.id()))); + } + + /** + * Updates discovery helper for specified device. + * + * Adds and starts a discovery helper for specified device if enabled, + * calls {@link #removeDevice(DeviceId)} otherwise. + * + * @param device device to add + * @return discovery helper if discovery is enabled for the device + */ + private Optional updateDevice(Device device) { + if (rules.isSuppressed(device)) { + log.trace("LinkDiscovery from {} disabled by configuration", device.id()); + removeDevice(device.id()); + return Optional.empty(); + } + LinkDiscovery ld = discoverers.computeIfAbsent(device.id(), + did -> new LinkDiscovery(device, context)); + if (ld.isStopped()) { + ld.start(); } + return Optional.of(ld); } /** - * Adds ports of the specified device to the specified discovery helper. + * Removes after stopping discovery helper for specified device. + * @param deviceId device to remove */ - private void addPorts(LinkDiscovery discoverer, DeviceId deviceId) { - for (Port p : deviceService.getPorts(deviceId)) { - if (rules.isSuppressed(p)) { - continue; - } - if (!p.number().isLogical()) { - discoverer.addPort(p); - } + private void removeDevice(final DeviceId deviceId) { + discoverers.computeIfPresent(deviceId, (did, ld) -> { + ld.stop(); + providerService.linksVanished(deviceId); + return null; + }); + + } + + /** + * Updates ports of the specified device to the specified discovery helper. + */ + private void updatePorts(LinkDiscovery discoverer, DeviceId deviceId) { + deviceService.getPorts(deviceId).forEach(p -> updatePort(discoverer, p)); + } + + /** + * Updates discovery helper state of the specified port. + * + * Adds a port to the discovery helper if up and discovery is enabled, + * or calls {@link #removePort(Port)} otherwise. + */ + private void updatePort(LinkDiscovery discoverer, Port port) { + if (rules.isSuppressed(port)) { + log.trace("LinkDiscovery from {} disabled by configuration", port); + removePort(port); + return; + } + + // check if enabled and turn off discovery? + if (!port.isEnabled()) { + removePort(port); + return; + } + + if (!port.number().isLogical()) { + discoverer.addPort(port); } } + /** + * Removes a port from the specified discovery helper. + * @param port the port + */ + private void removePort(Port port) { + if (port.element() instanceof Device) { + Device d = (Device) port.element(); + LinkDiscovery ld = discoverers.get(d.id()); + if (ld != null) { + ld.removePort(port.number()); + } + + ConnectPoint point = new ConnectPoint(d.id(), port.number()); + providerService.linksVanished(point); + } else { + log.warn("Attempted to remove non-Device port", port); + } + } /** * Loads LLDP suppression rules. @@ -317,7 +403,7 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { // default rule to suppress ROADM to maintain compatibility rules = new SuppressionRules(ImmutableSet.of(), EnumSet.of(Device.Type.ROADM), - ImmutableMap.of()); + ImmutableMap.of(NO_LLDP, SuppressionRules.ANY_VALUE)); } // should refresh discoverers when we need dynamic reconfiguration @@ -367,10 +453,9 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { log.debug("Device {} doesn't exist, or isn't there yet", deviceId); return; } - if (rules.isSuppressed(device)) { - return; + if (clusterService.getLocalNode().id().equals(event.roleInfo().master())) { + updateDevice(device).ifPresent(ld -> updatePorts(ld, device.id())); } - discoverers.computeIfAbsent(deviceId, k -> new LinkDiscovery(device, context)); } } @@ -381,7 +466,6 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { private class InternalDeviceListener implements DeviceListener { @Override public void event(DeviceEvent event) { - LinkDiscovery ld; Device device = event.subject(); Port port = event.port(); if (device == null) { @@ -393,73 +477,33 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { switch (event.type()) { case DEVICE_ADDED: case DEVICE_UPDATED: - synchronized (discoverers) { - ld = discoverers.get(deviceId); - if (ld == null) { - if (rules != null && rules.isSuppressed(device)) { - log.debug("LinkDiscovery from {} disabled by configuration", device.id()); - return; - } - log.debug("Device added ({}) {}", event.type(), deviceId); - discoverers.put(deviceId, new LinkDiscovery(device, context)); - } else { - if (ld.isStopped()) { - log.debug("Device restarted ({}) {}", event.type(), deviceId); - ld.start(); - } - } - } + updateDevice(device).ifPresent(ld -> updatePorts(ld, deviceId)); break; case PORT_ADDED: case PORT_UPDATED: if (port.isEnabled()) { - ld = discoverers.get(deviceId); - if (ld == null) { - return; - } - if (rules.isSuppressed(port)) { - log.debug("LinkDiscovery from {}@{} disabled by configuration", - port.number(), device.id()); - return; - } - if (!port.number().isLogical()) { - log.debug("Port added {}", port); - ld.addPort(port); - } + updateDevice(device).ifPresent(ld -> updatePort(ld, port)); } else { log.debug("Port down {}", port); - ConnectPoint point = new ConnectPoint(deviceId, port.number()); - providerService.linksVanished(point); + removePort(port); } break; case PORT_REMOVED: log.debug("Port removed {}", port); - ConnectPoint point = new ConnectPoint(deviceId, port.number()); - providerService.linksVanished(point); - + removePort(port); break; case DEVICE_REMOVED: case DEVICE_SUSPENDED: log.debug("Device removed {}", deviceId); - ld = discoverers.get(deviceId); - if (ld == null) { - return; - } - ld.stop(); - providerService.linksVanished(deviceId); + removeDevice(deviceId); break; case DEVICE_AVAILABILITY_CHANGED: - ld = discoverers.get(deviceId); - if (ld == null) { - return; - } if (deviceService.isAvailable(deviceId)) { log.debug("Device up {}", deviceId); - ld.start(); + updateDevice(device); } else { - providerService.linksVanished(deviceId); log.debug("Device down {}", deviceId); - ld.stop(); + removeDevice(deviceId); } break; case PORT_STATS_UPDATED: @@ -508,17 +552,7 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { } // check what deviceService sees, to see if we are missing anything try { - for (Device dev : deviceService.getDevices()) { - if (rules.isSuppressed(dev)) { - continue; - } - DeviceId did = dev.id(); - synchronized (discoverers) { - LinkDiscovery ld = discoverers - .computeIfAbsent(did, k -> new LinkDiscovery(dev, context)); - addPorts(ld, did); - } - } + loadDevices(); } catch (Exception e) { // Catch all exceptions to avoid task being suppressed log.error("Exception thrown during synchronization process", e); diff --git a/framework/src/onos/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LinkDiscovery.java b/framework/src/onos/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LinkDiscovery.java index 8cdfd50f..7dc9aed0 100644 --- a/framework/src/onos/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LinkDiscovery.java +++ b/framework/src/onos/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LinkDiscovery.java @@ -61,7 +61,7 @@ class LinkDiscovery implements TimerTask { private final ONOSLLDP lldpPacket; private final Ethernet ethPacket; - private Ethernet bddpEth; + private final Ethernet bddpEth; private Timeout timeout; private volatile boolean isStopped; @@ -126,7 +126,7 @@ class LinkDiscovery implements TimerTask { } /** - * Add physical port port to discovery process. + * Add physical port to discovery process. * Send out initial LLDP and label it as slow port. * * @param port the port @@ -140,6 +140,14 @@ class LinkDiscovery implements TimerTask { } } + /** + * removed physical port from discovery process. + * @param port the port number + */ + void removePort(PortNumber port) { + ports.remove(port.toLong()); + } + /** * Handles an incoming LLDP packet. Creates link in topology and adds the * link for staleness tracking. diff --git a/framework/src/onos/providers/lldp/src/test/java/org/onosproject/provider/lldp/impl/LLDPLinkProviderTest.java b/framework/src/onos/providers/lldp/src/test/java/org/onosproject/provider/lldp/impl/LLDPLinkProviderTest.java index b4b7b7b6..6070b857 100644 --- a/framework/src/onos/providers/lldp/src/test/java/org/onosproject/provider/lldp/impl/LLDPLinkProviderTest.java +++ b/framework/src/onos/providers/lldp/src/test/java/org/onosproject/provider/lldp/impl/LLDPLinkProviderTest.java @@ -16,6 +16,7 @@ package org.onosproject.provider.lldp.impl; import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import org.junit.After; @@ -32,7 +33,9 @@ import org.onosproject.core.CoreService; import org.onosproject.core.DefaultApplicationId; import org.onosproject.mastership.MastershipListener; import org.onosproject.mastership.MastershipService; +import org.onosproject.net.Annotations; import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DefaultAnnotations; import org.onosproject.net.DefaultDevice; import org.onosproject.net.DefaultPort; import org.onosproject.net.Device; @@ -73,6 +76,7 @@ public class LLDPLinkProviderTest { private static final DeviceId DID1 = DeviceId.deviceId("of:0000000000000001"); private static final DeviceId DID2 = DeviceId.deviceId("of:0000000000000002"); + private static final DeviceId DID3 = DeviceId.deviceId("of:0000000000000003"); private static Port pd1; private static Port pd2; @@ -133,10 +137,35 @@ public class LLDPLinkProviderTest { deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID1)); deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_REMOVED, DID1)); - assertTrue("Discoverer is not gone", provider.discoverers.get(DID1).isStopped()); + final LinkDiscovery linkDiscovery = provider.discoverers.get(DID1); + if (linkDiscovery != null) { + // If LinkDiscovery helper is there after DEVICE_REMOVED, + // it should be stopped + assertTrue("Discoverer is not stopped", linkDiscovery.isStopped()); + } assertTrue("Device is not gone.", vanishedDpid(DID1)); } + /** + * Checks that links on a reconfigured switch are properly removed. + */ + @Test + public void switchSuppressed() { + // add device to stub DeviceService + deviceService.putDevice(device(DID3)); + deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID3)); + + assertFalse("Device not added", provider.discoverers.isEmpty()); + + // update device in stub DeviceService with suppression config + deviceService.putDevice(device(DID3, DefaultAnnotations.builder() + .set(LLDPLinkProvider.NO_LLDP, "true") + .build())); + deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_UPDATED, DID3)); + + assertTrue("Links on suppressed Device was expected to vanish.", vanishedDpid(DID3)); + } + @Test public void portUp() { deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID1)); @@ -152,27 +181,101 @@ public class LLDPLinkProviderTest { deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID1)); deviceListener.event(portEvent(DeviceEvent.Type.PORT_ADDED, DID1, port(DID1, 1, false))); - - assertFalse("Port added to discoverer", provider.discoverers.get(DID1).containsPort(1L)); assertTrue("Port is not gone.", vanishedPort(1L)); } + @Test + public void portRemoved() { + deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID1)); + deviceListener.event(portEvent(DeviceEvent.Type.PORT_ADDED, DID1, port(DID1, 3, true))); + deviceListener.event(portEvent(DeviceEvent.Type.PORT_REMOVED, DID1, port(DID1, 3, true))); + + assertTrue("Port is not gone.", vanishedPort(3L)); + assertFalse("Port was not removed from discoverer", + provider.discoverers.get(DID1).containsPort(3L)); + } + + /** + * Checks that discovery on reconfigured switch are properly restarted. + */ + @Test + public void portSuppressedByDeviceConfig() { + + /// When Device is configured with suppression:ON, Port also is same + + // add device in stub DeviceService with suppression configured + deviceService.putDevice(device(DID3, DefaultAnnotations.builder() + .set(LLDPLinkProvider.NO_LLDP, "true") + .build())); + deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID3)); + + // non-suppressed port added to suppressed device + final long portno3 = 3L; + deviceService.putPorts(DID3, port(DID3, portno3, true)); + deviceListener.event(portEvent(DeviceEvent.Type.PORT_ADDED, DID3, port(DID3, portno3, true))); + + // discovery on device is expected to be stopped + LinkDiscovery linkDiscovery = provider.discoverers.get(DID3); + if (linkDiscovery != null) { + assertTrue("Discovery expected to be stopped", linkDiscovery.isStopped()); + } + + /// When Device is reconfigured without suppression:OFF, + /// Port should be included for discovery + + // update device in stub DeviceService without suppression configured + deviceService.putDevice(device(DID3)); + // update the Port in stub DeviceService. (Port has reference to Device) + deviceService.putPorts(DID3, port(DID3, portno3, true)); + deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_UPDATED, DID3)); + + // discovery should come back on + assertFalse("Discoverer is expected to start", provider.discoverers.get(DID3).isStopped()); + assertTrue("Discoverer should contain the port there", provider.discoverers.get(DID3).containsPort(portno3)); + } + + /** + * Checks that discovery on reconfigured port are properly restarted. + */ + @Test + public void portSuppressedByPortConfig() { + // add device in stub DeviceService without suppression configured + deviceService.putDevice(device(DID3)); + deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID3)); + + // suppressed port added to non-suppressed device + final long portno3 = 3L; + final Port port3 = port(DID3, portno3, true, + DefaultAnnotations.builder() + .set(LLDPLinkProvider.NO_LLDP, "true") + .build()); + deviceService.putPorts(DID3, port3); + deviceListener.event(portEvent(DeviceEvent.Type.PORT_ADDED, DID3, port3)); + + // discovery helper should be there turned on + assertFalse("Discoverer is expected to start", provider.discoverers.get(DID3).isStopped()); + assertFalse("Discoverer should not contain the port there", + provider.discoverers.get(DID3).containsPort(portno3)); + } + @Test public void portUnknown() { deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID1)); - deviceListener.event(portEvent(DeviceEvent.Type.PORT_ADDED, DID2, port(DID2, 1, false))); + // Note: DID3 hasn't been added to TestDeviceService, but only port is added + deviceListener.event(portEvent(DeviceEvent.Type.PORT_ADDED, DID3, port(DID3, 1, false))); assertNull("DeviceId exists", - provider.discoverers.get(DID2)); + provider.discoverers.get(DID3)); } @Test public void unknownPktCtx() { - PacketContext pktCtx = new TestPacketContext(deviceService.getDevice(DID2)); + // Note: DID3 hasn't been added to TestDeviceService + PacketContext pktCtx = new TestPacketContext(device(DID3)); testProcessor.process(pktCtx); assertFalse("Context should still be free", pktCtx.isHandled()); @@ -206,6 +309,16 @@ public class LLDPLinkProviderTest { } + private DefaultDevice device(DeviceId did) { + return new DefaultDevice(ProviderId.NONE, did, Device.Type.SWITCH, + "TESTMF", "TESTHW", "TESTSW", "TESTSN", new ChassisId()); + } + + private DefaultDevice device(DeviceId did, Annotations annotations) { + return new DefaultDevice(ProviderId.NONE, did, Device.Type.SWITCH, + "TESTMF", "TESTHW", "TESTSW", "TESTSN", new ChassisId(), annotations); + } + @SuppressWarnings(value = { "unused" }) private DeviceEvent portEvent(DeviceEvent.Type type, DeviceId did, PortNumber port) { return new DeviceEvent(type, deviceService.getDevice(did), @@ -221,6 +334,10 @@ public class LLDPLinkProviderTest { PortNumber.portNumber(port), enabled); } + private Port port(DeviceId did, long port, boolean enabled, Annotations annotations) { + return new DefaultPort(deviceService.getDevice(did), + PortNumber.portNumber(port), enabled, annotations); + } private boolean vanishedDpid(DeviceId... dids) { for (int i = 0; i < dids.length; i++) { @@ -384,10 +501,9 @@ public class LLDPLinkProviderTest { private class TestDeviceService extends DeviceServiceAdapter { - private Map devices = new HashMap<>(); + private final Map devices = new HashMap<>(); private final ArrayListMultimap ports = ArrayListMultimap.create(); - public TestDeviceService() { Device d1 = new DefaultDevice(ProviderId.NONE, DID1, Device.Type.SWITCH, "TESTMF", "TESTHW", "TESTSW", "TESTSN", new ChassisId()); @@ -395,7 +511,6 @@ public class LLDPLinkProviderTest { "TESTMF", "TESTHW", "TESTSW", "TESTSN", new ChassisId()); devices.put(DID1, d1); devices.put(DID2, d2); - pd1 = new DefaultPort(d1, PortNumber.portNumber(1), true); pd2 = new DefaultPort(d1, PortNumber.portNumber(2), true); pd3 = new DefaultPort(d2, PortNumber.portNumber(1), true); @@ -405,6 +520,15 @@ public class LLDPLinkProviderTest { ports.putAll(DID2, Lists.newArrayList(pd3, pd4)); } + private void putDevice(Device device) { + DeviceId deviceId = device.id(); + devices.put(deviceId, device); + } + + private void putPorts(DeviceId did, Port...ports) { + this.ports.putAll(did, Lists.newArrayList(ports)); + } + @Override public int getDeviceCount() { return devices.values().size(); @@ -412,7 +536,7 @@ public class LLDPLinkProviderTest { @Override public Iterable getDevices() { - return Collections.emptyList(); + return ImmutableList.copyOf(devices.values()); } @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 1039d049..4d5b6b28 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 @@ -15,15 +15,7 @@ */ package org.onosproject.provider.of.flow.impl; -import static org.onosproject.net.flow.criteria.Criteria.matchLambda; -import static org.onosproject.net.flow.criteria.Criteria.matchOchSignalType; -import static org.onosproject.provider.of.flow.impl.OpenFlowValueMapper.lookupChannelSpacing; -import static org.onosproject.provider.of.flow.impl.OpenFlowValueMapper.lookupGridType; -import static org.onosproject.provider.of.flow.impl.OpenFlowValueMapper.lookupOchSignalType; -import static org.slf4j.LoggerFactory.getLogger; - -import java.util.List; - +import com.google.common.collect.Lists; import org.onlab.packet.Ip4Address; import org.onlab.packet.Ip4Prefix; import org.onlab.packet.Ip6Address; @@ -36,6 +28,11 @@ import org.onosproject.core.DefaultGroupId; import org.onosproject.net.DeviceId; import org.onosproject.net.Lambda; import org.onosproject.net.PortNumber; +import org.onosproject.net.driver.DefaultDriverData; +import org.onosproject.net.driver.DefaultDriverHandler; +import org.onosproject.net.driver.Driver; +import org.onosproject.net.driver.DriverHandler; +import org.onosproject.net.driver.DriverService; import org.onosproject.net.flow.DefaultFlowEntry; import org.onosproject.net.flow.DefaultFlowRule; import org.onosproject.net.flow.DefaultTrafficSelector; @@ -47,6 +44,7 @@ import org.onosproject.net.flow.TrafficSelector; import org.onosproject.net.flow.TrafficTreatment; import org.onosproject.net.flow.instructions.Instructions; import org.onosproject.openflow.controller.Dpid; +import org.onosproject.openflow.controller.ExtensionInterpreter; import org.projectfloodlight.openflow.protocol.OFFlowMod; import org.projectfloodlight.openflow.protocol.OFFlowRemoved; import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry; @@ -55,13 +53,13 @@ import org.projectfloodlight.openflow.protocol.action.OFActionCircuit; import org.projectfloodlight.openflow.protocol.action.OFActionExperimenter; import org.projectfloodlight.openflow.protocol.action.OFActionGroup; import org.projectfloodlight.openflow.protocol.action.OFActionOutput; -import org.projectfloodlight.openflow.protocol.action.OFActionSetQueue; import org.projectfloodlight.openflow.protocol.action.OFActionPopMpls; import org.projectfloodlight.openflow.protocol.action.OFActionSetDlDst; import org.projectfloodlight.openflow.protocol.action.OFActionSetDlSrc; import org.projectfloodlight.openflow.protocol.action.OFActionSetField; import org.projectfloodlight.openflow.protocol.action.OFActionSetNwDst; import org.projectfloodlight.openflow.protocol.action.OFActionSetNwSrc; +import org.projectfloodlight.openflow.protocol.action.OFActionSetQueue; import org.projectfloodlight.openflow.protocol.action.OFActionSetVlanPcp; import org.projectfloodlight.openflow.protocol.action.OFActionSetVlanVid; import org.projectfloodlight.openflow.protocol.instruction.OFInstruction; @@ -75,7 +73,6 @@ import org.projectfloodlight.openflow.protocol.oxm.OFOxm; import org.projectfloodlight.openflow.protocol.oxm.OFOxmOchSigidBasic; import org.projectfloodlight.openflow.protocol.ver13.OFFactoryVer13; import org.projectfloodlight.openflow.types.CircuitSignalID; -import org.projectfloodlight.openflow.types.EthType; import org.projectfloodlight.openflow.types.IPv4Address; import org.projectfloodlight.openflow.types.IPv6Address; import org.projectfloodlight.openflow.types.Masked; @@ -87,7 +84,14 @@ import org.projectfloodlight.openflow.types.U8; import org.projectfloodlight.openflow.types.VlanPcp; import org.slf4j.Logger; -import com.google.common.collect.Lists; +import java.util.List; + +import static org.onosproject.net.flow.criteria.Criteria.matchLambda; +import static org.onosproject.net.flow.criteria.Criteria.matchOchSignalType; +import static org.onosproject.provider.of.flow.impl.OpenFlowValueMapper.lookupChannelSpacing; +import static org.onosproject.provider.of.flow.impl.OpenFlowValueMapper.lookupGridType; +import static org.onosproject.provider.of.flow.impl.OpenFlowValueMapper.lookupOchSignalType; +import static org.slf4j.LoggerFactory.getLogger; public class FlowEntryBuilder { private final Logger log = getLogger(getClass()); @@ -108,7 +112,9 @@ public class FlowEntryBuilder { private final FlowType type; - public FlowEntryBuilder(Dpid dpid, OFFlowStatsEntry entry) { + private final DriverService driverService; + + public FlowEntryBuilder(Dpid dpid, OFFlowStatsEntry entry, DriverService driverService) { this.stat = entry; this.match = entry.getMatch(); this.instructions = getInstructions(entry); @@ -116,9 +122,10 @@ public class FlowEntryBuilder { this.removed = null; this.flowMod = null; this.type = FlowType.STAT; + this.driverService = driverService; } - public FlowEntryBuilder(Dpid dpid, OFFlowRemoved removed) { + public FlowEntryBuilder(Dpid dpid, OFFlowRemoved removed, DriverService driverService) { this.match = removed.getMatch(); this.removed = removed; @@ -127,10 +134,10 @@ public class FlowEntryBuilder { this.stat = null; this.flowMod = null; this.type = FlowType.REMOVED; - + this.driverService = driverService; } - public FlowEntryBuilder(Dpid dpid, OFFlowMod fm) { + public FlowEntryBuilder(Dpid dpid, OFFlowMod fm, DriverService driverService) { this.match = fm.getMatch(); this.dpid = dpid; this.instructions = getInstructions(fm); @@ -138,6 +145,7 @@ public class FlowEntryBuilder { this.flowMod = fm; this.stat = null; this.removed = null; + this.driverService = driverService; } public FlowEntry build(FlowEntryState... state) { @@ -309,7 +317,7 @@ public class FlowEntryBuilder { break; case SET_FIELD: OFActionSetField setField = (OFActionSetField) act; - handleSetField(builder, setField.getField()); + handleSetField(builder, setField); break; case POP_MPLS: OFActionPopMpls popMpls = (OFActionPopMpls) act; @@ -365,7 +373,8 @@ public class FlowEntryBuilder { } - private void handleSetField(TrafficTreatment.Builder builder, OFOxm oxm) { + private void handleSetField(TrafficTreatment.Builder builder, OFActionSetField action) { + OFOxm oxm = action.getField(); switch (oxm.getMatchField().id) { case VLAN_PCP: @SuppressWarnings("unchecked") @@ -434,6 +443,13 @@ public class FlowEntryBuilder { OFOxm udpsrc = (OFOxm) oxm; builder.setUdpSrc(TpPort.tpPort(udpsrc.getValue().getPort())); break; + case TUNNEL_IPV4_DST: + DriverHandler driver = getDriver(dpid); + ExtensionInterpreter interpreter = driver.behaviour(ExtensionInterpreter.class); + if (interpreter != null) { + builder.extension(interpreter.mapAction(action), DeviceId.deviceId(Dpid.uri(dpid))); + } + break; case ARP_OP: case ARP_SHA: case ARP_SPA: @@ -520,11 +536,7 @@ public class FlowEntryBuilder { break; case ETH_TYPE: int ethType = match.get(MatchField.ETH_TYPE).getValue(); - if (ethType == EthType.VLAN_FRAME.getValue()) { - builder.matchVlanId(VlanId.ANY); - } else { - builder.matchEthType((short) ethType); - } + builder.matchEthType((short) ethType); break; case VLAN_VID: VlanId vlanId = null; @@ -703,4 +715,11 @@ public class FlowEntryBuilder { } return builder.build(); } + + private DriverHandler getDriver(Dpid dpid) { + DeviceId deviceId = DeviceId.deviceId(Dpid.uri(dpid)); + Driver driver = driverService.getDriver(deviceId); + DriverHandler handler = new DefaultDriverHandler(new DefaultDriverData(driver, deviceId)); + return handler; + } } diff --git a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilder.java b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilder.java index e050524a..7eca4920 100644 --- a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilder.java +++ b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilder.java @@ -15,16 +15,13 @@ */ package org.onosproject.provider.of.flow.impl; -import static org.slf4j.LoggerFactory.getLogger; - -import java.util.Optional; - import org.onlab.packet.Ip4Address; import org.onlab.packet.Ip4Prefix; import org.onlab.packet.Ip6Address; import org.onlab.packet.Ip6Prefix; import org.onlab.packet.VlanId; import org.onosproject.net.OchSignal; +import org.onosproject.net.driver.DriverService; import org.onosproject.net.flow.FlowRule; import org.onosproject.net.flow.TrafficSelector; import org.onosproject.net.flow.criteria.Criterion; @@ -85,6 +82,10 @@ import org.projectfloodlight.openflow.types.VlanPcp; import org.projectfloodlight.openflow.types.VlanVid; import org.slf4j.Logger; +import java.util.Optional; + +import static org.slf4j.LoggerFactory.getLogger; + /** * Builder for OpenFlow flow mods based on FlowRules. */ @@ -96,6 +97,7 @@ public abstract class FlowModBuilder { private final FlowRule flowRule; private final TrafficSelector selector; protected final Long xid; + protected final Optional driverService; /** * Creates a new flow mod builder. @@ -107,12 +109,13 @@ public abstract class FlowModBuilder { */ public static FlowModBuilder builder(FlowRule flowRule, OFFactory factory, - Optional xid) { + Optional xid, + Optional driverService) { switch (factory.getVersion()) { case OF_10: - return new FlowModBuilderVer10(flowRule, factory, xid); + return new FlowModBuilderVer10(flowRule, factory, xid, driverService); case OF_13: - return new FlowModBuilderVer13(flowRule, factory, xid); + return new FlowModBuilderVer13(flowRule, factory, xid, driverService); default: throw new UnsupportedOperationException( "No flow mod builder for protocol version " + factory.getVersion()); @@ -126,12 +129,13 @@ public abstract class FlowModBuilder { * @param factory the OpenFlow factory to use to build the flow mod * @param xid the transaction ID */ - protected FlowModBuilder(FlowRule flowRule, OFFactory factory, Optional xid) { + protected FlowModBuilder(FlowRule flowRule, OFFactory factory, Optional xid, + Optional driverService) { this.factory = factory; this.flowRule = flowRule; this.selector = flowRule.selector(); this.xid = xid.orElse(0L); - + this.driverService = driverService; } /** 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 f77819d5..c7898414 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 @@ -17,6 +17,7 @@ package org.onosproject.provider.of.flow.impl; import org.onlab.packet.Ip4Address; import org.onosproject.net.PortNumber; +import org.onosproject.net.driver.DriverService; import org.onosproject.net.flow.FlowRule; import org.onosproject.net.flow.TrafficTreatment; import org.onosproject.net.flow.instructions.Instruction; @@ -68,8 +69,9 @@ public class FlowModBuilderVer10 extends FlowModBuilder { * @param xid the transaction ID */ protected FlowModBuilderVer10(FlowRule flowRule, - OFFactory factory, Optional xid) { - super(flowRule, factory, xid); + OFFactory factory, Optional xid, + Optional driverService) { + super(flowRule, factory, xid, driverService); this.treatment = flowRule.treatment(); } 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 64b4360a..a99aa817 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 @@ -18,10 +18,16 @@ package org.onosproject.provider.of.flow.impl; import com.google.common.collect.Lists; import org.onlab.packet.Ip4Address; import org.onlab.packet.Ip6Address; +import org.onosproject.net.DeviceId; import org.onosproject.net.OchSignal; import org.onosproject.net.PortNumber; +import org.onosproject.net.driver.DefaultDriverData; +import org.onosproject.net.driver.DefaultDriverHandler; +import org.onosproject.net.driver.Driver; +import org.onosproject.net.driver.DriverService; import org.onosproject.net.flow.FlowRule; import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.flow.instructions.ExtensionInstruction; import org.onosproject.net.flow.instructions.Instruction; import org.onosproject.net.flow.instructions.Instructions; import org.onosproject.net.flow.instructions.Instructions.GroupInstruction; @@ -34,15 +40,16 @@ import org.onosproject.net.flow.instructions.L2ModificationInstruction; import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction; import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsBosInstruction; import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsLabelInstruction; +import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModTunnelIdInstruction; import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction; import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanPcpInstruction; import org.onosproject.net.flow.instructions.L2ModificationInstruction.PushHeaderInstructions; -import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModTunnelIdInstruction; import org.onosproject.net.flow.instructions.L3ModificationInstruction; import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPInstruction; import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPv6FlowLabelInstruction; import org.onosproject.net.flow.instructions.L4ModificationInstruction; import org.onosproject.net.flow.instructions.L4ModificationInstruction.ModTransportPortInstruction; +import org.onosproject.openflow.controller.ExtensionInterpreter; import org.projectfloodlight.openflow.protocol.OFFactory; import org.projectfloodlight.openflow.protocol.OFFlowAdd; import org.projectfloodlight.openflow.protocol.OFFlowDelete; @@ -88,6 +95,7 @@ public class FlowModBuilderVer13 extends FlowModBuilder { private static final int OFPCML_NO_BUFFER = 0xffff; private final TrafficTreatment treatment; + private final DeviceId deviceId; /** * Constructor for a flow mod builder for OpenFlow 1.3. @@ -96,10 +104,12 @@ public class FlowModBuilderVer13 extends FlowModBuilder { * @param factory the OpenFlow factory to use to build the flow mod * @param xid the transaction ID */ - protected FlowModBuilderVer13(FlowRule flowRule, OFFactory factory, Optional xid) { - super(flowRule, factory, xid); + protected FlowModBuilderVer13(FlowRule flowRule, OFFactory factory, Optional xid, + Optional driverService) { + super(flowRule, factory, xid, driverService); this.treatment = flowRule.treatment(); + this.deviceId = flowRule.deviceId(); } @Override @@ -256,6 +266,10 @@ public class FlowModBuilderVer13 extends FlowModBuilder { //FIXME: should not occur here. tableFound = true; break; + case EXTENSION: + actions.add(buildExtensionAction(((Instructions.ExtensionInstructionWrapper) i) + .extensionInstruction())); + break; default: log.warn("Instruction type {} not yet implemented.", i.type()); } @@ -467,4 +481,20 @@ public class FlowModBuilderVer13 extends FlowModBuilder { return null; } + private OFAction buildExtensionAction(ExtensionInstruction i) { + if (!driverService.isPresent()) { + log.error("No driver service present"); + return null; + } + Driver driver = driverService.get().getDriver(deviceId); + if (driver.hasBehaviour(ExtensionInterpreter.class)) { + DefaultDriverHandler handler = + new DefaultDriverHandler(new DefaultDriverData(driver, deviceId)); + ExtensionInterpreter interpreter = handler.behaviour(ExtensionInterpreter.class); + return interpreter.mapInstruction(factory(), i); + } + + return null; + } + } 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 index 487cae96..d5186fa9 100644 --- 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 @@ -16,21 +16,10 @@ 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; @@ -47,9 +36,19 @@ import org.projectfloodlight.openflow.types.OFPort; import org.projectfloodlight.openflow.types.TableId; import org.slf4j.Logger; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + 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.onosproject.net.flow.TypedStoredFlowEntry.FlowLiveType; import static org.slf4j.LoggerFactory.getLogger; /** @@ -232,7 +231,8 @@ public class NewAdaptiveFlowStatsCollector { // send openflow flow stats request message with getting the specific flow entry(fe) to a given switch sw private void ofFlowStatsRequestFlowSend(FlowEntry fe) { // set find match - Match match = FlowModBuilder.builder(fe, sw.factory(), Optional.empty()).buildMatch(); + Match match = FlowModBuilder.builder(fe, sw.factory(), Optional.empty(), + Optional.empty()).buildMatch(); // set find tableId TableId tableId = TableId.of(fe.tableId()); // set output port 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 6374ca55..b37cb42c 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 @@ -21,7 +21,6 @@ import com.google.common.cache.RemovalCause; import com.google.common.cache.RemovalNotification; import com.google.common.collect.Maps; import com.google.common.collect.Sets; - import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Deactivate; @@ -32,6 +31,7 @@ import org.apache.felix.scr.annotations.ReferenceCardinality; import org.onosproject.cfg.ComponentConfigService; import org.onosproject.core.ApplicationId; import org.onosproject.net.DeviceId; +import org.onosproject.net.driver.DriverService; import org.onosproject.net.flow.CompletedBatchOperation; import org.onosproject.net.flow.DefaultTableStatisticsEntry; import org.onosproject.net.flow.FlowEntry; @@ -61,12 +61,12 @@ import org.projectfloodlight.openflow.protocol.OFErrorType; import org.projectfloodlight.openflow.protocol.OFFlowMod; import org.projectfloodlight.openflow.protocol.OFFlowRemoved; import org.projectfloodlight.openflow.protocol.OFFlowStatsReply; -import org.projectfloodlight.openflow.protocol.OFTableStatsReply; -import org.projectfloodlight.openflow.protocol.OFTableStatsEntry; import org.projectfloodlight.openflow.protocol.OFMessage; import org.projectfloodlight.openflow.protocol.OFPortStatus; import org.projectfloodlight.openflow.protocol.OFStatsReply; import org.projectfloodlight.openflow.protocol.OFStatsType; +import org.projectfloodlight.openflow.protocol.OFTableStatsEntry; +import org.projectfloodlight.openflow.protocol.OFTableStatsReply; import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg; import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg; import org.slf4j.Logger; @@ -106,6 +106,9 @@ public class OpenFlowRuleProvider extends AbstractProvider @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected ComponentConfigService cfgService; + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected DriverService driverService; + private static final int DEFAULT_POLL_FREQUENCY = 5; @Property(name = "flowPollFrequency", intValue = DEFAULT_POLL_FREQUENCY, label = "Frequency (in seconds) for polling flow statistics") @@ -269,7 +272,7 @@ public class OpenFlowRuleProvider extends AbstractProvider return; } sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(), - Optional.empty()).buildFlowAdd()); + Optional.empty(), Optional.of(driverService)).buildFlowAdd()); if (adaptiveFlowSampling) { // Add TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector @@ -298,7 +301,7 @@ public class OpenFlowRuleProvider extends AbstractProvider return; } sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(), - Optional.empty()).buildFlowDel()); + Optional.empty(), Optional.of(driverService)).buildFlowDel()); if (adaptiveFlowSampling) { // Remove TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector @@ -334,7 +337,8 @@ public class OpenFlowRuleProvider extends AbstractProvider continue; } FlowModBuilder builder = - FlowModBuilder.builder(fbe.target(), sw.factory(), Optional.of(batch.id())); + FlowModBuilder.builder(fbe.target(), sw.factory(), + Optional.of(batch.id()), Optional.of(driverService)); NewAdaptiveFlowStatsCollector collector = afsCollectors.get(dpid); switch (fbe.operator()) { case ADD: @@ -423,7 +427,7 @@ public class OpenFlowRuleProvider extends AbstractProvider case FLOW_REMOVED: OFFlowRemoved removed = (OFFlowRemoved) msg; - FlowEntry fr = new FlowEntryBuilder(dpid, removed).build(); + FlowEntry fr = new FlowEntryBuilder(dpid, removed, driverService).build(); providerService.flowRemoved(fr); if (adaptiveFlowSampling) { @@ -474,7 +478,7 @@ public class OpenFlowRuleProvider extends AbstractProvider InternalCacheEntry entry = pendingBatches.getIfPresent(msg.getXid()); if (entry != null) { - entry.appendFailure(new FlowEntryBuilder(dpid, fm).build()); + entry.appendFailure(new FlowEntryBuilder(dpid, fm, driverService).build()); } else { log.error("No matching batch for this error: {}", error); } @@ -501,7 +505,7 @@ public class OpenFlowRuleProvider extends AbstractProvider DeviceId did = DeviceId.deviceId(Dpid.uri(dpid)); List flowEntries = replies.getEntries().stream() - .map(entry -> new FlowEntryBuilder(dpid, entry).build()) + .map(entry -> new FlowEntryBuilder(dpid, entry, driverService).build()) .collect(Collectors.toList()); if (adaptiveFlowSampling) { diff --git a/framework/src/onos/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/GroupBucketEntryBuilder.java b/framework/src/onos/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/GroupBucketEntryBuilder.java index b9de7c0f..d3a23782 100644 --- a/framework/src/onos/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/GroupBucketEntryBuilder.java +++ b/framework/src/onos/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/GroupBucketEntryBuilder.java @@ -115,6 +115,10 @@ public class GroupBucketEntryBuilder { DefaultGroupBucket.createFailoverGroupBucket(treatment, port, groupId); break; + case ALL: + groupBucket = + DefaultGroupBucket.createAllGroupBucket(treatment); + break; default: log.error("Unsupported Group type : {}", type); } diff --git a/framework/src/onos/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/OpenFlowGroupProvider.java b/framework/src/onos/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/OpenFlowGroupProvider.java index 8acf08ee..5783c842 100644 --- a/framework/src/onos/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/OpenFlowGroupProvider.java +++ b/framework/src/onos/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/OpenFlowGroupProvider.java @@ -252,7 +252,7 @@ public class OpenFlowGroupProvider extends AbstractProvider implements GroupProv private GroupDescription.Type getGroupType(OFGroupType type) { switch (type) { case ALL: - return GroupDescription.Type.ALL; + return GroupDescription.Type.ALL; case INDIRECT: return GroupDescription.Type.INDIRECT; case SELECT: diff --git a/framework/src/onos/providers/ovsdb/host/src/main/java/org/onosproject/ovsdb/provider/host/OvsdbHostProvider.java b/framework/src/onos/providers/ovsdb/host/src/main/java/org/onosproject/ovsdb/provider/host/OvsdbHostProvider.java index 0e3e1564..031fda78 100644 --- a/framework/src/onos/providers/ovsdb/host/src/main/java/org/onosproject/ovsdb/provider/host/OvsdbHostProvider.java +++ b/framework/src/onos/providers/ovsdb/host/src/main/java/org/onosproject/ovsdb/provider/host/OvsdbHostProvider.java @@ -111,7 +111,7 @@ public class OvsdbHostProvider extends AbstractProvider implements HostProvider } switch (event.type()) { case PORT_ADDED: - HostId hostId = HostId.hostId(subject.hwAddress(), null); + HostId hostId = HostId.hostId(subject.hwAddress(), VlanId.vlanId()); DeviceId deviceId = DeviceId.deviceId(uri(subject.dpid().value())); PortNumber portNumber = PortNumber.portNumber(subject .portNumber().value(), subject.portName().value()); @@ -127,7 +127,7 @@ public class OvsdbHostProvider extends AbstractProvider implements HostProvider providerService.hostDetected(hostId, hostDescription); break; case PORT_REMOVED: - HostId host = HostId.hostId(subject.hwAddress(), null); + HostId host = HostId.hostId(subject.hwAddress(), VlanId.vlanId()); providerService.hostVanished(host); break; default: diff --git a/framework/src/onos/tools/build/conf/pom.xml b/framework/src/onos/tools/build/conf/pom.xml index 29e4dea0..d56168f2 100644 --- a/framework/src/onos/tools/build/conf/pom.xml +++ b/framework/src/onos/tools/build/conf/pom.xml @@ -27,7 +27,7 @@ org.onosproject onos-build-conf - 1.1 + 1.1-SNAPSHOT Various ONOS build settings 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 1bb3b0bf..e04479c5 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 @@ -67,9 +67,7 @@ --> - - + diff --git a/framework/src/onos/tools/build/conf/src/main/resources/onos/suppressions.xml b/framework/src/onos/tools/build/conf/src/main/resources/onos/suppressions.xml index a71d941f..6d8f1982 100644 --- a/framework/src/onos/tools/build/conf/src/main/resources/onos/suppressions.xml +++ b/framework/src/onos/tools/build/conf/src/main/resources/onos/suppressions.xml @@ -29,4 +29,12 @@ + + + + + diff --git a/framework/src/onos/tools/dev/bin/onos-build-selective b/framework/src/onos/tools/dev/bin/onos-build-selective index ac2dec8e..351c53ac 100755 --- a/framework/src/onos/tools/dev/bin/onos-build-selective +++ b/framework/src/onos/tools/dev/bin/onos-build-selective @@ -15,9 +15,11 @@ if [ -n "$projects" ]; then # Ascertain artifact IDs of the projects to be rebuilt modulesERE="" for pd in ${projects//,/ }; do - artifactId=$(grep -E "^ .*$" ${pd}/pom.xml | \ - sed 's/.[^>]*>//;s/<.*//') - modulesERE="$modulesERE|$artifactId" + if [ -f ${pd}/pom.xml ]; then + artifactId=$(grep -E "^ .*$" ${pd}/pom.xml | \ + sed 's/.[^>]*>//;s/<.*//') + modulesERE="$modulesERE|$artifactId" + fi done modulesERE=${modulesERE#|*} diff --git a/framework/src/onos/tools/dev/bin/onos-build-selective.exclude b/framework/src/onos/tools/dev/bin/onos-build-selective.exclude index 1265494e..487f848c 100644 --- a/framework/src/onos/tools/dev/bin/onos-build-selective.exclude +++ b/framework/src/onos/tools/dev/bin/onos-build-selective.exclude @@ -6,4 +6,5 @@ .*/cord-gui/.* .*/jdvue/.* .*/ovsdb/api/.* -.*/netconf/flow/.* \ No newline at end of file +.*/netconf/flow/.* +.*/vtn/sfcmgr/.* \ No newline at end of file diff --git a/framework/src/onos/tools/dev/bin/onos-setup-karaf b/framework/src/onos/tools/dev/bin/onos-setup-karaf index 3323d9d1..cbe62253 100755 --- a/framework/src/onos/tools/dev/bin/onos-setup-karaf +++ b/framework/src/onos/tools/dev/bin/onos-setup-karaf @@ -97,13 +97,11 @@ fi echo "Creating local cluster configs for IP $IP..." [ -d $STAGE/config ] || mkdir -p $STAGE/config cat > $STAGE/config/cluster.json < $STAGE/config/tablets.json < links = linkService.getDeviceEgressLinks(devId); - sendHighlights(fromLinks(links, devId)); + Highlights highlights = fromLinks(links, devId); + addDeviceBadge(highlights, devId, links.size()); + sendHighlights(highlights); } // Note: could also process Host, if available } + private void addDeviceBadge(Highlights h, DeviceId devId, int n) { + DeviceHighlight dh = new DeviceHighlight(devId.toString()); + dh.setBadge(createBadge(n)); + h.add(dh); + } + + private NodeBadge createBadge(int n) { + Status status = n > 3 ? Status.ERROR : Status.WARN; + String noun = n > 3 ? "(critical)" : "(problematic)"; + String msg = "Egress links: " + n + " " + noun; + return NodeBadge.number(status, n, msg); + } + private Highlights fromLinks(Set links, DeviceId devId) { DemoLinkMap linkMap = new DemoLinkMap(); if (links != null) { 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 index 98999825..48e75a5a 100644 --- 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 @@ -18,13 +18,20 @@ */ package ${package}; +import org.onosproject.net.DeviceId; import org.onosproject.ui.UiTopoOverlay; import org.onosproject.ui.topo.ButtonId; import org.onosproject.ui.topo.PropertyPanel; import org.onosproject.ui.topo.TopoConstants.CoreButtons; import org.onosproject.ui.topo.TopoConstants.Glyphs; -import static org.onosproject.ui.topo.TopoConstants.Properties.*; +import static org.onosproject.ui.topo.TopoConstants.Properties.FLOWS; +import static org.onosproject.ui.topo.TopoConstants.Properties.INTENTS; +import static org.onosproject.ui.topo.TopoConstants.Properties.LATITUDE; +import static org.onosproject.ui.topo.TopoConstants.Properties.LONGITUDE; +import static org.onosproject.ui.topo.TopoConstants.Properties.TOPOLOGY_SSCS; +import static org.onosproject.ui.topo.TopoConstants.Properties.TUNNELS; +import static org.onosproject.ui.topo.TopoConstants.Properties.VERSION; /** * Our topology overlay. @@ -61,7 +68,7 @@ public class AppUiTopovOverlay extends UiTopoOverlay { } @Override - public void modifyDeviceDetails(PropertyPanel pp) { + public void modifyDeviceDetails(PropertyPanel pp, DeviceId deviceId) { pp.title(MY_DEVICE_TITLE); pp.removeProps(LATITUDE, LONGITUDE); diff --git a/framework/src/onos/tools/test/bin/onos-config b/framework/src/onos/tools/test/bin/onos-config index 348cb839..e37dc3b2 100755 --- a/framework/src/onos/tools/test/bin/onos-config +++ b/framework/src/onos/tools/test/bin/onos-config @@ -37,17 +37,6 @@ export ONOS_BOOT_FEATURES="${ONOS_BOOT_FEATURES:-webconsole,onos-api,onos-core,o # ONOS builtin apps and providers ignited by default export ONOS_APPS="${ONOS_APPS:-drivers,openflow}" -# Generate a cluster.json from the ON* environment variables -CDEF_FILE=/tmp/${remote}.cluster.json -echo "{ \"ipPrefix\": \"$ONOS_NIC\"," > $CDEF_FILE -echo " \"nodes\":[" >> $CDEF_FILE -for node in $(env | sort | egrep "OC[2-9]+" | cut -d= -f2); do - echo " { \"id\": \"$node\", \"ip\": \"$node\", \"tcpPort\": 9876 }," >> $CDEF_FILE -done -echo " { \"id\": \"$OC1\", \"ip\": \"$OC1\", \"tcpPort\": 9876 }" >> $CDEF_FILE -echo "]}" >> $CDEF_FILE -scp -q $CDEF_FILE $remote:$ONOS_INSTALL_DIR/config/cluster.json - ssh $remote " echo \"onos.ip = \$(sudo ifconfig | grep $ONOS_NIC | cut -d: -f2 | cut -d\\ -f1)\" \ >> $ONOS_INSTALL_DIR/$KARAF_DIST/etc/system.properties @@ -66,10 +55,10 @@ ssh $remote " done " -# Generate a default tablets.json from the ON* environment variables -TDEF_FILE=/tmp/${remote}.tablets.json -onos-gen-partitions $TDEF_FILE -scp -q $TDEF_FILE $remote:$ONOS_INSTALL_DIR/config/tablets.json +# Generate a default cluster.json from the ON* environment variables +CDEF_FILE=/tmp/${remote}.cluster.json +onos-gen-partitions $CDEF_FILE +scp -q $CDEF_FILE $remote:$ONOS_INSTALL_DIR/config/cluster.json # Copy tools/package/config/ to remote scp -qr ${ONOS_ROOT}/tools/package/config/ $remote:$ONOS_INSTALL_DIR/ diff --git a/framework/src/onos/tools/test/bin/onos-execute-expect b/framework/src/onos/tools/test/bin/onos-execute-expect new file mode 100755 index 00000000..6ad95699 --- /dev/null +++ b/framework/src/onos/tools/test/bin/onos-execute-expect @@ -0,0 +1,27 @@ +#!/bin/bash +# ----------------------------------------------------------------------------- +# Executes a command on the given ONOS instance and matches the output +# to the passed one. +# First argument is the IP address of the machine to run the command on, +# then you pass the command and it's arguments if needed, then --expect and +# after it the string of what the output should be. +# Example: +# onos-execute-expect 1.1.1.1 fooCommand fooParamenter --expect fooOutputString +# ----------------------------------------------------------------------------- + +[ ! -d "$ONOS_ROOT" ] && echo "ONOS_ROOT is not defined" >&2 && exit 1 +. $ONOS_ROOT/tools/build/envDefaults + + +aux=/tmp/stc-$$.log +trap "rm -f $aux 2>/dev/null" EXIT +ip=$1 +cmd="" +for a in ${*:2}; do shift; if [ "$a" = "--expect" ]; then break; fi; cmd="$cmd $a"; done +expect="${@: -1}" +onos $ip $cmd > $aux +cat $aux +grep -q $expect $aux && echo "expected value found" && exit 0 +exit 1 + + diff --git a/framework/src/onos/tools/test/bin/onos-gen-partitions b/framework/src/onos/tools/test/bin/onos-gen-partitions index a2558392..35195b04 100755 --- a/framework/src/onos/tools/test/bin/onos-gen-partitions +++ b/framework/src/onos/tools/test/bin/onos-gen-partitions @@ -23,22 +23,27 @@ def get_OC_vars(): return sorted(vars, key=alphanum_key) def get_nodes(vars, port=9876): - node = lambda k: { 'id': k, 'ip': k, 'tcpPort': port } + node = lambda k: { 'id': k, 'ip': k, 'port': port } return [ node(environ[v]) for v in vars ] def generate_permutations(nodes, k): l = deque(nodes) - perms = {} + perms = [] for i in range(1, len(nodes)+1): - perms['p%d' % i] = list(l)[:k] + part = { + 'name': 'p%d' % i, + 'members': list(l)[:k] + } + perms.append(part) l.rotate(-1) - return OrderedDict(sorted(perms.iteritems(), key=lambda (k, v): alphanum_key(k))) + return perms if __name__ == '__main__': vars = get_OC_vars() nodes = get_nodes(vars) - partitions = generate_permutations(nodes, 3) - data = { + partitions = generate_permutations([v.get('id') for v in nodes], 3) + data = { + 'name': 'default', 'nodes': nodes, 'partitions': partitions } diff --git a/framework/src/onos/tools/test/bin/onos-secure-ssh b/framework/src/onos/tools/test/bin/onos-secure-ssh index a3980e17..6d898ee8 100755 --- a/framework/src/onos/tools/test/bin/onos-secure-ssh +++ b/framework/src/onos/tools/test/bin/onos-secure-ssh @@ -10,7 +10,8 @@ nodes=$(env | sort | egrep "OC[0-9]+" | cut -d= -f2) for node in $nodes; do # Prune the node entry from the known hosts file since server key changes - ssh-keygen -f "$HOME/.ssh/known_hosts" -R [$node]:8101 + ssh-keygen -f "$HOME/.ssh/known_hosts" -R [$node]:8101 || + ( echo "Failed to remove key from known_hosts" >&2 && exit 1 ) # Setup passwordless login for the local user on the remote node ssh $ONOS_USER@$node " diff --git a/framework/src/onos/tools/test/bin/stc b/framework/src/onos/tools/test/bin/stc index 8737cf3f..60a1720e 100755 --- a/framework/src/onos/tools/test/bin/stc +++ b/framework/src/onos/tools/test/bin/stc @@ -20,6 +20,7 @@ scenario=${1:-smoke} # If stcColor is not set, we will enable color if this is an interactive session [ -t 1 ] && interactive=true || interactive=false +[ -t 1 ] && notInteractive=false || notInteractive=true # stc requires that ONOS_USE_SSH=true, but we will store the old value and reset it after sshSet=$([ -z ${ONOS_USE_SSH+x} ]) && oldSSH=$ONOS_USE_SSH @@ -27,7 +28,8 @@ export ONOS_USE_SSH=true # Run stc [ -z "$stcDebug" ] && DEBUG_OPTS="" -stcColor=${stcColor:-$interactive} java $DEBUG_OPTS -jar $JAR $scenario "$@" +stcColor=${stcColor:-$interactive} stcDumpLogs=${stcDumpLogs:-$notInteractive} \ + java $DEBUG_OPTS -jar $JAR $scenario "$@" # Reset the old value of ONOS_USE_SSH [ $sshSet ] && export ONOS_USE_SSH=oldSSH || unset ONOS_USE_SSH diff --git a/framework/src/onos/tools/test/scenarios/dist-test-seq.xml b/framework/src/onos/tools/test/scenarios/dist-test-seq.xml new file mode 100644 index 00000000..2e99fa27 --- /dev/null +++ b/framework/src/onos/tools/test/scenarios/dist-test-seq.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/framework/src/onos/tools/test/scenarios/dist-test.xml b/framework/src/onos/tools/test/scenarios/dist-test.xml new file mode 100644 index 00000000..5e7dab0b --- /dev/null +++ b/framework/src/onos/tools/test/scenarios/dist-test.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/framework/src/onos/tools/test/topos/opticalUtils.py b/framework/src/onos/tools/test/topos/opticalUtils.py index a1ae834b..5d955e51 100644 --- a/framework/src/onos/tools/test/topos/opticalUtils.py +++ b/framework/src/onos/tools/test/topos/opticalUtils.py @@ -344,7 +344,10 @@ class LINCSwitch(OpticalSwitch): continue portDict = {} portDict[ 'port' ] = port - portDict[ 'type' ] = 'FIBER' if isinstance(intf.link, LINCLink) else 'COPPER' + portType = 'COPPER' + if isinstance(intf.link, LINCLink): + portType = 'OCH' if intf.link.isCrossConnect else 'OMS' + portDict[ 'type' ] = portType intfList = [ intf.link.intf1, intf.link.intf2 ] intfList.remove(intf) portDict[ 'speed' ] = intfList[ 0 ].speed if isinstance(intf.link, LINCLink) else 0 @@ -787,7 +790,10 @@ class LINCIntf(OpticalIntf): configDict = {} configDict[ 'port' ] = self.port configDict[ 'speed' ] = self.speed - configDict[ 'type' ] = 'FIBER' + portType = 'COPPER' + if isinstance(self.link, LINCLink): + portType = 'OCH' if self.link.isCrossConnect else 'OMS' + configDict[ 'type' ] = portType return configDict def config(self, *args, **kwargs): diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/Ethernet.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/Ethernet.java index 003c1772..9ab5cab1 100644 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/Ethernet.java +++ b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/Ethernet.java @@ -18,6 +18,12 @@ package org.onlab.packet; +import org.onlab.packet.ndp.NeighborAdvertisement; +import org.onlab.packet.ndp.NeighborSolicitation; +import org.onlab.packet.ndp.Redirect; +import org.onlab.packet.ndp.RouterAdvertisement; +import org.onlab.packet.ndp.RouterSolicitation; + import java.nio.ByteBuffer; import java.util.Arrays; import java.util.HashMap; @@ -531,27 +537,114 @@ public class Ethernet extends BasePacket { sb.append("\nnw_proto: "); sb.append(p.getProtocol()); - if (pkt instanceof TCP) { - sb.append("\ntp_src: "); - sb.append(((TCP) pkt).getSourcePort()); - sb.append("\ntp_dst: "); - sb.append(((TCP) pkt).getDestinationPort()); - - } else if (pkt instanceof UDP) { - sb.append("\ntp_src: "); - sb.append(((UDP) pkt).getSourcePort()); - sb.append("\ntp_dst: "); - sb.append(((UDP) pkt).getDestinationPort()); + IPacket payload = pkt.getPayload(); + if (payload != null) { + if (payload instanceof TCP) { + sb.append("\ntp_src: "); + sb.append(((TCP) payload).getSourcePort()); + sb.append("\ntp_dst: "); + sb.append(((TCP) payload).getDestinationPort()); + + } else if (payload instanceof UDP) { + sb.append("\ntp_src: "); + sb.append(((UDP) payload).getSourcePort()); + sb.append("\ntp_dst: "); + sb.append(((UDP) payload).getDestinationPort()); + } else if (payload instanceof ICMP) { + final ICMP icmp = (ICMP) payload; + sb.append("\nicmp_type: "); + sb.append(icmp.getIcmpType()); + sb.append("\nicmp_code: "); + sb.append(icmp.getIcmpCode()); + } } - - if (pkt instanceof ICMP) { - final ICMP icmp = (ICMP) pkt; - sb.append("\nicmp_type: "); - sb.append(icmp.getIcmpType()); - sb.append("\nicmp_code: "); - sb.append(icmp.getIcmpCode()); + } else if (pkt instanceof IPv6) { + final IPv6 ipv6 = (IPv6) pkt; + sb.append("\nipv6_src: "); + sb.append(Ip6Address.valueOf(ipv6.getSourceAddress()).toString()); + sb.append("\nipv6_dst: "); + sb.append(Ip6Address.valueOf(ipv6.getDestinationAddress()).toString()); + sb.append("\nipv6_proto: "); + sb.append(ipv6.getNextHeader()); + + IPacket payload = pkt.getPayload(); + if (payload != null && payload instanceof ICMP6) { + final ICMP6 icmp6 = (ICMP6) payload; + sb.append("\nicmp6_type: "); + sb.append(icmp6.getIcmpType()); + sb.append("\nicmp6_code: "); + sb.append(icmp6.getIcmpCode()); + + payload = payload.getPayload(); + if (payload != null) { + if (payload instanceof NeighborSolicitation) { + final NeighborSolicitation ns = (NeighborSolicitation) payload; + sb.append("\nns_target_addr: "); + sb.append(Ip6Address.valueOf(ns.getTargetAddress()).toString()); + ns.getOptions().forEach(option -> { + sb.append("\noption_type: "); + sb.append(option.type()); + sb.append("\noption_data: "); + sb.append(bytesToHex(option.data())); + }); + } else if (payload instanceof NeighborAdvertisement) { + final NeighborAdvertisement na = (NeighborAdvertisement) payload; + sb.append("\nna_target_addr: "); + sb.append(Ip6Address.valueOf(na.getTargetAddress()).toString()); + sb.append("\nna_solicited_flag: "); + sb.append(na.getSolicitedFlag()); + sb.append("\nna_router_flag: "); + sb.append(na.getRouterFlag()); + sb.append("\nna_override_flag: "); + sb.append(na.getOverrideFlag()); + na.getOptions().forEach(option -> { + sb.append("\noption_type: "); + sb.append(option.type()); + sb.append("\noption_data: "); + sb.append(bytesToHex(option.data())); + }); + } else if (payload instanceof RouterSolicitation) { + final RouterSolicitation rs = (RouterSolicitation) payload; + sb.append("\nrs"); + rs.getOptions().forEach(option -> { + sb.append("\noption_type: "); + sb.append(option.type()); + sb.append("\noption_data: "); + sb.append(bytesToHex(option.data())); + }); + } else if (payload instanceof RouterAdvertisement) { + final RouterAdvertisement ra = (RouterAdvertisement) payload; + sb.append("\nra_hop_limit: "); + sb.append(ra.getCurrentHopLimit()); + sb.append("\nra_mflag: "); + sb.append(ra.getMFlag()); + sb.append("\nra_oflag: "); + sb.append(ra.getOFlag()); + sb.append("\nra_reachable_time: "); + sb.append(ra.getReachableTime()); + sb.append("\nra_retransmit_time: "); + sb.append(ra.getRetransmitTimer()); + sb.append("\nra_router_lifetime: "); + sb.append(ra.getRouterLifetime()); + ra.getOptions().forEach(option -> { + sb.append("\noption_type: "); + sb.append(option.type()); + sb.append("\noption_data: "); + sb.append(bytesToHex(option.data())); + }); + } else if (payload instanceof Redirect) { + final Redirect rd = (Redirect) payload; + sb.append("\nrd_target_addr: "); + sb.append(Ip6Address.valueOf(rd.getTargetAddress()).toString()); + rd.getOptions().forEach(option -> { + sb.append("\noption_type: "); + sb.append(option.type()); + sb.append("\noption_data: "); + sb.append(bytesToHex(option.data())); + }); + } + } } - } else if (pkt instanceof DHCP) { sb.append("\ndhcp packet"); } else if (pkt instanceof Data) { diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/Bandwidth.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/Bandwidth.java index 349e660f..60806568 100644 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/Bandwidth.java +++ b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/Bandwidth.java @@ -41,6 +41,17 @@ public final class Bandwidth implements RichComparable { this.bps = 0; } + /** + * Creates a new instance with given bandwidth. + * + * @param v bandwidth value + * @param unit {@link DataRateUnit} of {@code v} + * @return {@link Bandwidth} instance with given bandwidth + */ + public static Bandwidth of(double v, DataRateUnit unit) { + return new Bandwidth(unit.toBitsPerSecond(v)); + } + /** * Creates a new instance with given bandwidth in bps. * diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/DataRateUnit.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/DataRateUnit.java new file mode 100644 index 00000000..d49ed7b5 --- /dev/null +++ b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/DataRateUnit.java @@ -0,0 +1,64 @@ +package org.onlab.util; + +import com.google.common.annotations.Beta; + +/** + * Data rate unit. + */ +@Beta +public enum DataRateUnit { + /** + * Bit per second. + */ + BPS(1L), + /** + * Kilobit per second. + * (Decimal/SI) + */ + KBPS(1_000L), + /** + * Megabit per second. + * (Decimal/SI) + */ + MBPS(1_000_000L), + /** + * Gigabit per second. + * (Decimal/SI) + */ + GBPS(1_000_000_000L); + + private final long multiplier; + + DataRateUnit(long multiplier) { + this.multiplier = multiplier; + } + + /** + * Returns the multiplier to use, when converting value of this unit to bps. + * + * @return multiplier + */ + public long multiplier() { + return multiplier; + } + + /** + * Converts given value in this unit to bits per seconds. + * + * @param v data rate value + * @return {@code v} in bits per seconds + */ + public long toBitsPerSecond(long v) { + return v * multiplier; + } + + /** + * Converts given value in this unit to bits per seconds. + * + * @param v data rate value + * @return {@code v} in bits per seconds + */ + public double toBitsPerSecond(double v) { + return v * multiplier; + } +} 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 db7224ad..8a409c3d 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 @@ -31,7 +31,10 @@ import static org.onlab.junit.TestTools.assertAfter; public class AbstractAccumulatorTest { - private final ManuallyAdvancingTimer timer = new ManuallyAdvancingTimer(); + private final ManuallyAdvancingTimer timer = new ManuallyAdvancingTimer(true); + + private static final int LONG_REAL_TIME_DELAY = 30; + private static final int SHORT_REAL_TIME_DELAY = 5; @Test @@ -52,7 +55,7 @@ public class AbstractAccumulatorTest { accumulator.add(new TestItem("d")); assertTrue("should not have fired yet", accumulator.batch.isEmpty()); accumulator.add(new TestItem("e")); - timer.advanceTimeMillis(20, 10); + timer.advanceTimeMillis(20, LONG_REAL_TIME_DELAY); assertFalse("should have fired", accumulator.batch.isEmpty()); assertEquals("incorrect batch", "abcde", accumulator.batch); } @@ -61,16 +64,16 @@ public class AbstractAccumulatorTest { public void timeTrigger() { TestAccumulator accumulator = new TestAccumulator(); accumulator.add(new TestItem("a")); - timer.advanceTimeMillis(30, 1); + timer.advanceTimeMillis(30, SHORT_REAL_TIME_DELAY); assertTrue("should not have fired yet", accumulator.batch.isEmpty()); accumulator.add(new TestItem("b")); - timer.advanceTimeMillis(30, 1); + timer.advanceTimeMillis(30, SHORT_REAL_TIME_DELAY); assertTrue("should not have fired yet", accumulator.batch.isEmpty()); accumulator.add(new TestItem("c")); - timer.advanceTimeMillis(30, 1); + timer.advanceTimeMillis(30, SHORT_REAL_TIME_DELAY); assertTrue("should not have fired yet", accumulator.batch.isEmpty()); accumulator.add(new TestItem("d")); - timer.advanceTimeMillis(10, 10); + timer.advanceTimeMillis(10, LONG_REAL_TIME_DELAY); assertFalse("should have fired", accumulator.batch.isEmpty()); assertEquals("incorrect batch", "abcd", accumulator.batch); } @@ -81,7 +84,7 @@ public class AbstractAccumulatorTest { accumulator.add(new TestItem("a")); assertTrue("should not have fired yet", accumulator.batch.isEmpty()); accumulator.add(new TestItem("b")); - timer.advanceTimeMillis(70, 10); + timer.advanceTimeMillis(70, LONG_REAL_TIME_DELAY); assertFalse("should have fired", accumulator.batch.isEmpty()); assertEquals("incorrect batch", "ab", accumulator.batch); } @@ -93,10 +96,10 @@ public class AbstractAccumulatorTest { accumulator.add(new TestItem("a")); assertTrue("should not have fired yet", accumulator.batch.isEmpty()); accumulator.add(new TestItem("b")); - timer.advanceTimeMillis(80, 1); + timer.advanceTimeMillis(80, SHORT_REAL_TIME_DELAY); assertTrue("should not have fired yet", accumulator.batch.isEmpty()); accumulator.ready = true; - timer.advanceTimeMillis(80, 10); + timer.advanceTimeMillis(80, LONG_REAL_TIME_DELAY); assertFalse("should have fired", accumulator.batch.isEmpty()); assertEquals("incorrect batch", "ab", accumulator.batch); } @@ -105,12 +108,12 @@ public class AbstractAccumulatorTest { public void readyLongTrigger() { TestAccumulator accumulator = new TestAccumulator(); accumulator.ready = false; - timer.advanceTimeMillis(120, 1); + timer.advanceTimeMillis(120, SHORT_REAL_TIME_DELAY); assertTrue("should not have fired yet", accumulator.batch.isEmpty()); accumulator.add(new TestItem("a")); assertTrue("should not have fired yet", accumulator.batch.isEmpty()); accumulator.ready = true; - timer.advanceTimeMillis(120, 10); + timer.advanceTimeMillis(120, LONG_REAL_TIME_DELAY); assertFalse("should have fired", accumulator.batch.isEmpty()); assertEquals("incorrect batch", "a", accumulator.batch); } @@ -128,7 +131,7 @@ public class AbstractAccumulatorTest { assertTrue("should not have fired yet", accumulator.batch.isEmpty()); accumulator.ready = true; accumulator.add(new TestItem("g")); - timer.advanceTimeMillis(10, 10); + timer.advanceTimeMillis(10, LONG_REAL_TIME_DELAY); assertFalse("should have fired", accumulator.batch.isEmpty()); assertEquals("incorrect batch", "abcdefg", accumulator.batch); } 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 index 4116cbef..8fb008e8 100644 --- 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 @@ -65,6 +65,14 @@ public class ManuallyAdvancingTimer extends java.util.Timer { /* Data structure for tracking tasks */ private final TaskQueue queue = new TaskQueue(); + /* Whether execution should execute on the executor thread or the calling thread. */ + private final boolean runLocally; + + public ManuallyAdvancingTimer(boolean runLocally) { + this.runLocally = runLocally; + } + + @Override public void schedule(TimerTask task, long delay) { if (!staticsPopulated) { @@ -165,14 +173,16 @@ public class ManuallyAdvancingTimer extends java.util.Timer { /** * Advances the virtual time a certain number of millis triggers execution delays a certain amount to - * allow time for execution. + * allow time for execution. If runLocally is true then all real time delays are ignored. * * @param virtualTimeAdvance the time to be advances in millis of simulated time. * @param realTimeDelay the time to delay in real time to allow for processing. */ public void advanceTimeMillis(long virtualTimeAdvance, int realTimeDelay) { timerKeeper.advanceTimeMillis(virtualTimeAdvance); - delay(realTimeDelay); + if (!runLocally) { + delay(realTimeDelay); + } } /** @@ -238,7 +248,11 @@ public class ManuallyAdvancingTimer extends java.util.Timer { e.printStackTrace(); return false; } - executorService.execute(task); + if (runLocally) { + task.run(); + } else { + executorService.execute(task); + } return true; } else { //Calculate next execution time, using absolute value of period @@ -253,7 +267,11 @@ public class ManuallyAdvancingTimer extends java.util.Timer { } //Schedule next execution queue.insertOrdered(task); - executorService.execute(task); + if (runLocally) { + task.run(); + } else { + executorService.execute(task); + } return true; } } 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 index b8e1e85e..36b50e67 100644 --- 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 @@ -47,14 +47,14 @@ public class ManuallyAdvancingTimerTest { private AtomicInteger tasksRunCount; // FIXME if this class fails first try increasing the real time delay to account for heavy system load. - private static final int REAL_TIME_DELAY = 1; + private static final int REAL_TIME_DELAY = 10; /** * Sets up the testing environment. */ @Before public void setup() { - timer = new ManuallyAdvancingTimer(); + timer = new ManuallyAdvancingTimer(true); idGenerator = new AtomicInteger(1); tasksRunCount = new AtomicInteger(0); taskList = Lists.newArrayList(); diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Main.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Main.java index bc10ec7a..ca04a7c2 100644 --- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Main.java +++ b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Main.java @@ -16,13 +16,16 @@ package org.onlab.stc; import com.google.common.collect.ImmutableList; +import com.google.common.io.Files; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.ServletHandler; import org.eclipse.jetty.util.log.Logger; import org.onlab.stc.Coordinator.Status; +import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; +import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; @@ -64,10 +67,12 @@ public final class Main { private String runToPatterns = ""; private Coordinator coordinator; + private Compiler compiler; private Monitor monitor; private Listener delegate = new Listener(); private static boolean useColor = Objects.equals("true", System.getenv("stcColor")); + private static boolean dumpLogs = Objects.equals("true", System.getenv("stcDumpLogs")); // usage: stc [] [run] // usage: stc [] run [from ] [to ]] @@ -113,7 +118,7 @@ public final class Main { Scenario scenario = Scenario.loadScenario(new FileInputStream(scenarioFile)); // Elaborate scenario - Compiler compiler = new Compiler(scenario); + compiler = new Compiler(scenario); compiler.compile(); // Setup the process flow coordinator @@ -221,7 +226,7 @@ public final class Main { /** * Internal delegate to monitor the process execution. */ - private static class Listener implements StepProcessListener { + private class Listener implements StepProcessListener { @Override public void onStart(Step step, String command) { logStatus(currentTimeMillis(), step.name(), IN_PROGRESS, command); @@ -230,6 +235,9 @@ public final class Main { @Override public void onCompletion(Step step, Status status) { logStatus(currentTimeMillis(), step.name(), status, null); + if (dumpLogs && !(step instanceof Group) && status == FAILED) { + dumpLogs(step); + } } @Override @@ -246,6 +254,18 @@ public final class Main { } } + // Dumps the step logs to standard output. + private void dumpLogs(Step step) { + File logFile = new File(compiler.logDir(), step.name() + ".log"); + try { + print(">>>>>"); + Files.copy(logFile, System.out); + print("<<<<<"); + } catch (IOException e) { + print("Unable to dump log file %s", logFile.getName()); + } + } + // Produces a description of event using the specified step status. private static String action(Status status) { return status == IN_PROGRESS ? "started" : diff --git a/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/ClusterWebResource.java b/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/ClusterWebResource.java index dd9b9fc3..312f6e35 100644 --- a/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/ClusterWebResource.java +++ b/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/ClusterWebResource.java @@ -84,10 +84,9 @@ public class ClusterWebResource extends AbstractWebResource { public Response formCluster(InputStream config) throws IOException { JsonCodec codec = codec(ControllerNode.class); ObjectNode root = (ObjectNode) mapper().readTree(config); - String ipPrefix = root.path("ipPrefix").asText(); List nodes = codec.decode((ArrayNode) root.path("nodes"), this); - get(ClusterAdminService.class).formCluster(new HashSet<>(nodes), ipPrefix); + get(ClusterAdminService.class).formCluster(new HashSet<>(nodes)); return Response.ok().build(); } diff --git a/framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandler.java b/framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandler.java index 8acdc2cf..82b7a782 100644 --- a/framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandler.java +++ b/framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandler.java @@ -27,12 +27,14 @@ import org.onosproject.cluster.ClusterEventListener; import org.onosproject.cluster.ControllerNode; import org.onosproject.core.ApplicationId; import org.onosproject.core.CoreService; +import org.onosproject.core.DefaultApplicationId; import org.onosproject.event.Event; import org.onosproject.mastership.MastershipAdminService; import org.onosproject.mastership.MastershipEvent; import org.onosproject.mastership.MastershipListener; import org.onosproject.net.ConnectPoint; import org.onosproject.net.Device; +import org.onosproject.net.DeviceId; import org.onosproject.net.Host; import org.onosproject.net.HostId; import org.onosproject.net.HostLocation; @@ -48,11 +50,14 @@ import org.onosproject.net.flow.TrafficTreatment; import org.onosproject.net.host.HostEvent; import org.onosproject.net.host.HostListener; import org.onosproject.net.intent.HostToHostIntent; +import org.onosproject.net.intent.Intent; import org.onosproject.net.intent.IntentEvent; import org.onosproject.net.intent.IntentListener; +import org.onosproject.net.intent.Key; import org.onosproject.net.intent.MultiPointToSinglePointIntent; import org.onosproject.net.link.LinkEvent; import org.onosproject.net.link.LinkListener; +import org.onosproject.ui.JsonUtils; import org.onosproject.ui.RequestHandler; import org.onosproject.ui.UiConnection; import org.onosproject.ui.impl.TrafficMonitor.Mode; @@ -76,7 +81,9 @@ import static org.onlab.util.Tools.groupedThreads; import static org.onosproject.cluster.ClusterEvent.Type.INSTANCE_ADDED; import static org.onosproject.net.DeviceId.deviceId; import static org.onosproject.net.HostId.hostId; -import static org.onosproject.net.device.DeviceEvent.Type.*; +import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_ADDED; +import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_UPDATED; +import static org.onosproject.net.device.DeviceEvent.Type.PORT_STATS_UPDATED; import static org.onosproject.net.host.HostEvent.Type.HOST_ADDED; import static org.onosproject.net.link.LinkEvent.Type.LINK_ADDED; import static org.onosproject.ui.JsonUtils.envelope; @@ -97,6 +104,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { private static final String REQ_NEXT_INTENT = "requestNextRelatedIntent"; private static final String REQ_PREV_INTENT = "requestPrevRelatedIntent"; private static final String REQ_SEL_INTENT_TRAFFIC = "requestSelectedIntentTraffic"; + private static final String SEL_INTENT = "selectIntent"; private static final String REQ_ALL_FLOW_TRAFFIC = "requestAllFlowTraffic"; private static final String REQ_ALL_PORT_TRAFFIC = "requestAllPortTraffic"; private static final String REQ_DEV_LINK_FLOWS = "requestDeviceLinkFlows"; @@ -117,9 +125,13 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { private static final String SPRITE_LIST_RESPONSE = "spriteListResponse"; private static final String SPRITE_DATA_RESPONSE = "spriteDataResponse"; private static final String UPDATE_INSTANCE = "updateInstance"; + private static final String TOPO_START_DONE = "topoStartDone"; // fields private static final String ID = "id"; + private static final String KEY = "key"; + private static final String APP_ID = "appId"; + private static final String APP_NAME = "appName"; private static final String DEVICE = "device"; private static final String HOST = "host"; private static final String CLASS = "class"; @@ -135,7 +147,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { private static final String DEACTIVATE = "deactivate"; - private static final String APP_ID = "org.onosproject.gui"; + private static final String MY_APP_ID = "org.onosproject.gui"; private static final long TRAFFIC_PERIOD = 5000; private static final long SUMMARY_PERIOD = 30000; @@ -176,7 +188,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { @Override public void init(UiConnection connection, ServiceDirectory directory) { super.init(connection, directory); - appId = directory.get(CoreService.class).registerApplication(APP_ID); + appId = directory.get(CoreService.class).registerApplication(MY_APP_ID); traffic = new TrafficMonitor(TRAFFIC_PERIOD, servicesBundle, this); } @@ -213,6 +225,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { new ReqNextIntent(), new ReqPrevIntent(), new ReqSelectedIntentTraffic(), + new SelIntent(), new CancelTraffic() ); @@ -241,6 +254,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { sendAllDevices(); sendAllLinks(); sendAllHosts(); + sendTopoStartDone(); } } @@ -344,11 +358,13 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { PropertyPanel pp = null; if (type.equals(DEVICE)) { - pp = deviceDetails(deviceId(id), sid); - overlayCache.currentOverlay().modifyDeviceDetails(pp); + DeviceId did = deviceId(id); + pp = deviceDetails(did, sid); + overlayCache.currentOverlay().modifyDeviceDetails(pp, did); } else if (type.equals(HOST)) { - pp = hostDetails(hostId(id), sid); - overlayCache.currentOverlay().modifyHostDetails(pp); + HostId hid = hostId(id); + pp = hostDetails(hid, sid); + overlayCache.currentOverlay().modifyHostDetails(pp, hid); } sendMessage(envelope(SHOW_DETAILS, sid, json(pp))); @@ -524,6 +540,31 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { } } + private final class SelIntent extends RequestHandler { + private SelIntent() { + super(SEL_INTENT); + } + + @Override + public void process(long sid, ObjectNode payload) { + int appId = Integer.parseInt(string(payload, APP_ID)); + String appName = string(payload, APP_NAME); + ApplicationId applicId = new DefaultApplicationId(appId, appName); + long intentKey = Long.decode(string(payload, KEY)); + + Key key = Key.of(intentKey, applicId); + log.debug("Attempting to select intent key={}", key); + + Intent intent = intentService.getIntent(key); + if (intent == null) { + log.debug("no such intent found!"); + } else { + log.debug("starting to monitor intent {}", key); + traffic.monitor(intent); + } + } + } + private final class CancelTraffic extends RequestHandler { private CancelTraffic() { super(CANCEL_TRAFFIC); @@ -623,6 +664,9 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { return hostIds; } + private void sendTopoStartDone() { + sendMessage(JsonUtils.envelope(TOPO_START_DONE, objectNode())); + } private synchronized void startSummaryMonitoring() { stopSummaryMonitoring(); diff --git a/framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/TrafficOverlay.java b/framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/TrafficOverlay.java index ea8ca3ea..f4b5598d 100644 --- a/framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/TrafficOverlay.java +++ b/framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/TrafficOverlay.java @@ -17,6 +17,7 @@ package org.onosproject.ui.impl; +import org.onosproject.net.DeviceId; import org.onosproject.ui.UiTopoOverlay; import org.onosproject.ui.topo.ButtonId; import org.onosproject.ui.topo.PropertyPanel; @@ -55,7 +56,7 @@ public class TrafficOverlay extends UiTopoOverlay { } @Override - public void modifyDeviceDetails(PropertyPanel pp) { + public void modifyDeviceDetails(PropertyPanel pp, DeviceId deviceId) { pp.addButton(SHOW_DEVICE_FLOWS) .addButton(SHOW_RELATED_TRAFFIC); } diff --git a/framework/src/onos/web/gui/src/main/webapp/app/fw/layer/panel.css b/framework/src/onos/web/gui/src/main/webapp/app/fw/layer/panel.css index 46dbdb52..ded05cf1 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/fw/layer/panel.css +++ b/framework/src/onos/web/gui/src/main/webapp/app/fw/layer/panel.css @@ -34,6 +34,10 @@ border-radius: 6px; } +.floatpanel.dialog { + top: 180px; +} + html[data-platform='iPad'] .floatpanel { top: 80px; } diff --git a/framework/src/onos/web/gui/src/main/webapp/app/fw/layer/panel.js b/framework/src/onos/web/gui/src/main/webapp/app/fw/layer/panel.js index aef71eee..10f04813 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/fw/layer/panel.js +++ b/framework/src/onos/web/gui/src/main/webapp/app/fw/layer/panel.js @@ -171,7 +171,10 @@ } angular.module('onosLayer') - .factory('PanelService', ['$log', 'FnService', function (_$log_, _fs_) { + .factory('PanelService', + ['$log', '$window', 'FnService', + + function (_$log_, _$window_, _fs_) { $log = _$log_; fs = _fs_; @@ -210,5 +213,4 @@ destroyPanel: destroyPanel }; }]); - }()); 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 15b44bc9..12536361 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 @@ -37,6 +37,8 @@ play: 'play', stop: 'stop', + topo: 'topo', + refresh: 'refresh', garbage: 'garbage', diff --git a/framework/src/onos/web/gui/src/main/webapp/app/fw/widget/table.css b/framework/src/onos/web/gui/src/main/webapp/app/fw/widget/table.css index 18b81ba6..356ac0f7 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/fw/widget/table.css +++ b/framework/src/onos/web/gui/src/main/webapp/app/fw/widget/table.css @@ -81,7 +81,7 @@ div.summary-list tr.no-data td { } .light div.summary-list tr.selected { - background-color: deepskyblue; + background-color: deepskyblue !important; } .dark div.summary-list tr.selected { diff --git a/framework/src/onos/web/gui/src/main/webapp/app/fw/widget/tableBuilder.js b/framework/src/onos/web/gui/src/main/webapp/app/fw/widget/tableBuilder.js index 24161bbb..6a5ffb1f 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/fw/widget/tableBuilder.js +++ b/framework/src/onos/web/gui/src/main/webapp/app/fw/widget/tableBuilder.js @@ -47,6 +47,7 @@ resp = o.tag + 'DataResponse', onSel = fs.isF(o.selCb), onResp = fs.isF(o.respCb), + idKey = o.idKey || 'id', oldTableData = [], loaded = false, refreshPromise, loadingPromise; @@ -104,7 +105,8 @@ // === selecting a row functions ---------------- function selCb($event, selRow) { - o.scope.selId = (o.scope.selId === selRow.id) ? null : selRow.id; + var selId = selRow[idKey]; + o.scope.selId = (o.scope.selId === selId) ? null : selId; onSel && onSel($event, selRow); } o.scope.selectCallback = selCb; diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/intent/intent.css b/framework/src/onos/web/gui/src/main/webapp/app/view/intent/intent.css index ed9cd48d..dfa50c37 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/view/intent/intent.css +++ b/framework/src/onos/web/gui/src/main/webapp/app/view/intent/intent.css @@ -23,7 +23,6 @@ } #ov-intent div.ctrl-btns { - width: 45px; } .light #ov-intent tr:nth-child(6n + 1), diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/intent/intent.html b/framework/src/onos/web/gui/src/main/webapp/app/view/intent/intent.html index 4883beed..98aa5659 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/view/intent/intent.html +++ b/framework/src/onos/web/gui/src/main/webapp/app/view/intent/intent.html @@ -1,24 +1,13 @@ - -

Intents ({{tableData.length}} total)

+
+
{{intent.appId}} {{intent.key}} @@ -58,10 +49,14 @@ {{intent.priority}} {{intent.state}} - + {{intent.resources}} - + {{intent.details}} diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/intent/intent.js b/framework/src/onos/web/gui/src/main/webapp/app/view/intent/intent.js index 5810f347..19f2c076 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/view/intent/intent.js +++ b/framework/src/onos/web/gui/src/main/webapp/app/view/intent/intent.js @@ -23,14 +23,37 @@ angular.module('ovIntent', []) .controller('OvIntentCtrl', - ['$log', '$scope', 'TableBuilderService', + ['$log', '$scope', 'TableBuilderService', 'NavService', - function ($log, $scope, tbs) { - tbs.buildTable({ - scope: $scope, - tag: 'intent' - }); + function ($log, $scope, tbs, ns) { - $log.log('OvIntentCtrl has been created'); - }]); + function selCb($event, row) { + $log.debug('Got a click on:', row); + var m = /(\d+)\s:\s(.*)/.exec(row.appId), + id = m ? m[1] : null, + name = m ? m[2] : null; + + $scope.intentData = ($scope.selId && m) ? { + intentAppId: id, + intentAppName: name, + intentKey: row.key + } : null; + } + + tbs.buildTable({ + scope: $scope, + tag: 'intent', + selCb: selCb, + idKey: 'key' + }); + + $scope.topoTip = 'Show selected intent on topology view'; + + $scope.showIntent = function () { + var d = $scope.intentData; + d && ns.navTo('topo', d); + }; + + $log.log('OvIntentCtrl has been created'); + }]); }()); diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topo.css b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topo.css index f4b089a0..dda6d5c6 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topo.css +++ b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topo.css @@ -96,6 +96,24 @@ html[data-platform='iPad'] #topo-p-detail { height: 30px; } +/* --- Topo Dialog Panel --- */ + +#topo-p-dialog .dialog-button { + display: inline-block; + cursor: pointer; + height: 20px; + padding: 2px 6px; + margin: 4px; + float: right; +} + +.light #topo-p-dialog .dialog-button { + background-color: #fec; +} +.dark #topo-p-dialog .dialog-button { + background-color: #369; +} + /* --- general topo-panel styling --- */ .topo-p div.header div.icon { @@ -427,6 +445,39 @@ html[data-platform='iPad'] #topo-p-detail { fill: #f90; } +/* Badges */ +/* (... works for both light and dark themes...) */ +#ov-topo svg .node .badge circle { + stroke: #aaa; +} + +#ov-topo svg .node .badge.badgeInfo circle { + fill: #ccf; +} + +#ov-topo svg .node .badge.badgeWarn circle { + fill: #da2; +} + +#ov-topo svg .node .badge.badgeError circle { + fill: #e44; +} + +#ov-topo svg .node .badge use { + fill: white; +} + +#ov-topo svg .node .badge.badgeInfo use { + fill: #448; +} + +#ov-topo svg .node .badge text { + fill: white; +} + +#ov-topo svg .node .badge.badgeInfo text { + fill: #448; +} /* Host Nodes */ 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 0dfd6281..7ddfd136 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 @@ -412,6 +412,12 @@ flash.enable(true); } + function topoStartDone() { + var d = $scope.intentData; + if (d) { + tts.selectIntent(d); + } + } // --- Controller Definition ----------------------------------------- @@ -430,7 +436,8 @@ _zs_, _gs_, _ms_, _sus_, _flash_, _wss_, _ps_, _tes_, _tfs_, _tps_, _tis_, _tss_, _tls_, _tts_, _tos_, _fltr_, _ttbs_, tspr, _ttip_, _tov_) { - var projection, + var params = $loc.search(), + projection, dim, uplink = { // provides function calls back into this space @@ -438,7 +445,8 @@ projection: function () { return projection; }, zoomLayer: function () { return zoomLayer; }, zoomer: function () { return zoomer; }, - opacifyMap: opacifyMap + opacifyMap: opacifyMap, + topoStartDone: topoStartDone }; $scope = _$scope_; @@ -469,6 +477,14 @@ ttip = _ttip_; tov = _tov_; + if (params.intentKey && params.intentAppId && params.intentAppName) { + $scope.intentData = { + key: params.intentKey, + appId: params.intentAppId, + appName: params.intentAppName + }; + } + $scope.notifyResize = function () { svgResized(fs.windowSize(mast.mastHeight())); }; diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoD3.js b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoD3.js index 1f061dd6..1d2c5b10 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoD3.js +++ b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoD3.js @@ -55,8 +55,23 @@ height: 14 } }, + badgeConfig = { + radius: 12, + yoff: 5, + gdelta: 10 + }, icfg; + var status = { + i: 'badgeInfo', + w: 'badgeWarn', + e: 'badgeError' + }; + + function badgeStatus(badge) { + return status[badge.status] || status.i; + } + // internal state var deviceLabelIndex = 0, hostLabelIndex = 0; @@ -186,12 +201,15 @@ } - function updateDeviceLabel(d) { + function updateDeviceRendering(d) { var label = trimLabel(deviceLabel(d)), noLabel = !label, node = d.el, dim = icfg.device.dim, - box, dx, dy; + box, dx, dy, bsel, + bdg = d.badge, + bcr = badgeConfig.radius, + bcgd = badgeConfig.gdelta; node.select('text') .text(label) @@ -216,23 +234,34 @@ node.select('g.deviceIcon') .transition() .attr('transform', sus.translate(dx, dy)); - } - function updateDeviceBadge(d) { - // TODO: Fix this WIP - var node = d.el, - bsel; + // handle badge, if defined + if (bdg) { + node.select('g.badge').remove(); - if (d.badge) { bsel = node.append('g') .classed('badge', true) - .attr('transform', sus.translate(-14, -14)); + .classed(badgeStatus(bdg), true) + .attr('transform', sus.translate(dx + dim, dy)); bsel.append('circle') - .attr('r', 14); - bsel.append('text') - .attr('transform', sus.translate(-5, 3)) - .text('42'); + .attr('r', bcr); + + if (bdg.txt) { + bsel.append('text') + .attr('dy', badgeConfig.yoff) + .attr('text-anchor', 'middle') + .text(bdg.txt); + } else if (bdg.gid) { + bsel.append('use') + .attr({ + width: bcgd * 2, + height: bcgd * 2, + transform: sus.translate(-bcgd, -bcgd), + 'xlink:href': '#' + bdg.gid + }); + + } } } @@ -258,8 +287,7 @@ function deviceExisting(d) { var node = d.el; node.classed('online', d.online); - updateDeviceLabel(d); - updateDeviceBadge(d); + updateDeviceRendering(d); api.posNode(d, true); } @@ -574,7 +602,7 @@ deviceLabel: deviceLabel, trimLabel: trimLabel, - updateDeviceLabel: updateDeviceLabel, + updateDeviceLabel: updateDeviceRendering, updateHostLabel: updateHostLabel, updateDeviceColors: updateDeviceColors, diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoDialog.js b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoDialog.js new file mode 100644 index 00000000..93079183 --- /dev/null +++ b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoDialog.js @@ -0,0 +1,183 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + ONOS GUI -- Topology Dialog Module. + Defines functions for manipulating a dialog box. + */ + +(function () { + 'use strict'; + + // injected refs + var $log, $window, $rootScope, fs, ps, bns; + + // constants + var pCls = 'topo-p dialog', + idDialog = 'topo-p-dialog', + panelOpts = { + width: 300, + edge: 'left' + }; + + // internal state + var pApi, panel, dApi; + + // TODO: ESC key invokes Cancel callback + // TODO: Enter invokes OK callback + + // create the dialog; return its API + function createDialog() { + var header, body, footer, + p = ps.createPanel(idDialog, panelOpts); + p.classed(pCls, true); + panel = p; + + function reset() { + p.empty(); + p.append('div').classed('header', true); + p.append('div').classed('body', true); + p.append('div').classed('footer', true); + + header = p.el().select('.header'); + body = p.el().select('.body'); + footer = p.el().select('.footer'); + } + + function hAppend(x) { + if (typeof x === 'string') { + return header.append(x); + } + header.node().appendChild(x.node()); + return header; + } + + function bAppend(x) { + if (typeof x === 'string') { + return body.append(x); + } + body.node().appendChild(x.node()); + return body; + } + + function fAppend(x) { + if (typeof x === 'string') { + return footer.append(x); + } + footer.node().appendChild(x.node()); + return footer; + } + + function destroy() { + ps.destroyPanel(idDialog); + } + + return { + reset: reset, + appendHeader: hAppend, + appendBody: bAppend, + appendFooter: fAppend, + destroy: destroy + }; + } + + function makeButton(text, callback) { + var cb = fs.isF(callback); + + function invoke() { + cb && cb(); + panel.hide(); + } + return createDiv('dialog-button') + .text(text) + .on('click', invoke); + } + + function addContent(content) { + if (pApi) { + pApi.appendBody(content); + } + return dApi; + } + + function addButton(text, cb) { + if (pApi) { + pApi.appendFooter(makeButton(text, cb)); + } + return dApi; + } + + // opens the dialog (creates if necessary) + function openDialog() { + $log.debug('Open DIALOG'); + if (!pApi) { + pApi = createDialog(); + } + pApi.reset(); + pApi.appendHeader('h2').text('=dialog='); + panel.show(); + + // return the dialog object API + dApi = { + addContent: addContent, + addButton: addButton + }; + return dApi; + } + + // closes the dialog (destroying panel) + function closeDialog() { + $log.debug('Close DIALOG'); + if (pApi) { + panel.hide(); + pApi.destroy(); + pApi = null; + dApi = null; + } + } + + // creates a detached div, returning D3 selection + // optional CSS class may be provided + function createDiv(cls) { + var div = d3.select(document.createElement('div')); + if (cls) { + div.classed(cls, true); + } + return div; + } + + // ========================== + + angular.module('ovTopo') + .factory('TopoDialogService', + ['$log', '$window', '$rootScope', 'FnService', 'PanelService', 'ButtonService', + + function (_$log_, _$window_, _$rootScope_, + _fs_, _ps_, _bns_) { + $log = _$log_; + $window = _$window_; + $rootScope = _$rootScope_; + fs = _fs_; + ps = _ps_; + bns = _bns_; + + return { + openDialog: openDialog, + closeDialog: closeDialog, + createDiv: createDiv + }; + }]); +}()); diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoEvent.js b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoEvent.js index 5fd38bf6..2957629a 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoEvent.js +++ b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoEvent.js @@ -60,6 +60,8 @@ updateLink: tfs, removeLink: tfs, + topoStartDone: tfs, + spriteListResponse: tspr, spriteDataResponse: tspr }; diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoForce.js b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoForce.js index f00b87fa..844d7dc9 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoForce.js +++ b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoForce.js @@ -240,6 +240,11 @@ } } + function topoStartDone(data) { + // called when the initial barrage of data has been sent from server + uplink.topoStartDone(); + } + // ======================== function nodeById(id) { @@ -1140,7 +1145,8 @@ removeHost: removeHost, addLink: addLink, updateLink: updateLink, - removeLink: removeLink + removeLink: removeLink, + topoStartDone: topoStartDone }; }]); }()); diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoOverlay.js b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoOverlay.js index 9a3b4358..2dee4c40 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoOverlay.js +++ b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoOverlay.js @@ -34,7 +34,8 @@ // internal state var overlays = {}, - current = null; + current = null, + reset = true; function error(fn, msg) { $log.error(tos + fn + '(): ' + msg); @@ -144,7 +145,8 @@ payload[op] = oid; } - if (!same) { + if (reset || !same) { + reset = false; current && doop('deactivate'); current = overlays[id]; current && doop('activate'); @@ -390,6 +392,7 @@ tbSelection: tbSelection, installButtons: installButtons, addDetailButton: addDetailButton, + resetOnToolbarDestroy: function () { reset = true; }, hooks: { escape: escapeHook, emptySelect: emptySelectHook, diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoSelect.js b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoSelect.js index 483c4baa..4ad76903 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoSelect.js +++ b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoSelect.js @@ -240,6 +240,33 @@ return cc; } + // returns a selection context, providing info about what is selected + function selectionContext() { + var devices = [], + hosts = [], + types = {}; + + angular.forEach(selections, function (d) { + var o = d.obj, + c = o.class; + + if (c === 'device') { + devices.push(o.id); + types[o.id] = o.type; + } + if (c === 'host') { + hosts.push(o.id); + types[o.id] = o.type; + } + }); + + return { + devices: devices, + hosts: hosts, + types: types + }; + } + // === ----------------------------------------------------- // === MODULE DEFINITION === @@ -280,7 +307,8 @@ selectOrder: function () { return selectOrder; }, somethingSelected: somethingSelected, - clickConsumed: clickConsumed + clickConsumed: clickConsumed, + selectionContext: selectionContext }; }]); }()); diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoToolbar.js b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoToolbar.js index 3928cd21..06285442 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoToolbar.js +++ b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoToolbar.js @@ -243,6 +243,7 @@ function destroyToolbar() { tbs.destroyToolbar(name); + tov.resetOnToolbarDestroy(); } // allows us to ensure the button states track key strokes diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoTraffic.js b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoTraffic.js index ca379360..ff690c49 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoTraffic.js +++ b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoTraffic.js @@ -152,6 +152,14 @@ } } + // force the system to create a single intent selection + function selectIntent(data) { + trafficMode = 'intents'; + hoverMode = null; + wss.sendEvent('selectIntent', data); + flash.flash('Selecting Intent ' + data.key); + } + // === ------------------------------------------------------ // action buttons on detail panel (multiple selection) @@ -207,6 +215,7 @@ showPrevIntent: showPrevIntent, showNextIntent: showNextIntent, showSelectedIntentTraffic: showSelectedIntentTraffic, + selectIntent: selectIntent, // invoked from mouseover/mouseout and selection change requestTrafficForMode: requestTrafficForMode, 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 5df3c664..7e0d9b7d 100644 --- a/framework/src/onos/web/gui/src/main/webapp/index.html +++ b/framework/src/onos/web/gui/src/main/webapp/index.html @@ -98,6 +98,7 @@ + diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_10_showHighlights_stuff.json b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_10_showHighlights_stuff.json new file mode 100644 index 00000000..4f35403f --- /dev/null +++ b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_10_showHighlights_stuff.json @@ -0,0 +1,63 @@ +{ + "event": "showHighlights", + "payload": { + "devices": [ + { + "id": "of:0000000000000001", + "badge": { + "status": "i", + "gid": "xMark", + "msg": "x marks the spot" + } + }, + { + "id": "of:0000000000000002", + "badge": { + "status": "w", + "gid": "crown", + "msg": "it's good to be the King" + } + }, + { + "id": "of:0000000000000003", + "badge": { + "status": "e", + "gid": "chain", + "msg": "the weakest link" + } + }, + { + "id": "of:0000000000000004", + "badge": { + "status": "i", + "txt": "1", + "msg": "singular sensation" + } + }, + { + "id": "of:0000000000000005", + "badge": { + "status": "w", + "txt": "42", + "msg": "life, the universe, and everything!" + } + }, + { + "id": "of:0000000000000006", + "badge": { + "status": "e", + "txt": "99", + "msg": "cadbury's flake" + } + } + ], + "hosts": [], + "links": [ + { + "css": "primary", + "id": "of:0000000000000001/5-of:0000000000000002/7", + "label": "Foo!" + } + ] + } +} diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_11_showHighlights_clear.json b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_11_showHighlights_clear.json new file mode 100644 index 00000000..615efd25 --- /dev/null +++ b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_11_showHighlights_clear.json @@ -0,0 +1,8 @@ +{ + "event": "showHighlights", + "payload": { + "devices": [], + "hosts": [], + "links": [] + } +} diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_4_addDevice_s3.json b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_4_addDevice_s3.json new file mode 100644 index 00000000..57f3251b --- /dev/null +++ b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_4_addDevice_s3.json @@ -0,0 +1,18 @@ +{ + "event": "addDevice", + "payload": { + "id": "of:0000000000000003", + "type": "switch", + "online": true, + "master": "ONOS", + "labels": [ + "", + "switch-3", + "of:0000000000000003" + ], + "metaUi": { + "x": 600, + "y": 200 + } + } +} diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_4_addLink_1_2.json b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_4_addLink_1_2.json deleted file mode 100644 index fb952837..00000000 --- a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_4_addLink_1_2.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "event": "addLink", - "payload": { - "id": "of:0000000000000001/5-of:0000000000000002/7", - "type": "direct", - "online": true, - "linkWidth": 2, - "src": "of:0000000000000001", - "srcPort": "5", - "dst": "of:0000000000000002", - "dstPort": "7", - "props" : { - "BW": "70 Gb" - } - } -} diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_5_addDevice_s4.json b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_5_addDevice_s4.json new file mode 100644 index 00000000..bab00488 --- /dev/null +++ b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_5_addDevice_s4.json @@ -0,0 +1,18 @@ +{ + "event": "addDevice", + "payload": { + "id": "of:0000000000000004", + "type": "switch", + "online": true, + "master": "ONOS", + "labels": [ + "", + "switch-4", + "of:0000000000000004" + ], + "metaUi": { + "x": 200, + "y": 400 + } + } +} diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_5_showHighlights_clear.json b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_5_showHighlights_clear.json deleted file mode 100644 index 615efd25..00000000 --- a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_5_showHighlights_clear.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "event": "showHighlights", - "payload": { - "devices": [], - "hosts": [], - "links": [] - } -} diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_6_addDevice_s5.json b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_6_addDevice_s5.json new file mode 100644 index 00000000..6ee18080 --- /dev/null +++ b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_6_addDevice_s5.json @@ -0,0 +1,18 @@ +{ + "event": "addDevice", + "payload": { + "id": "of:0000000000000005", + "type": "switch", + "online": true, + "master": "ONOS", + "labels": [ + "", + "switch-5", + "of:0000000000000005" + ], + "metaUi": { + "x": 400, + "y": 420 + } + } +} diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_6_showHighlights_stuff.json b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_6_showHighlights_stuff.json deleted file mode 100644 index 74c42c5c..00000000 --- a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_6_showHighlights_stuff.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "event": "showHighlights", - "payload": { - "devices": [ - { - "id": "of:0000000000000001", - "badge": { - "status": "e", - "gid": "xMark", - "msg": "x marks the spot" - } - }, - { - "id": "of:0000000000000002", - "badge": { - "status": "w", - "txt": "7" - } - } - ], - "hosts": [], - "links": [ - { - "css": "primary", - "id": "of:0000000000000001/5-of:0000000000000002/7", - "label": "Antz!" - } - ] - } -} diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_7_addDevice_s6.json b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_7_addDevice_s6.json new file mode 100644 index 00000000..4554996e --- /dev/null +++ b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_7_addDevice_s6.json @@ -0,0 +1,18 @@ +{ + "event": "addDevice", + "payload": { + "id": "of:0000000000000006", + "type": "switch", + "online": true, + "master": "ONOS", + "labels": [ + "", + "switch-6", + "of:0000000000000006" + ], + "metaUi": { + "x": 600, + "y": 400 + } + } +} diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_7_showHighlights_clear.json b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_7_showHighlights_clear.json deleted file mode 100644 index 615efd25..00000000 --- a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_7_showHighlights_clear.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "event": "showHighlights", - "payload": { - "devices": [], - "hosts": [], - "links": [] - } -} diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_8_addLink_1_2.json b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_8_addLink_1_2.json new file mode 100644 index 00000000..fb952837 --- /dev/null +++ b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_8_addLink_1_2.json @@ -0,0 +1,16 @@ +{ + "event": "addLink", + "payload": { + "id": "of:0000000000000001/5-of:0000000000000002/7", + "type": "direct", + "online": true, + "linkWidth": 2, + "src": "of:0000000000000001", + "srcPort": "5", + "dst": "of:0000000000000002", + "dstPort": "7", + "props" : { + "BW": "70 Gb" + } + } +} diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_9_showHighlights_clear.json b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_9_showHighlights_clear.json new file mode 100644 index 00000000..615efd25 --- /dev/null +++ b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_9_showHighlights_clear.json @@ -0,0 +1,8 @@ +{ + "event": "showHighlights", + "payload": { + "devices": [], + "hosts": [], + "links": [] + } +} diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/badges/scenario.json b/framework/src/onos/web/gui/src/test/_karma/ev/badges/scenario.json index 0ca4f4f4..ae093d69 100644 --- a/framework/src/onos/web/gui/src/test/_karma/ev/badges/scenario.json +++ b/framework/src/onos/web/gui/src/test/_karma/ev/badges/scenario.json @@ -4,7 +4,7 @@ ], "title": "Demo adding badges", "params": { - "lastAuto": 5 + "lastAuto": 9 }, "description": [ "Demonstrate the device badging feature." -- cgit 1.2.3-korg