/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "test/network/network_emulation_manager.h" #include #include #include "api/units/time_delta.h" #include "api/units/timestamp.h" #include "call/simulated_network.h" #include "rtc_base/fake_network.h" #include "test/time_controller/real_time_controller.h" #include "test/time_controller/simulated_time_controller.h" namespace webrtc { namespace test { namespace { // uint32_t representation of 192.168.0.0 address constexpr uint32_t kMinIPv4Address = 0xC0A80000; // uint32_t representation of 192.168.255.255 address constexpr uint32_t kMaxIPv4Address = 0xC0A8FFFF; std::unique_ptr CreateTimeController(TimeMode mode) { switch (mode) { case TimeMode::kRealTime: return std::make_unique(); case TimeMode::kSimulated: // Using an offset of 100000 to get nice fixed width and readable // timestamps in typical test scenarios. const Timestamp kSimulatedStartTime = Timestamp::Seconds(100000); return std::make_unique( kSimulatedStartTime); } } } // namespace NetworkEmulationManagerImpl::NetworkEmulationManagerImpl(TimeMode mode) : time_controller_(CreateTimeController(mode)), clock_(time_controller_->GetClock()), next_node_id_(1), next_ip4_address_(kMinIPv4Address), task_queue_(time_controller_->GetTaskQueueFactory()->CreateTaskQueue( "NetworkEmulation", TaskQueueFactory::Priority::NORMAL)) {} // TODO(srte): Ensure that any pending task that must be run for consistency // (such as stats collection tasks) are not cancelled when the task queue is // destroyed. NetworkEmulationManagerImpl::~NetworkEmulationManagerImpl() = default; EmulatedNetworkNode* NetworkEmulationManagerImpl::CreateEmulatedNode( BuiltInNetworkBehaviorConfig config) { return CreateEmulatedNode(std::make_unique(config)); } EmulatedNetworkNode* NetworkEmulationManagerImpl::CreateEmulatedNode( std::unique_ptr network_behavior) { auto node = std::make_unique( clock_, &task_queue_, std::move(network_behavior)); EmulatedNetworkNode* out = node.get(); task_queue_.PostTask([this, node = std::move(node)]() mutable { network_nodes_.push_back(std::move(node)); }); return out; } NetworkEmulationManager::SimulatedNetworkNode::Builder NetworkEmulationManagerImpl::NodeBuilder() { return SimulatedNetworkNode::Builder(this); } EmulatedEndpoint* NetworkEmulationManagerImpl::CreateEndpoint( EmulatedEndpointConfig config) { absl::optional ip = config.ip; if (!ip) { switch (config.generated_ip_family) { case EmulatedEndpointConfig::IpAddressFamily::kIpv4: ip = GetNextIPv4Address(); RTC_CHECK(ip) << "All auto generated IPv4 addresses exhausted"; break; case EmulatedEndpointConfig::IpAddressFamily::kIpv6: ip = GetNextIPv4Address(); RTC_CHECK(ip) << "All auto generated IPv6 addresses exhausted"; ip = ip->AsIPv6Address(); break; } } bool res = used_ip_addresses_.insert(*ip).second; RTC_CHECK(res) << "IP=" << ip->ToString() << " already in use"; auto node = std::make_unique( next_node_id_++, *ip, config.start_as_enabled, config.type, &task_queue_, clock_); EmulatedEndpoint* out = node.get(); endpoints_.push_back(std::move(node)); return out; } void NetworkEmulationManagerImpl::EnableEndpoint(EmulatedEndpoint* endpoint) { EmulatedNetworkManager* network_manager = endpoint_to_network_manager_[endpoint]; RTC_CHECK(network_manager); network_manager->EnableEndpoint(static_cast(endpoint)); } void NetworkEmulationManagerImpl::DisableEndpoint(EmulatedEndpoint* endpoint) { EmulatedNetworkManager* network_manager = endpoint_to_network_manager_[endpoint]; RTC_CHECK(network_manager); network_manager->DisableEndpoint( static_cast(endpoint)); } EmulatedRoute* NetworkEmulationManagerImpl::CreateRoute( EmulatedEndpoint* from, const std::vector& via_nodes, EmulatedEndpoint* to) { // Because endpoint has no send node by default at least one should be // provided here. RTC_CHECK(!via_nodes.empty()); static_cast(from)->router()->SetReceiver( to->GetPeerLocalAddress(), via_nodes[0]); EmulatedNetworkNode* cur_node = via_nodes[0]; for (size_t i = 1; i < via_nodes.size(); ++i) { cur_node->router()->SetReceiver(to->GetPeerLocalAddress(), via_nodes[i]); cur_node = via_nodes[i]; } cur_node->router()->SetReceiver(to->GetPeerLocalAddress(), to); std::unique_ptr route = std::make_unique( static_cast(from), std::move(via_nodes), static_cast(to)); EmulatedRoute* out = route.get(); routes_.push_back(std::move(route)); return out; } EmulatedRoute* NetworkEmulationManagerImpl::CreateRoute( const std::vector& via_nodes) { EmulatedEndpoint* from = CreateEndpoint(EmulatedEndpointConfig()); EmulatedEndpoint* to = CreateEndpoint(EmulatedEndpointConfig()); return CreateRoute(from, via_nodes, to); } void NetworkEmulationManagerImpl::ClearRoute(EmulatedRoute* route) { RTC_CHECK(route->active) << "Route already cleared"; task_queue_.SendTask( [route]() { // Remove receiver from intermediate nodes. for (auto* node : route->via_nodes) { node->router()->RemoveReceiver(route->to->GetPeerLocalAddress()); } // Remove destination endpoint from source endpoint's router. route->from->router()->RemoveReceiver(route->to->GetPeerLocalAddress()); route->active = false; }, RTC_FROM_HERE); } TrafficRoute* NetworkEmulationManagerImpl::CreateTrafficRoute( const std::vector& via_nodes) { RTC_CHECK(!via_nodes.empty()); EmulatedEndpoint* endpoint = CreateEndpoint(EmulatedEndpointConfig()); // Setup a route via specified nodes. EmulatedNetworkNode* cur_node = via_nodes[0]; for (size_t i = 1; i < via_nodes.size(); ++i) { cur_node->router()->SetReceiver(endpoint->GetPeerLocalAddress(), via_nodes[i]); cur_node = via_nodes[i]; } cur_node->router()->SetReceiver(endpoint->GetPeerLocalAddress(), endpoint); std::unique_ptr traffic_route = std::make_unique(clock_, via_nodes[0], endpoint); TrafficRoute* out = traffic_route.get(); traffic_routes_.push_back(std::move(traffic_route)); return out; } RandomWalkCrossTraffic* NetworkEmulationManagerImpl::CreateRandomWalkCrossTraffic( TrafficRoute* traffic_route, RandomWalkConfig config) { auto traffic = std::make_unique(config, traffic_route); RandomWalkCrossTraffic* out = traffic.get(); task_queue_.PostTask( [this, config, traffic = std::move(traffic)]() mutable { auto* traffic_ptr = traffic.get(); random_cross_traffics_.push_back(std::move(traffic)); RepeatingTaskHandle::Start(task_queue_.Get(), [this, config, traffic_ptr] { traffic_ptr->Process(Now()); return config.min_packet_interval; }); }); return out; } PulsedPeaksCrossTraffic* NetworkEmulationManagerImpl::CreatePulsedPeaksCrossTraffic( TrafficRoute* traffic_route, PulsedPeaksConfig config) { auto traffic = std::make_unique(config, traffic_route); PulsedPeaksCrossTraffic* out = traffic.get(); task_queue_.PostTask( [this, config, traffic = std::move(traffic)]() mutable { auto* traffic_ptr = traffic.get(); pulsed_cross_traffics_.push_back(std::move(traffic)); RepeatingTaskHandle::Start(task_queue_.Get(), [this, config, traffic_ptr] { traffic_ptr->Process(Now()); return config.min_packet_interval; }); }); return out; } FakeTcpCrossTraffic* NetworkEmulationManagerImpl::StartFakeTcpCrossTraffic( std::vector send_link, std::vector ret_link, FakeTcpConfig config) { auto traffic = std::make_unique( clock_, config, CreateRoute(send_link), CreateRoute(ret_link)); auto* traffic_ptr = traffic.get(); task_queue_.PostTask([this, traffic = std::move(traffic)]() mutable { traffic->Start(task_queue_.Get()); tcp_cross_traffics_.push_back(std::move(traffic)); }); return traffic_ptr; } TcpMessageRoute* NetworkEmulationManagerImpl::CreateTcpRoute( EmulatedRoute* send_route, EmulatedRoute* ret_route) { auto tcp_route = std::make_unique( clock_, task_queue_.Get(), send_route, ret_route); auto* route_ptr = tcp_route.get(); task_queue_.PostTask([this, tcp_route = std::move(tcp_route)]() mutable { tcp_message_routes_.push_back(std::move(tcp_route)); }); return route_ptr; } void NetworkEmulationManagerImpl::StopCrossTraffic( FakeTcpCrossTraffic* traffic) { task_queue_.PostTask([=]() { traffic->Stop(); tcp_cross_traffics_.remove_if( [=](const std::unique_ptr& ptr) { return ptr.get() == traffic; }); }); } EmulatedNetworkManagerInterface* NetworkEmulationManagerImpl::CreateEmulatedNetworkManagerInterface( const std::vector& endpoints) { std::vector endpoint_impls; for (EmulatedEndpoint* endpoint : endpoints) { endpoint_impls.push_back(static_cast(endpoint)); } auto endpoints_container = std::make_unique(endpoint_impls); auto network_manager = std::make_unique( time_controller_.get(), &task_queue_, endpoints_container.get()); for (auto* endpoint : endpoints) { // Associate endpoint with network manager. bool insertion_result = endpoint_to_network_manager_.insert({endpoint, network_manager.get()}) .second; RTC_CHECK(insertion_result) << "Endpoint ip=" << endpoint->GetPeerLocalAddress().ToString() << " is already used for another network"; } EmulatedNetworkManagerInterface* out = network_manager.get(); endpoints_containers_.push_back(std::move(endpoints_container)); network_managers_.push_back(std::move(network_manager)); return out; } absl::optional NetworkEmulationManagerImpl::GetNextIPv4Address() { uint32_t addresses_count = kMaxIPv4Address - kMinIPv4Address; for (uint32_t i = 0; i < addresses_count; i++) { rtc::IPAddress ip(next_ip4_address_); if (next_ip4_address_ == kMaxIPv4Address) { next_ip4_address_ = kMinIPv4Address; } else { next_ip4_address_++; } if (used_ip_addresses_.find(ip) == used_ip_addresses_.end()) { return ip; } } return absl::nullopt; } Timestamp NetworkEmulationManagerImpl::Now() const { return clock_->CurrentTime(); } } // namespace test } // namespace webrtc