Kea: monitored_duration.cc Source File

| Kea 3.2.0-git

monitored_duration.cc
Go to the documentation of this file.
1// Copyright (C) 2024-2025 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 <dhcp/pkt4.h>
10#include <dhcp/pkt6.h>
11#include <dhcp/dhcp6.h>
12#include <exceptions/exceptions.h>
13#include <monitored_duration.h>
14#include <util/boost_time_utils.h>
15
16using namespace isc::dhcp;
17using namespace isc::data;
18using namespace isc::util;
19using namespace boost::posix_time;
20
21namespace isc {
22namespace perfmon {
23
24// DurationDataInterval methods
25
26DurationDataInterval::DurationDataInterval(const Timestamp& start_time /* = PktEvent::now()*/)
27 : start_time_(start_time), occurrences_(0),
28 min_duration_(pos_infin), max_duration_(neg_infin),
29 total_duration_(microseconds(0)) {
30}
31
32void
33DurationDataInterval::addDuration(const Duration& duration) {
34 ++occurrences_;
35 if (duration < min_duration_) {
36 min_duration_ = duration;
37 }
38
39 if (duration > max_duration_) {
40 max_duration_ = duration;
41 }
42
43 total_duration_ += duration;
44}
45
46 Duration
47DurationDataInterval::getMeanDuration() const {
48 if (!occurrences_) {
49 return (ZERO_DURATION());
50 }
51
52 return (total_duration_ / occurrences_);
53}
54
55bool
56DurationDataInterval::operator==(const DurationDataInterval& other) const {
57 return ((start_time_ == other.start_time_) &&
58 (occurrences_ == other.occurrences_) &&
59 (min_duration_ == other.min_duration_) &&
60 (max_duration_ == other.max_duration_) &&
61 (total_duration_ == other.total_duration_));
62}
63
64// DurationKey methods
65
66DurationKey::DurationKey(uint16_t family,
67 uint8_t query_type,
68 uint8_t response_type,
69 const std::string& start_event_label,
70 const std::string& stop_event_label,
71 dhcp::SubnetID subnet_id)
72 : family_(family),
73 query_type_(query_type),
74 response_type_(response_type),
75 start_event_label_(start_event_label),
76 stop_event_label_(stop_event_label),
77 subnet_id_(subnet_id) {
78 if (family != AF_INET && family != AF_INET6) {
79 isc_throw (BadValue, "DurationKey: family must be AF_INET or AF_INET6");
80 }
81
82 validateMessagePair(family, query_type, response_type);
83}
84
85void
86DurationKey::validateMessagePair(uint16_t family, uint8_t query_type, uint8_t response_type) {
87 if (family == AF_INET) {
88 switch(query_type) {
89 case DHCP_NOTYPE:
90 if (response_type == DHCP_NOTYPE ||
91 response_type == DHCPOFFER ||
92 response_type == DHCPACK ||
93 response_type == DHCPNAK) {
94 return;
95 }
96 break;
97
98 case DHCPDISCOVER:
99 if (response_type == DHCP_NOTYPE ||
100 response_type == DHCPOFFER ||
101 response_type == DHCPNAK) {
102 return;
103 }
104 break;
105
106 case DHCPREQUEST:
107 if (response_type == DHCP_NOTYPE ||
108 response_type == DHCPACK ||
109 response_type == DHCPNAK) {
110 return;
111 }
112 break;
113
114 case DHCPINFORM:
115 if (response_type == DHCP_NOTYPE ||
116 response_type == DHCPACK) {
117 return;
118 }
119 break;
120
121 default:
122 isc_throw(BadValue, "Query type not supported by monitoring: "
123 << Pkt4::getName(query_type));
124 break;
125 }
126
127 isc_throw(BadValue, "Response type: " << Pkt4::getName(response_type)
128 << " not valid for query type: " << Pkt4::getName(query_type));
129
130 } else {
131 switch(query_type) {
132 case DHCPV6_NOTYPE:
133 case DHCPV6_SOLICIT:
134 if (response_type == DHCPV6_NOTYPE ||
135 response_type == DHCPV6_ADVERTISE ||
136 response_type == DHCPV6_REPLY) {
137 return;
138 }
139 break;
140
141 case DHCPV6_REQUEST:
142 case DHCPV6_RENEW:
143 case DHCPV6_REBIND:
144 case DHCPV6_CONFIRM:
145 if (response_type == DHCPV6_NOTYPE ||
146 response_type == DHCPV6_REPLY) {
147 return;
148 }
149 break;
150
151 default:
152 isc_throw(BadValue, "Query type not supported by monitoring: "
153 << Pkt6::getName(query_type));
154 break;
155 }
156
157 isc_throw(BadValue, "Response type: " << Pkt6::getName(response_type)
158 << " not valid for query type: " << Pkt6::getName(query_type));
159 }
160}
161
162std::string
163DurationKey::getMessageTypeLabel(uint16_t family, uint16_t msg_type) {
164 if (family == AF_INET) {
165 return (msg_type == DHCP_NOTYPE ? "*" : Pkt4::getName(msg_type));
166 }
167
168 return (msg_type == DHCPV6_NOTYPE ? "*" : Pkt6::getName(msg_type));
169}
170
171std::string
172DurationKey::getLabel() const {
173 std::ostringstream oss;
174 oss << getMessageTypeLabel(family_, query_type_)
175 << "-"
176 << getMessageTypeLabel(family_, response_type_)
177 << "." << start_event_label_ << "-" << stop_event_label_
178 << "." << subnet_id_;
179
180 return (oss.str());
181}
182
183std::string
184DurationKey::getStatName(const std::string& value_name) const {
185 std::ostringstream oss;
186 if (subnet_id_ != SUBNET_ID_GLOBAL) {
187 oss << "subnet-id[" << subnet_id_ << "].";
188 }
189
190 oss << "perfmon."
191 << getMessageTypeLabel(family_, query_type_)
192 << "-"
193 << getMessageTypeLabel(family_, response_type_)
194 << "." << start_event_label_ << "-" << stop_event_label_
195 << "." << value_name;
196
197 return (oss.str());
198}
199
200 ElementPtr
201DurationKey::toElement() const {
202 ElementPtr element = Element::createMap();
203 element->set("query-type", Element::create(getMessageTypeLabel(family_, query_type_)));
204 element->set("response-type", Element::create(getMessageTypeLabel(family_, response_type_)));
205 element->set("start-event", Element::create(start_event_label_));
206 element->set("stop-event", Element::create(stop_event_label_));
207 element->set("subnet-id", Element::create(static_cast<long long>(subnet_id_)));
208 return (element);
209}
210
211bool
212DurationKey::operator==(const DurationKey& other) const {
213 return (
214 (query_type_ == other.query_type_) &&
215 (response_type_ == other.response_type_) &&
216 (start_event_label_ == other.start_event_label_) &&
217 (stop_event_label_ == other.stop_event_label_) &&
218 (subnet_id_ == other.subnet_id_)
219 );
220}
221
222bool
223DurationKey::operator!=(const DurationKey& other) const {
224 return (!(*this == other));
225}
226
227 bool
228 DurationKey::operator<(const DurationKey& other) const {
229 return ((query_type_ < other.query_type_) ||
230 (response_type_ < other.response_type_) ||
231 (start_event_label_ < other.start_event_label_) ||
232 (stop_event_label_ < other.stop_event_label_) ||
233 (subnet_id_ < other.subnet_id_));
234}
235
236std::ostream&
237 operator<<(std::ostream& os, const DurationKey& key) {
238 os << key.getLabel();
239 return (os);
240}
241
242// MonitoredDuration methods
243
244MonitoredDuration::MonitoredDuration(uint16_t family,
245 uint8_t query_type,
246 uint8_t response_type,
247 const std::string& start_event_label,
248 const std::string& stop_event_label,
249 dhcp::SubnetID subnet_id,
250 const Duration& interval_duration)
251 : DurationKey(family, query_type, response_type, start_event_label, stop_event_label, subnet_id),
252 interval_duration_(interval_duration),
253 current_interval_(0),
254 previous_interval_(0) {
255 if (interval_duration_ <= DurationDataInterval::ZERO_DURATION()) {
256 isc_throw(BadValue, "MonitoredDuration - interval_duration " << interval_duration_
257 << ", is invalid, it must be greater than 0");
258 }
259}
260
261 MonitoredDuration::MonitoredDuration(const DurationKey& key,
262 const Duration& interval_duration)
263 : DurationKey(key),
264 interval_duration_(interval_duration),
265 current_interval_(0),
266 previous_interval_(0) {
267 if (interval_duration_ <= DurationDataInterval::ZERO_DURATION()) {
268 isc_throw(BadValue, "MonitoredDuration - interval_duration " << interval_duration_
269 << ", is invalid, it must be greater than 0");
270 }
271}
272
273 MonitoredDuration::MonitoredDuration(const MonitoredDuration& rhs)
274 : DurationKey(rhs),
275 interval_duration_(rhs.interval_duration_),
276 current_interval_(0),
277 previous_interval_(0) {
278 if (rhs.current_interval_) {
279 current_interval_.reset(new DurationDataInterval(*rhs.current_interval_));
280 }
281
282 if (rhs.previous_interval_) {
283 previous_interval_.reset(new DurationDataInterval(*rhs.previous_interval_));
284 }
285}
286
287 Timestamp
288MonitoredDuration::getCurrentIntervalStart() const {
289 return (current_interval_ ? current_interval_->getStartTime()
290 : dhcp::PktEvent::MIN_TIME());
291}
292
293bool
294MonitoredDuration::addSample(const Duration& sample) {
295 auto now = PktEvent::now();
296 bool do_report = false;
297 if (!current_interval_) {
298 current_interval_.reset(new DurationDataInterval(now));
299 } else if ((now - current_interval_->getStartTime()) > interval_duration_) {
300 previous_interval_ = current_interval_;
301 do_report = true;
302 current_interval_.reset(new DurationDataInterval(now));
303 }
304
305 current_interval_->addDuration(sample);
306 return (do_report);
307}
308
309void
310MonitoredDuration::expireCurrentInterval() {
311 if (!current_interval_) {
312 isc_throw(InvalidOperation, "MonitoredDuration::expireInterval"
313 " - no current interval for: " << getLabel());
314 }
315
316 previous_interval_ = current_interval_;
317 current_interval_.reset();
318}
319
320void
321MonitoredDuration::clear() {
322 current_interval_.reset();
323 previous_interval_.reset();
324}
325
326 ElementPtr
327MonitoredDuration::toElement() const {
328 ElementPtr element = Element::createMap();
329 element->set("duration-key", DurationKey::toElement());
330 if (previous_interval_) {
331 element->set("start-time", Element::create(ptimeToText(previous_interval_->getStartTime())));
332 element->set("occurrences", Element::create(static_cast<long long>(previous_interval_->getOccurrences())));
333 element->set("min-duration-usecs", Element::create(previous_interval_->getMinDuration().total_microseconds()));
334 element->set("max-duration-usecs", Element::create(previous_interval_->getMaxDuration().total_microseconds()));
335 element->set("total-duration-usecs", Element::create(previous_interval_->getTotalDuration().total_microseconds()));
336 element->set("mean-duration-usecs", Element::create(previous_interval_->getMeanDuration().total_microseconds()));
337 } else {
338 element->set("start-time", Element::create("<none>"));
339 element->set("occurrences", Element::create(0));
340 element->set("min-duration-usecs", Element::create(0));
341 element->set("max-duration-usecs", Element::create(0));
342 element->set("total-duration-usecs", Element::create(0));
343 element->set("mean-duration-usecs", Element::create(0));
344 }
345
346 return (element);
347}
348
349 ConstElementPtr
350MonitoredDuration::valueRowColumns() {
351 static std::list<std::string> column_labels{
352 "query-type",
353 "response-type",
354 "start-event",
355 "end-event",
356 "subnet-id",
357 "interval-start",
358 "occurrences",
359 "min-duration-usecs",
360 "max-duration-usecs",
361 "total-duration-usecs"
362 "mean-duration-usecs"
363 };
364
365 static ElementPtr cols;
366 if (!cols) {
367 // Create the list of column names and add it to the result set.
368 cols = Element::createList();
369 for (auto const& label : column_labels) {
370 cols->add(Element::create(label));
371 }
372 }
373
374 return(cols);
375}
376
377 ElementPtr
378MonitoredDuration::toValueRow() const {
379 // Create the value row.
380 ElementPtr row = Element::createList();
381
382 // Add key values.
383 row->add(Element::create(getMessageTypeLabel(family_, query_type_)));
384 row->add(Element::create(getMessageTypeLabel(family_, response_type_)));
385 row->add(Element::create(start_event_label_));
386 row->add(Element::create(stop_event_label_));
387 row->add(Element::create(static_cast<long long>(subnet_id_)));
388
389 // Add interval data values.
390 if (previous_interval_) {
391 row->add(Element::create(ptimeToText(previous_interval_->getStartTime())));
392 row->add(Element::create(static_cast<long long>(previous_interval_->getOccurrences())));
393 row->add(Element::create(previous_interval_->getMinDuration().total_microseconds()));
394 row->add(Element::create(previous_interval_->getMaxDuration().total_microseconds()));
395 row->add(Element::create(previous_interval_->getTotalDuration().total_microseconds()));
396 row->add(Element::create(previous_interval_->getMeanDuration().total_microseconds()));
397 } else {
398 row->add(Element::create("<none>"));
399 row->add(Element::create(0));
400 row->add(Element::create(0));
401 row->add(Element::create(0));
402 row->add(Element::create(0));
403 row->add(Element::create(0));
404 }
405
406 return (row);
407}
408
409} // end of namespace perfmon
410} // end of namespace isc
boost_time_utils.h
isc::BadValue
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
Definition exceptions/exceptions.h:132
isc::InvalidOperation
A generic exception that is thrown if a function is called in a prohibited way.
Definition exceptions/exceptions.h:143
isc::data::Element::create
static ElementPtr create(const Position &pos=ZERO_POSITION())
Create a NullElement.
Definition data.cc:299
isc::data::Element::createMap
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition data.cc:354
isc::data::Element::createList
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition data.cc:349
isc::dhcp::Pkt4::getName
static const char * getName(const uint8_t type)
Returns name of the DHCP message for a given type number.
Definition pkt4.cc:284
isc::dhcp::Pkt6::getName
static const char * getName(const uint8_t type)
Returns name of the DHCPv6 message for a given type number.
Definition pkt6.cc:784
isc::dhcp::PktEvent::now
static boost::posix_time::ptime now()
Fetch the current UTC system time, microsecond precision.
Definition pkt.h:117
isc::dhcp::PktEvent::MIN_TIME
static boost::posix_time::ptime & MIN_TIME()
Fetches the minimum timestamp.
Definition pkt.h:132
isc::perfmon::DurationDataInterval
Embodies a span of time (i.e.
Definition monitored_duration.h:25
isc::perfmon::DurationDataInterval::getMeanDuration
Duration getMeanDuration() const
Get the mean duration for the interval.
Definition monitored_duration.cc:47
isc::perfmon::DurationDataInterval::DurationDataInterval
DurationDataInterval(const Timestamp &start_time=dhcp::PktEvent::now())
Constructor.
Definition monitored_duration.cc:26
isc::perfmon::DurationDataInterval::ZERO_DURATION
static const Duration & ZERO_DURATION()
Get a duration of zero.
Definition monitored_duration.h:30
isc::perfmon::DurationDataInterval::operator==
bool operator==(const DurationDataInterval &other) const
Equality operator.
Definition monitored_duration.cc:56
isc::perfmon::DurationDataInterval::addDuration
void addDuration(const Duration &duration)
Add a duration to the interval.
Definition monitored_duration.cc:33
isc::perfmon::DurationKey
Houses the composite key that uniquely identifies a duration:
Definition monitored_duration.h:134
isc::perfmon::DurationKey::operator!=
bool operator!=(const DurationKey &other) const
Inequality operator.
Definition monitored_duration.cc:223
isc::perfmon::DurationKey::subnet_id_
isc::dhcp::SubnetID subnet_id_
Subnet ID of the subnet selected during query fulfillment.
Definition monitored_duration.h:314
isc::perfmon::DurationKey::getMessageTypeLabel
static std::string getMessageTypeLabel(uint16_t family, uint16_t msg_type)
Get a label for a family-specific message type (e.g.
Definition monitored_duration.cc:163
isc::perfmon::DurationKey::response_type_
uint8_t response_type_
Response message type (e.g. DHCPOFFER, DHCP6_ADVERTISE).
Definition monitored_duration.h:305
isc::perfmon::DurationKey::operator<
bool operator<(const DurationKey &other) const
Less than operator.
Definition monitored_duration.cc:228
isc::perfmon::DurationKey::start_event_label_
std::string start_event_label_
Label of the start event which begins the duration.
Definition monitored_duration.h:308
isc::perfmon::DurationKey::toElement
virtual data::ElementPtr toElement() const
Renders the the duration key as an Element.
Definition monitored_duration.cc:201
isc::perfmon::DurationKey::operator==
bool operator==(const DurationKey &other) const
Equality operator.
Definition monitored_duration.cc:212
isc::perfmon::DurationKey::DurationKey
DurationKey(uint16_t family, uint8_t query_type, uint8_t response_type, const std::string &start_event_label, const std::string &stop_event_label, dhcp::SubnetID subnet_id)
Constructor.
Definition monitored_duration.cc:66
isc::perfmon::DurationKey::family_
uint16_t family_
Protocol family AF_INET or AF_INET6.
Definition monitored_duration.h:299
isc::perfmon::DurationKey::getStatName
std::string getStatName(const std::string &value_name) const
Get the StatsMgr formatted compatible name.
Definition monitored_duration.cc:184
isc::perfmon::DurationKey::validateMessagePair
static void validateMessagePair(uint16_t family, uint8_t query_type, uint8_t response_type)
Validates that a query and response message type pair is sane.
Definition monitored_duration.cc:86
isc::perfmon::DurationKey::stop_event_label_
std::string stop_event_label_
Label of the end event which ends the duration.
Definition monitored_duration.h:311
isc::perfmon::DurationKey::getLabel
std::string getLabel() const
Get a composite label of the member values with text message types.
Definition monitored_duration.cc:172
isc::perfmon::DurationKey::query_type_
uint8_t query_type_
Query message type (e.g. DHCPDISCOVER, DHCP6_SOLICIT).
Definition monitored_duration.h:302
isc::perfmon::MonitoredDuration::toElement
virtual data::ElementPtr toElement() const
Renders the the duration as an Element.
Definition monitored_duration.cc:327
isc::perfmon::MonitoredDuration::toValueRow
data::ElementPtr toValueRow() const
Renders the the duration as an Element::list of values.
Definition monitored_duration.cc:378
isc::perfmon::MonitoredDuration::getCurrentIntervalStart
Timestamp getCurrentIntervalStart() const
Get the current interval start time.
Definition monitored_duration.cc:288
isc::perfmon::MonitoredDuration::addSample
bool addSample(const Duration &sample)
Add a sample to the duration's current interval.
Definition monitored_duration.cc:294
isc::perfmon::MonitoredDuration::expireCurrentInterval
void expireCurrentInterval()
Concludes the current interval.
Definition monitored_duration.cc:310
isc::perfmon::MonitoredDuration::MonitoredDuration
MonitoredDuration(uint16_t family, uint8_t query_type, uint8_t response_type, const std::string &start_event_label, const std::string &stop_event_label, dhcp::SubnetID subnet_id, const Duration &interval_duration)
Constructor.
Definition monitored_duration.cc:244
isc::perfmon::MonitoredDuration::clear
void clear()
Deletes the current and previous intervals.
Definition monitored_duration.cc:321
isc::perfmon::MonitoredDuration::valueRowColumns
static data::ConstElementPtr valueRowColumns()
Fetches an Element::list of value row column names.
Definition monitored_duration.cc:350
if
if(!(yy_init))
Definition d2_lexer.cc:1515
dhcp6.h
DHCPV6_ADVERTISE
@ DHCPV6_ADVERTISE
Definition dhcp6.h:209
DHCPV6_REQUEST
@ DHCPV6_REQUEST
Definition dhcp6.h:210
DHCPV6_RENEW
@ DHCPV6_RENEW
Definition dhcp6.h:212
DHCPV6_REBIND
@ DHCPV6_REBIND
Definition dhcp6.h:213
DHCPV6_REPLY
@ DHCPV6_REPLY
Definition dhcp6.h:214
DHCPV6_SOLICIT
@ DHCPV6_SOLICIT
Definition dhcp6.h:208
DHCPV6_CONFIRM
@ DHCPV6_CONFIRM
Definition dhcp6.h:211
DHCPV6_NOTYPE
@ DHCPV6_NOTYPE
Definition dhcp6.h:207
exceptions.h
isc_throw
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition exceptions/exceptions.h:210
monitored_duration.h
isc::data
Definition base_stamped_element.cc:12
isc::data::ConstElementPtr
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:30
isc::data::ElementPtr
boost::shared_ptr< Element > ElementPtr
Definition data.h:29
isc::dhcp
Definition dhcp4/client_handler.cc:20
isc::dhcp::SubnetID
uint32_t SubnetID
Defines unique IPv4 or IPv6 subnet identifier.
Definition subnet_id.h:25
isc::dhcp::DHCPREQUEST
@ DHCPREQUEST
Definition dhcp4.h:237
isc::dhcp::DHCPOFFER
@ DHCPOFFER
Definition dhcp4.h:236
isc::dhcp::DHCPNAK
@ DHCPNAK
Definition dhcp4.h:240
isc::dhcp::DHCPDISCOVER
@ DHCPDISCOVER
Definition dhcp4.h:235
isc::dhcp::DHCP_NOTYPE
@ DHCP_NOTYPE
Message Type option missing.
Definition dhcp4.h:234
isc::dhcp::DHCPINFORM
@ DHCPINFORM
Definition dhcp4.h:242
isc::dhcp::DHCPACK
@ DHCPACK
Definition dhcp4.h:239
isc::perfmon
Definition alarm.cc:19
isc::perfmon::Duration
boost::posix_time::time_duration Duration
Definition monitored_duration.h:21
isc::perfmon::Timestamp
boost::posix_time::ptime Timestamp
Definition monitored_duration.h:20
isc::perfmon::operator<<
std::ostream & operator<<(std::ostream &os, const DurationKey &key)
Definition monitored_duration.cc:237
isc::util
Definition time_utils.cc:43
isc::util::ptimeToText
std::string ptimeToText(boost::posix_time::ptime t, size_t fsecs_precision=MAX_FSECS_PRECISION)
Converts ptime structure to text.
Definition boost_time_utils.cc:14
isc
Defines the logger used by the top-level component of kea-lfc.
Definition check_exists_add.cc:18
pkt4.h
pkt6.h