Kea: client_handler.cc Source File

| Kea 2.2.0

dhcp6/client_handler.cc
Go to the documentation of this file.
1// Copyright (C) 2020-2021 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
9#include <dhcp6/client_handler.h>
10#include <dhcp6/dhcp6_log.h>
11#include <exceptions/exceptions.h>
12#include <stats/stats_mgr.h>
13#include <util/multi_threading_mgr.h>
14
15using namespace std;
16using namespace isc::util;
17using namespace isc::log;
18
19namespace isc {
20namespace dhcp {
21
22ClientHandler::Client::Client(Pkt6Ptr query, DuidPtr client_id)
23 : query_(query), thread_(this_thread::get_id()) {
24 // Sanity checks.
25 if (!query) {
26 isc_throw(InvalidParameter, "null query in ClientHandler");
27 }
28 if (!client_id) {
29 isc_throw(InvalidParameter, "null client-id in ClientHandler");
30 }
31
32 duid_ = client_id->getDuid();
33}
34
35mutex ClientHandler::mutex_;
36
37ClientHandler::ClientContainer ClientHandler::clients_;
38
39ClientHandler::ClientPtr
40ClientHandler::lookup(const DuidPtr& duid) {
41 // Sanity check.
42 if (!duid) {
43 isc_throw(InvalidParameter, "null duid in ClientHandler::lookup");
44 }
45
46 auto it = clients_.find(duid->getDuid());
47 if (it == clients_.end()) {
48 return (ClientPtr());
49 }
50 return (*it);
51}
52
53void
54ClientHandler::add(const ClientPtr& client) {
55 // Sanity check.
56 if (!client) {
57 isc_throw(InvalidParameter, "null client in ClientHandler::add");
58 }
59
60 // Assume insert will never fail so not checking its result.
61 clients_.insert(client);
62}
63
64void
65ClientHandler::del(const DuidPtr& duid) {
66 // Sanity check.
67 if (!duid) {
68 isc_throw(InvalidParameter, "null duid in ClientHandler::del");
69 }
70
71 // Assume erase will never fail so not checking its result.
72 clients_.erase(duid->getDuid());
73}
74
75ClientHandler::ClientHandler() : client_(), locked_() {
76}
77
78ClientHandler::~ClientHandler() {
79 if (locked_) {
80 lock_guard<mutex> lk(mutex_);
81 unLock();
82 }
83}
84
85bool
86ClientHandler::tryLock(Pkt6Ptr query, ContinuationPtr cont) {
87 // Sanity checks.
88 if (!query) {
89 isc_throw(InvalidParameter, "null query in ClientHandler::tryLock");
90 }
91 if (locked_) {
92 isc_throw(Unexpected, "already handling in ClientHandler::tryLock");
93 }
94
95 const DuidPtr& duid = query->getClientId();
96 if (!duid) {
97 // Can't do something useful: cross fingers.
98 return (true);
99 }
100 if (duid->getDuid().empty()) {
101 // A lot of code assumes this will never happen...
102 isc_throw(Unexpected, "empty DUID in ClientHandler::tryLock");
103 }
104
105 ClientPtr holder;
106 Pkt6Ptr next_query;
107 client_.reset(new Client(query, duid));
108
109 {
110 // Try to acquire the lock and return the holder when it failed.
111 lock_guard<mutex> lk(mutex_);
112 holder = lookup(duid);
113 if (!holder) {
114 locked_ = duid;
115 lock();
116 return (true);
117 }
118 // This query can be a duplicate so put the continuation.
119 if (cont) {
120 next_query = holder->next_query_;
121 holder->next_query_ = query;
122 holder->cont_ = cont;
123 }
124 }
125
126 if (cont) {
127 if (next_query) {
128 // Logging a warning as it is supposed to be a rare event
129 // with well behaving clients...
130 LOG_DEBUG(bad_packet6_logger, DBGLVL_PKT_HANDLING, DHCP6_PACKET_DROP_DUPLICATE)
131 .arg(next_query->toText())
132 .arg(this_thread::get_id())
133 .arg(holder->query_->toText())
134 .arg(holder->thread_);
135 stats::StatsMgr::instance().addValue("pkt6-receive-drop",
136 static_cast<int64_t>(1));
137 }
138 } else {
139 // Logging a warning as it is supposed to be a rare event
140 // with well behaving clients...
141 LOG_DEBUG(bad_packet6_logger, DBGLVL_PKT_HANDLING, DHCP6_PACKET_DROP_DUPLICATE)
142 .arg(query->toText())
143 .arg(this_thread::get_id())
144 .arg(holder->query_->toText())
145 .arg(holder->thread_);
146 stats::StatsMgr::instance().addValue("pkt6-receive-drop",
147 static_cast<int64_t>(1));
148 }
149 return (false);
150}
151
152void
153ClientHandler::lock() {
154 // Sanity check.
155 if (!locked_) {
156 isc_throw(Unexpected, "nothing to lock in ClientHandler::lock");
157 }
158
159 add(client_);
160}
161
162void
163ClientHandler::unLock() {
164 // Sanity check.
165 if (!locked_) {
166 isc_throw(Unexpected, "nothing to unlock in ClientHandler::unLock");
167 }
168
169 del(locked_);
170 locked_.reset();
171
172 if (!client_ || !client_->cont_) {
173 return;
174 }
175
176 // Try to process next query. As the caller holds the mutex of
177 // the handler class the continuation will be resumed after.
178 MultiThreadingMgr& mt_mgr = MultiThreadingMgr::instance();
179 if (mt_mgr.getMode()) {
180 if (!mt_mgr.getThreadPool().addFront(client_->cont_)) {
181 LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_PACKET_QUEUE_FULL);
182 }
183 }
184}
185
186} // namespace dhcp
187} // namespace isc
isc::InvalidParameter
A generic exception that is thrown if a parameter given to a method or function is considered invalid...
Definition: exceptions/exceptions.h:124
isc::Unexpected
A generic exception that is thrown when an unexpected error condition occurs.
Definition: exceptions/exceptions.h:153
isc::util::MultiThreadingMgr
Multi Threading Manager.
Definition: multi_threading_mgr.h:136
isc::util::MultiThreadingMgr::getThreadPool
ThreadPool< std::function< void()> > & getThreadPool()
Get the dhcp thread pool.
Definition: multi_threading_mgr.cc:83
isc::util::MultiThreadingMgr::getMode
bool getMode() const
Get the multi-threading mode.
Definition: multi_threading_mgr.cc:28
client_handler.h
dhcp6_log.h
exceptions.h
isc_throw
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition: exceptions/exceptions.h:210
stats_mgr.h
LOG_DEBUG
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
multi_threading_mgr.h
isc::dhcp::bad_packet6_logger
isc::log::Logger bad_packet6_logger(DHCP6_BAD_PACKET_LOGGER_NAME)
Logger for rejected packets.
Definition: dhcp6_log.h:94
isc::dhcp::DuidPtr
boost::shared_ptr< DUID > DuidPtr
Definition: duid.h:20
isc::dhcp::ContinuationPtr
boost::shared_ptr< Continuation > ContinuationPtr
Define the type of shared pointers to continuations.
Definition: dhcp4/client_handler.h:28
isc::dhcp::Pkt6Ptr
boost::shared_ptr< Pkt6 > Pkt6Ptr
A pointer to Pkt6 packet.
Definition: pkt6.h:28
isc::dhcp::DBG_DHCP6_BASIC
const int DBG_DHCP6_BASIC
Debug level used to trace basic operations within the code.
Definition: dhcp6_log.h:31
isc::dhcp::dhcp6_logger
isc::log::Logger dhcp6_logger(DHCP6_APP_LOGGER_NAME)
Base logger for DHCPv6 server.
Definition: dhcp6_log.h:88
isc::dhcp::DHCP6_PACKET_DROP_DUPLICATE
const isc::log::MessageID DHCP6_PACKET_DROP_DUPLICATE
Definition: dhcp6_messages.h:107
isc::dhcp::DHCP6_PACKET_QUEUE_FULL
const isc::log::MessageID DHCP6_PACKET_QUEUE_FULL
Definition: dhcp6_messages.h:115
isc::log
Definition: buffer_appender_impl.cc:17
isc::log::DBGLVL_PKT_HANDLING
const int DBGLVL_PKT_HANDLING
This debug level is reserved for logging the details of packet handling, such as dropping the packet ...
Definition: log_dbglevels.h:58
isc::util
Definition: edns.h:19
isc
Defines the logger used by the top-level component of kea-lfc.
Definition: agent_parser.cc:143
isc::util::ThreadPool::addFront
bool addFront(const WorkItemPtr &item)
add a work item to the thread pool at front
Definition: thread_pool.h:105