Kea 3.3.1
csv_lease_file6.cc
Go to the documentation of this file.
1// Copyright (C) 2014-2026 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
11
12#include <ctime>
13
14using namespace isc::asiolink;
15using namespace isc::data;
16using namespace isc::util;
17
18namespace isc {
19namespace dhcp {
20
21CSVLeaseFile6::CSVLeaseFile6(const std::string& filename)
22 : VersionedCSVFile(filename) {
23 initColumns();
24}
25
26void
27CSVLeaseFile6::open(const bool seek_to_end) {
28 // Call the base class to open the file
29 VersionedCSVFile::open(seek_to_end);
30
31 // and clear any statistics we may have
33}
34
35void
37 // Bump the number of write attempts
38 ++writes_;
39
40 if (((!(lease.duid_)) || (*(lease.duid_) == DUID::EMPTY())) &&
41 (lease.state_ != Lease::STATE_DECLINED)) {
43 isc_throw(BadValue, "Lease6: " << lease.addr_.toText() << ", state: "
44 << Lease::basicStatesToText(lease.state_) << ", has no DUID");
45 }
46
48 row.writeAt(getColumnIndex("address"), lease.addr_.toText());
49 row.writeAt(getColumnIndex("duid"), lease.duid_->toText());
50 row.writeAt(getColumnIndex("valid_lifetime"), lease.valid_lft_);
51 row.writeAt(getColumnIndex("expire"), static_cast<uint64_t>(lease.cltt_) + lease.valid_lft_);
52 row.writeAt(getColumnIndex("subnet_id"), lease.subnet_id_);
53 row.writeAt(getColumnIndex("pref_lifetime"), lease.preferred_lft_);
54 row.writeAt(getColumnIndex("lease_type"), lease.type_);
55 row.writeAt(getColumnIndex("iaid"), lease.iaid_);
56 row.writeAt(getColumnIndex("prefix_len"),
57 static_cast<int>(lease.prefixlen_));
58 row.writeAt(getColumnIndex("fqdn_fwd"), lease.fqdn_fwd_);
59 row.writeAt(getColumnIndex("fqdn_rev"), lease.fqdn_rev_);
60 row.writeAtEscaped(getColumnIndex("hostname"), lease.hostname_);
61 // We may not have hardware information.
62 if (lease.hwaddr_) {
63 row.writeAt(getColumnIndex("hwaddr"), lease.hwaddr_->toText(false));
64 row.writeAt(getColumnIndex("hwtype"), lease.hwaddr_->htype_);
65 row.writeAt(getColumnIndex("hwaddr_source"), lease.hwaddr_->source_);
66 } else {
69 }
70 row.writeAt(getColumnIndex("state"), lease.state_);
71 // User context is optional.
72 if (lease.getContext()) {
73 row.writeAtEscaped(getColumnIndex("user_context"), lease.getContext()->str());
74 }
75 row.writeAt(getColumnIndex("pool_id"), lease.pool_id_);
76 try {
78 } catch (const std::exception&) {
79 // Catch any errors so we can bump the error counter than rethrow it
81 throw;
82 }
83
84 // Bump the number of leases written
86}
87
88bool
90 // Bump the number of read attempts
91 ++reads_;
92
93 // Read the CSV row and try to create a lease from the values read.
94 // This may easily result in exception. We don't want this function
95 // to throw exceptions, so we catch them all and rather return the
96 // false value.
97 try {
98 // Get the row of CSV values.
99 CSVRow row;
101 // The empty row signals EOF.
102 if (row == CSVFile::EMPTY_ROW()) {
103 lease.reset();
104 return (true);
105 }
106
107 Lease::Type type = readType(row);
108 uint8_t prefixlen = 128;
109 if (type == Lease::TYPE_PD) {
110 prefixlen = readPrefixLen(row);
111 }
112
113 lease.reset(new Lease6(type, readAddress(row), readDUID(row),
114 readIAID(row), readPreferred(row),
115 readValid(row),
116 readSubnetID(row),
117 readHWAddr(row),
118 prefixlen));
119
120 lease->cltt_ = readCltt(row);
121 lease->fqdn_fwd_ = readFqdnFwd(row);
122 lease->fqdn_rev_ = readFqdnRev(row);
123 lease->hostname_ = readHostname(row);
124 lease->state_ = readState(row);
125
126 if ((*lease->duid_ == DUID::EMPTY())
127 && lease->state_ != Lease::STATE_DECLINED) {
129 "The Empty DUID is only valid for declined leases");
130 }
131
132 ConstElementPtr ctx = readContext(row);
133 if (ctx) {
134 lease->setContext(ctx);
135 }
136
137 lease->pool_id_ = readPoolID(row);
138 } catch (const std::exception& ex) {
139 // bump the read error count
140 ++read_errs_;
141
142 // The lease might have been created, so let's set it back to NULL to
143 // signal that lease hasn't been parsed.
144 lease.reset();
145 setReadMsg(ex.what());
146 return (false);
147 }
148
149 // bump the number of leases read
150 ++read_leases_;
151
152 return (true);
153}
154
155void
156CSVLeaseFile6::initColumns() {
157 addColumn("address", "1.0");
158 addColumn("duid", "1.0");
159 addColumn("valid_lifetime", "1.0");
160 addColumn("expire", "1.0");
161 addColumn("subnet_id", "1.0");
162 addColumn("pref_lifetime", "1.0");
163 addColumn("lease_type", "1.0");
164 addColumn("iaid", "1.0");
165 addColumn("prefix_len", "1.0");
166 addColumn("fqdn_fwd", "1.0");
167 addColumn("fqdn_rev", "1.0");
168 addColumn("hostname", "1.0");
169 addColumn("hwaddr", "2.0");
170 addColumn("state", "3.0", "0" /* == STATE_DEFAULT */);
171 addColumn("user_context", "3.1");
172 // Default not added for hwtype and hwaddr_source, because they depend on
173 // hwaddr having value. When a CSV lease having a hwaddr is upgraded to 4.0,
174 // hwtype will have value "1" meaning HTYPE_ETHER and
175 // hwaddr_source will have value "0" meaning HWADDR_SOURCE_UNKNOWN.
176 addColumn("hwtype", "4.0");
177 addColumn("hwaddr_source", "4.0");
178 addColumn("pool_id", "5.0", "0");
179
180 // Any file with less than hostname is invalid
181 setMinimumValidColumns("hostname");
182}
183
185CSVLeaseFile6::readType(const CSVRow& row) {
186 return (static_cast<Lease::Type>
187 (row.readAndConvertAt<int>(getColumnIndex("lease_type"))));
188}
189
191CSVLeaseFile6::readAddress(const CSVRow& row) {
192 IOAddress address(row.readAt(getColumnIndex("address")));
193 return (address);
194}
195
197CSVLeaseFile6::readDUID(const util::CSVRow& row) {
198 DuidPtr duid(new DUID(DUID::fromText(row.readAt(getColumnIndex("duid")))));
199 return (duid);
200}
201
202uint32_t
203CSVLeaseFile6::readIAID(const CSVRow& row) {
204 uint32_t iaid = row.readAndConvertAt<uint32_t>(getColumnIndex("iaid"));
205 return (iaid);
206}
207
208uint32_t
209CSVLeaseFile6::readPreferred(const CSVRow& row) {
210 uint32_t pref =
211 row.readAndConvertAt<uint32_t>(getColumnIndex("pref_lifetime"));
212 return (pref);
213}
214
215uint32_t
216CSVLeaseFile6::readValid(const CSVRow& row) {
217 uint32_t valid =
218 row.readAndConvertAt<uint32_t>(getColumnIndex("valid_lifetime"));
219 return (valid);
220}
221
222uint32_t
223CSVLeaseFile6::readCltt(const CSVRow& row) {
224 uint32_t cltt =
225 static_cast<uint32_t>(row.readAndConvertAt<uint64_t>(getColumnIndex("expire"))
226 - readValid(row));
227 return (cltt);
228}
229
231CSVLeaseFile6::readSubnetID(const CSVRow& row) {
232 SubnetID subnet_id =
233 row.readAndConvertAt<SubnetID>(getColumnIndex("subnet_id"));
234 return (subnet_id);
235}
236
237uint32_t
238CSVLeaseFile6::readPoolID(const CSVRow& row) {
239 uint32_t pool_id =
240 row.readAndConvertAt<uint32_t>(getColumnIndex("pool_id"));
241 return (pool_id);
242}
243
244uint8_t
245CSVLeaseFile6::readPrefixLen(const CSVRow& row) {
246 int prefixlen = row.readAndConvertAt<int>(getColumnIndex("prefix_len"));
247 return (static_cast<uint8_t>(prefixlen));
248}
249
250bool
251CSVLeaseFile6::readFqdnFwd(const CSVRow& row) {
252 bool fqdn_fwd = row.readAndConvertAt<bool>(getColumnIndex("fqdn_fwd"));
253 return (fqdn_fwd);
254}
255
256bool
257CSVLeaseFile6::readFqdnRev(const CSVRow& row) {
258 bool fqdn_rev = row.readAndConvertAt<bool>(getColumnIndex("fqdn_rev"));
259 return (fqdn_rev);
260}
261
262std::string
263CSVLeaseFile6::readHostname(const CSVRow& row) {
264 std::string hostname = row.readAtEscaped(getColumnIndex("hostname"));
265 return (hostname);
266}
267
269CSVLeaseFile6::readHWAddr(const CSVRow& row) {
270
271 try {
272 uint16_t const hwtype(readHWType(row).valueOr(HTYPE_ETHER));
273 HWAddr hwaddr(
274 HWAddr::fromText(row.readAt(getColumnIndex("hwaddr")), hwtype));
275 if (hwaddr.hwaddr_.empty()) {
276 return (HWAddrPtr());
277 }
278 hwaddr.source_ =
279 readHWAddrSource(row).valueOr(HWAddr::HWADDR_SOURCE_UNKNOWN);
280
283
284 // Let's return a pointer to new freshly created copy.
285 return (HWAddrPtr(new HWAddr(hwaddr)));
286
287 } catch (const std::exception& ex) {
288 // That's worse. There was something in the file, but its conversion
289 // to HWAddr failed. Let's log it on warning and carry on.
291 .arg(ex.what());
292
293 return (HWAddrPtr());
294 }
295}
296
297uint32_t
298CSVLeaseFile6::readState(const util::CSVRow& row) {
299 uint32_t state = row.readAndConvertAt<uint32_t>(getColumnIndex("state"));
300 return (state);
301}
302
304CSVLeaseFile6::readContext(const util::CSVRow& row) {
305 std::string user_context = row.readAtEscaped(getColumnIndex("user_context"));
306 if (user_context.empty()) {
307 return (ConstElementPtr());
308 }
309 ConstElementPtr ctx = Element::fromJSON(user_context);
310 if (!ctx || (ctx->getType() != Element::map)) {
311 isc_throw(isc::BadValue, "user context '" << user_context
312 << "' is not a JSON map");
313 }
314 return (ctx);
315}
316
318CSVLeaseFile6::readHWType(const CSVRow& row) {
319 size_t const index(getColumnIndex("hwtype"));
320 if (row.readAt(index).empty()) {
321 return Optional<uint16_t>();
322 }
323 return row.readAndConvertAt<uint16_t>(index);
324}
325
327CSVLeaseFile6::readHWAddrSource(const CSVRow& row) {
328 size_t const index(getColumnIndex("hwaddr_source"));
329 if (row.readAt(index).empty()) {
330 return Optional<uint16_t>();
331 }
332 return row.readAndConvertAt<uint32_t>(index);
333}
334
335} // end of namespace isc::dhcp
336} // end of namespace isc
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
static ElementPtr fromJSON(const std::string &in, bool preproc=false)
These functions will parse the given string (JSON) representation of a compound element.
Definition data.cc:865
bool next(Lease6Ptr &lease)
Reads next lease from the CSV file.
void append(const Lease6 &lease)
Appends the lease record to the CSV file.
virtual void open(const bool seek_to_end=false)
Opens a lease file.
CSVLeaseFile6(const std::string &filename)
Constructor.
static DUID fromText(const std::string &text)
Create DUID from the textual format.
Definition duid.cc:50
static const DUID & EMPTY()
Defines the constant "empty" DUID.
Definition duid.cc:55
uint32_t write_leases_
Number of lease written.
uint32_t read_leases_
Number of leases read.
uint32_t reads_
Number of attempts to read a lease.
void clearStatistics()
Clears the statistics.
uint32_t writes_
Number of attempts to write a lease.
uint32_t write_errs_
Number of errors when writing.
uint32_t read_errs_
Number of errors when reading.
size_t getColumnCount() const
Returns the number of columns in the file.
Definition csv_file.h:419
static CSVRow EMPTY_ROW()
Represents empty row.
Definition csv_file.h:507
void setReadMsg(const std::string &read_msg)
Sets error message after row validation.
Definition csv_file.h:502
void append(const CSVRow &row) const
Writes the CSV row into the file.
Definition csv_file.cc:173
bool valid() const
Checks if the CSV file is valid.
Definition csv_file.cc:142
size_t getColumnIndex(const std::string &col_name) const
Returns the index of the column having specified name.
Definition csv_file.cc:257
Represents a single row of the CSV file.
Definition csv_file.h:59
T readAndConvertAt(const size_t at) const
Retrieves a value from the internal container.
Definition csv_file.h:164
std::string readAtEscaped(const size_t at) const
Retrieves a value from the internal container, free of escaped characters.
Definition csv_file.cc:67
void writeAt(const size_t at, const char *value)
Replaces the value at specified index.
Definition csv_file.cc:85
std::string readAt(const size_t at) const
Retrieves a value from the internal container.
Definition csv_file.cc:61
void writeAtEscaped(const size_t at, const std::string &value)
Replaces the value at the specified index with a value that has had special characters escaped.
Definition csv_file.cc:91
A template representing an optional value.
Definition optional.h:37
virtual void open(const bool seek_to_end=false)
Opens existing file or creates a new one.
VersionedCSVFile(const std::string &filename)
Constructor.
void setMinimumValidColumns(const std::string &column_name)
Sets the minimum number of valid columns based on a given column.
bool next(CSVRow &row)
Reads next row from the file file.
void addColumn(const std::string &col_name, const std::string &version, const std::string &default_value="")
Adds metadata for a single column to the schema.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
static const uint32_t HWADDR_SOURCE_UNKNOWN
Used when actual origin is not known, e.g.
Definition hwaddr.h:41
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition macros.h:26
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:30
isc::log::Logger dhcpsrv_logger("dhcpsrv")
DHCP server library Logger.
Definition dhcpsrv_log.h:56
const isc::log::MessageID DHCPSRV_MEMFILE_READ_HWADDR_FAIL
boost::shared_ptr< DUID > DuidPtr
Definition duid.h:136
boost::shared_ptr< Lease6 > Lease6Ptr
Pointer to a Lease6 structure.
Definition lease.h:528
boost::shared_ptr< HWAddr > HWAddrPtr
Shared pointer to a hardware address structure.
Definition hwaddr.h:154
uint32_t SubnetID
Defines unique IPv4 or IPv6 subnet identifier.
Definition subnet_id.h:25
@ HTYPE_UNDEFINED
not specified or undefined
Definition dhcp4.h:55
@ HTYPE_ETHER
Ethernet 10Mbps.
Definition dhcp4.h:56
Defines the logger used by the top-level component of kea-lfc.
data::ConstElementPtr getContext() const
Returns const pointer to the user context.
static HWAddr fromText(const std::string &text, const uint16_t htype=HTYPE_ETHER)
Creates instance of the hardware address from textual format.
Definition hwaddr.cc:62
Structure that holds a lease for IPv6 address and/or prefix.
Definition lease.h:536
Lease::Type type_
Lease type.
Definition lease.h:541
uint32_t iaid_
Identity Association Identifier (IAID).
Definition lease.h:553
uint32_t preferred_lft_
Preferred lifetime.
Definition lease.h:562
DuidPtr duid_
Client identifier.
Definition lease.h:556
uint8_t prefixlen_
IPv6 prefix length.
Definition lease.h:546
static constexpr uint32_t STATE_DECLINED
Declined lease.
Definition lease.h:72
SubnetID subnet_id_
Subnet identifier.
Definition lease.h:160
uint32_t pool_id_
The pool id.
Definition lease.h:165
uint32_t valid_lft_
Valid lifetime.
Definition lease.h:131
static std::string basicStatesToText(const uint32_t state)
Returns name(s) of the basic lease state(s).
Definition lease.cc:89
std::string hostname_
Client hostname.
Definition lease.h:170
uint32_t state_
Holds the lease state(s).
Definition lease.h:196
Type
Type of lease or pool.
Definition lease.h:46
@ TYPE_PD
the lease contains IPv6 prefix (for prefix delegation)
Definition lease.h:49
bool fqdn_fwd_
Forward zone updated?
Definition lease.h:175
time_t cltt_
Client last transmission time.
Definition lease.h:149
HWAddrPtr hwaddr_
Client's MAC/hardware address.
Definition lease.h:185
bool fqdn_rev_
Reverse zone updated?
Definition lease.h:180
isc::asiolink::IOAddress addr_
IPv4 ot IPv6 address.
Definition lease.h:126