client_class_def.cc 7.77 KB
Newer Older
1
// Copyright (C) 2015-2017 Internet Systems Consortium, Inc. ("ISC")
2
//
3
4
5
// 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/.
6

7
8
#include <config.h>

9
#include <dhcpsrv/client_class_def.h>
10
#include <dhcpsrv/cfgmgr.h>
11
#include <boost/foreach.hpp>
12

13
14
using namespace isc::data;

15
16
17
18
19
20
namespace isc {
namespace dhcp {

//********** ClientClassDef ******************//

ClientClassDef::ClientClassDef(const std::string& name,
Francis Dupont's avatar
Francis Dupont committed
21
                               const ExpressionPtr& match_expr,
22
                               const CfgOptionPtr& cfg_option)
23
    : name_(name), match_expr_(match_expr), cfg_option_(cfg_option),
Tomek Mrugalski's avatar
Tomek Mrugalski committed
24
      next_server_(asiolink::IOAddress::IPV4_ZERO_ADDRESS()) {
Francis Dupont's avatar
Francis Dupont committed
25

26
27
    // Name can't be blank
    if (name_.empty()) {
28
        isc_throw(BadValue, "Client Class name cannot be blank");
29
    }
30
31
32

    // We permit an empty expression for now.  This will likely be useful
    // for automatic classes such as vendor class.
33
34

    // For classes without options, make sure we have an empty collection
35
36
    if (!cfg_option_) {
        cfg_option_.reset(new CfgOption());
37
38
39
    }
}

40
ClientClassDef::ClientClassDef(const ClientClassDef& rhs)
41
    : name_(rhs.name_), match_expr_(ExpressionPtr()),
Tomek Mrugalski's avatar
Tomek Mrugalski committed
42
43
      cfg_option_(new CfgOption()),
      next_server_(asiolink::IOAddress::IPV4_ZERO_ADDRESS()) {
44
45
46
47
48
49

    if (rhs.match_expr_) {
        match_expr_.reset(new Expression());
        *match_expr_ = *(rhs.match_expr_);
    }

50
51
52
53
    if (rhs.cfg_option_def_) {
        rhs.cfg_option_def_->copyTo(*cfg_option_def_);
    }

54
55
56
    if (rhs.cfg_option_) {
        rhs.cfg_option_->copyTo(*cfg_option_);
    }
57
58
59
60

    next_server_ = rhs.next_server_;
    sname_ = rhs.sname_;
    filename_ = rhs.filename_;
61
62
}

63
64
65
66
67
68
69
70
71
72
ClientClassDef::~ClientClassDef() {
}

std::string
ClientClassDef::getName() const {
    return (name_);
}

void
ClientClassDef::setName(const std::string& name) {
Francis Dupont's avatar
Francis Dupont committed
73
    name_ = name;
74
75
76
77
78
79
80
81
82
}

const ExpressionPtr&
ClientClassDef::getMatchExpr() const {
    return (match_expr_);
}

void
ClientClassDef::setMatchExpr(const ExpressionPtr& match_expr) {
Francis Dupont's avatar
Francis Dupont committed
83
    match_expr_ = match_expr;
84
85
}

86
87
88
89
90
91
92
93
94
95
std::string
ClientClassDef::getTest() const {
    return (test_);
}

void
ClientClassDef::setTest(const std::string& test) {
    test_ = test;
}

96
97
98
99
100
101
102
103
104
105
const CfgOptionDefPtr&
ClientClassDef::getCfgOptionDef() const {
    return (cfg_option_def_);
}

void
ClientClassDef::setCfgOptionDef(const CfgOptionDefPtr& cfg_option_def) {
    cfg_option_def_ = cfg_option_def;
}

106
107
108
const CfgOptionPtr&
ClientClassDef::getCfgOption() const {
    return (cfg_option_);
109
110
111
}

void
112
113
ClientClassDef::setCfgOption(const CfgOptionPtr& cfg_option) {
    cfg_option_ = cfg_option;
114
115
}

116
117
118
119
bool
ClientClassDef::equals(const ClientClassDef& other) const {
    return ((name_ == other.name_) &&
        ((!match_expr_ && !other.match_expr_) ||
120
        (match_expr_ && other.match_expr_ &&
121
122
         (*match_expr_ == *(other.match_expr_)))) &&
        ((!cfg_option_ && !other.cfg_option_) ||
123
        (cfg_option_ && other.cfg_option_ &&
124
         (*cfg_option_ == *other.cfg_option_))) &&
125
126
127
        ((!cfg_option_def_ && !other.cfg_option_def_) ||
        (cfg_option_def_ && other.cfg_option_def_ &&
         (*cfg_option_def_ == *other.cfg_option_def_))) &&
128
129
130
            (next_server_ == other.next_server_) &&
            (sname_ == other.sname_) &&
            (filename_ == other.filename_));
131
132
}

133
134
ElementPtr
ClientClassDef:: toElement() const {
135
    uint16_t family = CfgMgr::instance().getFamily();
136
    ElementPtr result = Element::createMap();
137
138
    // Set user-context
    contextToElement(result);
139
140
    // Set name
    result->set("name", Element::create(name_));
141
142
143
144
    // Set original match expression (empty string won't parse)
    if (!test_.empty()) {
        result->set("test", Element::create(test_));
    }
145
146
    // Set option-def (used only by DHCPv4)
    if (cfg_option_def_ && (family == AF_INET)) {
147
148
        result->set("option-def", cfg_option_def_->toElement());
    }
149
150
    // Set option-data
    result->set("option-data", cfg_option_->toElement());
151
152
153
154
    if (family != AF_INET) {
        // Other parameters are DHCPv4 specific
        return (result);
    }
155
156
157
158
159
160
161
162
163
    // Set next-server
    result->set("next-server", Element::create(next_server_.toText()));
    // Set server-hostname
    result->set("server-hostname", Element::create(sname_));
    // Set boot-file-name
    result->set("boot-file-name", Element::create(filename_));
    return (result);
}

164
165
166
167
168
169
170
171
172
173
174
std::ostream& operator<<(std::ostream& os, const ClientClassDef& x) {
    os << "ClientClassDef:" << x.getName();
    return (os);
}

//********** ClientClassDictionary ******************//

ClientClassDictionary::ClientClassDictionary()
    : classes_(new ClientClassDefMap()) {
}

175
176
177
178
179
180
181
182
ClientClassDictionary::ClientClassDictionary(const ClientClassDictionary& rhs)
    : classes_(new ClientClassDefMap()) {
    BOOST_FOREACH(ClientClassMapPair cclass, *(rhs.classes_)) {
        ClientClassDefPtr copy(new ClientClassDef(*(cclass.second)));
        addClass(copy);
    }
}

183
184
185
186
187
ClientClassDictionary::~ClientClassDictionary() {
}

void
ClientClassDictionary::addClass(const std::string& name,
Francis Dupont's avatar
Francis Dupont committed
188
                                const ExpressionPtr& match_expr,
189
                                const std::string& test,
190
                                const CfgOptionPtr& cfg_option,
191
                                CfgOptionDefPtr cfg_option_def,
192
                                ConstElementPtr user_context,
193
                                asiolink::IOAddress next_server,
Tomek Mrugalski's avatar
Tomek Mrugalski committed
194
195
                                const std::string& sname,
                                const std::string& filename) {
196
    ClientClassDefPtr cclass(new ClientClassDef(name, match_expr, cfg_option));
197
    cclass->setTest(test);
198
    cclass->setCfgOptionDef(cfg_option_def);
199
    cclass->setContext(user_context),
200
201
202
    cclass->setNextServer(next_server);
    cclass->setSname(sname);
    cclass->setFilename(filename);
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
    addClass(cclass);
}

void
ClientClassDictionary::addClass(ClientClassDefPtr& class_def) {
    if (!class_def) {
        isc_throw(BadValue, "ClientClassDictionary::addClass "
                            " - class definition cannot be null");
    }

    if (findClass(class_def->getName())) {
        isc_throw(DuplicateClientClassDef, "Client Class: "
                  << class_def->getName() << " has already been defined");
    }

Francis Dupont's avatar
Francis Dupont committed
218
    (*classes_)[class_def->getName()] = class_def;
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
}

ClientClassDefPtr
ClientClassDictionary::findClass(const std::string& name) const {
    ClientClassDefMap::iterator it = classes_->find(name);
    if (it != classes_->end()) {
        return (*it).second;
    }

    return(ClientClassDefPtr());
}

void
ClientClassDictionary::removeClass(const std::string& name) {
    classes_->erase(name);
}

const ClientClassDefMapPtr&
ClientClassDictionary::getClasses() const {
    return (classes_);
}

241
242
243
244
245
246
247
248
bool
ClientClassDictionary::equals(const ClientClassDictionary& other) const {
    if (classes_->size() != other.classes_->size()) {
        return (false);
    }

    ClientClassDefMap::iterator this_class = classes_->begin();
    ClientClassDefMap::iterator other_class = other.classes_->begin();
249
    while (this_class != classes_->end() &&
250
           other_class != other.classes_->end()) {
251
        if (!(*this_class).second || !(*other_class).second ||
252
253
254
255
256
257
258
259
260
261
262
            (*(*this_class).second) != (*(*other_class).second)) {
                return false;
        }

        ++this_class;
        ++other_class;
    }

    return (true);
}

263
264
265
266
267
268
269
270
271
272
ElementPtr
ClientClassDictionary::toElement() const {
    ElementPtr result = Element::createList();
    // Iterate on the map
    for (ClientClassDefMap::iterator this_class = classes_->begin();
         this_class != classes_->end(); ++this_class) {
        result->add(this_class->second->toElement());
    }
    return (result);
}
273

274
275
} // namespace isc::dhcp
} // namespace isc