From f5f56e1a1c4d9e9496fcb9d81131066a964ccd23 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 13 Apr 2024 14:15:43 +0200 Subject: Adding upstream version 2.4.1. Signed-off-by: Daniel Baumann --- src/bin/dhcp6/client_handler.cc | 191 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 src/bin/dhcp6/client_handler.cc (limited to 'src/bin/dhcp6/client_handler.cc') diff --git a/src/bin/dhcp6/client_handler.cc b/src/bin/dhcp6/client_handler.cc new file mode 100644 index 0000000..54fc9d8 --- /dev/null +++ b/src/bin/dhcp6/client_handler.cc @@ -0,0 +1,191 @@ +// Copyright (C) 2020-2023 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include + +#include +#include +#include +#include +#include + +using namespace std; +using namespace isc::util; +using namespace isc::log; + +namespace isc { +namespace dhcp { + +ClientHandler::Client::Client(Pkt6Ptr query, DuidPtr client_id) + : query_(query), thread_(this_thread::get_id()) { + // Sanity checks. + if (!query) { + isc_throw(InvalidParameter, "null query in ClientHandler"); + } + if (!client_id) { + isc_throw(InvalidParameter, "null client-id in ClientHandler"); + } + + duid_ = client_id->getDuid(); +} + +mutex ClientHandler::mutex_; + +ClientHandler::ClientContainer ClientHandler::clients_; + +ClientHandler::ClientPtr +ClientHandler::lookup(const DuidPtr& duid) { + // Sanity check. + if (!duid) { + isc_throw(InvalidParameter, "null duid in ClientHandler::lookup"); + } + + auto it = clients_.find(duid->getDuid()); + if (it == clients_.end()) { + return (ClientPtr()); + } + return (*it); +} + +void +ClientHandler::add(const ClientPtr& client) { + // Sanity check. + if (!client) { + isc_throw(InvalidParameter, "null client in ClientHandler::add"); + } + + // Assume insert will never fail so not checking its result. + clients_.insert(client); +} + +void +ClientHandler::del(const DuidPtr& duid) { + // Sanity check. + if (!duid) { + isc_throw(InvalidParameter, "null duid in ClientHandler::del"); + } + + // Assume erase will never fail so not checking its result. + clients_.erase(duid->getDuid()); +} + +ClientHandler::ClientHandler() : client_(), locked_() { +} + +ClientHandler::~ClientHandler() { + if (locked_) { + lock_guard lk(mutex_); + unLock(); + } +} + +bool +ClientHandler::tryLock(Pkt6Ptr query, ContinuationPtr cont) { + // Sanity checks. + if (!query) { + isc_throw(InvalidParameter, "null query in ClientHandler::tryLock"); + } + if (locked_) { + isc_throw(Unexpected, "already handling in ClientHandler::tryLock"); + } + + const DuidPtr& duid = query->getClientId(); + if (!duid) { + // Can't do something useful: cross fingers. + return (true); + } + if (duid->getDuid().empty()) { + // A lot of code assumes this will never happen... + isc_throw(Unexpected, "empty DUID in ClientHandler::tryLock"); + } + + ClientPtr holder; + Pkt6Ptr next_query; + client_.reset(new Client(query, duid)); + + { + // Try to acquire the lock and return the holder when it failed. + lock_guard lk(mutex_); + holder = lookup(duid); + if (!holder) { + locked_ = duid; + lock(); + return (true); + } + // This query can be a duplicate so put the continuation. + if (cont) { + next_query = holder->next_query_; + holder->next_query_ = query; + holder->cont_ = cont; + } + } + + if (cont) { + if (next_query) { + // Logging a warning as it is supposed to be a rare event + // with well behaving clients... + LOG_DEBUG(bad_packet6_logger, DBGLVL_PKT_HANDLING, DHCP6_PACKET_DROP_DUPLICATE) + .arg(next_query->makeLabel(next_query->getClientId(), nullptr)) + .arg(next_query->toText()) + .arg(this_thread::get_id()) + .arg(holder->query_->makeLabel(holder->query_->getClientId(), nullptr)) + .arg(holder->query_->toText()) + .arg(holder->thread_); + stats::StatsMgr::instance().addValue("pkt6-receive-drop", + static_cast(1)); + } + } else { + // Logging a warning as it is supposed to be a rare event + // with well behaving clients... + LOG_DEBUG(bad_packet6_logger, DBGLVL_PKT_HANDLING, DHCP6_PACKET_DROP_DUPLICATE) + .arg(query->makeLabel(query->getClientId(), nullptr)) + .arg(query->toText()) + .arg(this_thread::get_id()) + .arg(holder->query_->makeLabel(holder->query_->getClientId(), nullptr)) + .arg(holder->query_->toText()) + .arg(holder->thread_); + stats::StatsMgr::instance().addValue("pkt6-receive-drop", + static_cast(1)); + } + return (false); +} + +void +ClientHandler::lock() { + // Sanity check. + if (!locked_) { + isc_throw(Unexpected, "nothing to lock in ClientHandler::lock"); + } + + add(client_); +} + +void +ClientHandler::unLock() { + // Sanity check. + if (!locked_) { + isc_throw(Unexpected, "nothing to unlock in ClientHandler::unLock"); + } + + del(locked_); + locked_.reset(); + + if (!client_ || !client_->cont_) { + return; + } + + // Try to process next query. As the caller holds the mutex of + // the handler class the continuation will be resumed after. + MultiThreadingMgr& mt_mgr = MultiThreadingMgr::instance(); + if (mt_mgr.getMode()) { + if (!mt_mgr.getThreadPool().addFront(client_->cont_)) { + LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_PACKET_QUEUE_FULL); + } + } +} + +} // namespace dhcp +} // namespace isc -- cgit v1.2.3