Kea 2.7.5
dhcp6/client_handler.cc
Go to the documentation of this file.
1// Copyright (C) 2020-2023 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
10#include <dhcp6/dhcp6_log.h>
12#include <stats/stats_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...
131 .arg(next_query->makeLabel(next_query->getClientId(), nullptr))
132 .arg(next_query->toText())
133 .arg(this_thread::get_id())
134 .arg(holder->query_->makeLabel(holder->query_->getClientId(), nullptr))
135 .arg(holder->query_->toText())
136 .arg(holder->thread_);
137 stats::StatsMgr::instance().addValue("pkt6-receive-drop",
138 static_cast<int64_t>(1));
139 }
140 } else {
141 // Logging a warning as it is supposed to be a rare event
142 // with well behaving clients...
144 .arg(query->makeLabel(query->getClientId(), nullptr))
145 .arg(query->toText())
146 .arg(this_thread::get_id())
147 .arg(holder->query_->makeLabel(holder->query_->getClientId(), nullptr))
148 .arg(holder->query_->toText())
149 .arg(holder->thread_);
150 stats::StatsMgr::instance().addValue("pkt6-receive-drop",
151 static_cast<int64_t>(1));
152 }
153 return (false);
154}
155
156void
157ClientHandler::lock() {
158 // Sanity check.
159 if (!locked_) {
160 isc_throw(Unexpected, "nothing to lock in ClientHandler::lock");
161 }
162
163 add(client_);
164}
165
166void
167ClientHandler::unLock() {
168 // Sanity check.
169 if (!locked_) {
170 isc_throw(Unexpected, "nothing to unlock in ClientHandler::unLock");
171 }
172
173 del(locked_);
174 locked_.reset();
175
176 if (!client_ || !client_->cont_) {
177 return;
178 }
179
180 // Try to process next query. As the caller holds the mutex of
181 // the handler class the continuation will be resumed after.
183 if (mt_mgr.getMode()) {
184 if (!mt_mgr.getThreadPool().addFront(client_->cont_)) {
185 LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_PACKET_QUEUE_FULL);
186 }
187 }
188}
189
190} // namespace dhcp
191} // namespace isc
A generic exception that is thrown if a parameter given to a method or function is considered invalid...
A generic exception that is thrown when an unexpected error condition occurs.
static MultiThreadingMgr & instance()
Returns a single instance of Multi Threading Manager.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition macros.h:14
isc::log::Logger bad_packet6_logger(DHCP6_BAD_PACKET_LOGGER_NAME)
Logger for rejected packets.
Definition dhcp6_log.h:94
boost::shared_ptr< DUID > DuidPtr
Definition duid.h:136
boost::shared_ptr< Continuation > ContinuationPtr
Define the type of shared pointers to continuations.
boost::shared_ptr< Pkt6 > Pkt6Ptr
A pointer to Pkt6 packet.
Definition pkt6.h:31
const isc::log::MessageID DHCP6_PACKET_DROP_DUPLICATE
const int DBGLVL_PKT_HANDLING
This debug level is reserved for logging the details of packet handling, such as dropping the packet ...
Defines the logger used by the top-level component of kea-lfc.