Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : * Copyright Contributors to the OpenSDN project
4 : */
5 :
6 : #include <stdint.h>
7 : #include "vr_defs.h"
8 : #include "cmn/agent_cmn.h"
9 : #include "pkt/pkt_init.h"
10 : #include "oper/vn.h"
11 : #include "services/dhcp_proto.h"
12 : #include "services/dhcpv6_proto.h"
13 : #include "services/services_types.h"
14 : #include "services/services_init.h"
15 : #include "services/dns_proto.h"
16 : #include "services/services_sandesh.h"
17 : #include "bind/bind_util.h"
18 :
19 : #include <boost/assign/list_of.hpp>
20 : #include <boost/scoped_array.hpp>
21 : #include <bind/bind_util.h>
22 :
23 : using namespace boost::assign;
24 :
25 0 : DhcpHandlerBase::DhcpHandlerBase(Agent *agent, boost::shared_ptr<PktInfo> info,
26 0 : boost::asio::io_context &io)
27 0 : : ProtoHandler(agent, info, io), vm_itf_(NULL), vm_itf_index_(-1),
28 0 : option_(NULL), flags_(), dns_enable_(true),
29 0 : host_routes_level_(Invalid) {
30 0 : ipam_type_.ipam_dns_method = "none";
31 0 : }
32 :
33 0 : DhcpHandlerBase::~DhcpHandlerBase() {
34 0 : }
35 :
36 : // Add option taking no data (length = 0)
37 0 : uint16_t DhcpHandlerBase::AddNoDataOption(uint32_t option, uint16_t opt_len) {
38 0 : option_->WriteData(option, 0, NULL, &opt_len);
39 0 : return opt_len;
40 : }
41 :
42 : // Add option taking a byte from input
43 0 : uint16_t DhcpHandlerBase::AddByteOption(uint32_t option, uint16_t opt_len,
44 : const std::string &input) {
45 0 : std::stringstream value(input);
46 0 : uint32_t data = 0;
47 0 : value >> data;
48 0 : if (value.bad() || value.fail() || data > 0xFF) {
49 0 : DHCP_BASE_TRACE("Invalid DHCP option " << option << " data : " <<
50 : input << "is invalid");
51 : } else {
52 0 : uint8_t byte = (uint8_t)data;
53 0 : option_->WriteData(option, 1, &byte, &opt_len);
54 : }
55 0 : return opt_len;
56 0 : }
57 :
58 : // Add option taking array of bytes from input
59 0 : uint16_t DhcpHandlerBase::AddByteArrayOption(uint32_t option, uint16_t opt_len,
60 : const std::string &input) {
61 0 : option_->WriteData(option, 0, NULL, &opt_len);
62 0 : std::stringstream value(input);
63 0 : bool done = false;
64 0 : uint32_t byte = 0;
65 0 : value >> byte;
66 0 : while (!value.bad() && !value.fail() && byte <= 0xFF) {
67 0 : option_->AppendData(1, &byte, &opt_len);
68 0 : if (value.eof()) {
69 0 : done = true;
70 0 : break;
71 : }
72 0 : value >> byte;
73 : }
74 :
75 : // if atleast one byte is not added or in case of error, ignore this option
76 0 : if (!option_->GetLen() || !done) {
77 0 : DHCP_BASE_TRACE("Invalid DHCP option " << option << " data : " <<
78 : input << "is invalid");
79 0 : return opt_len - option_->GetLen() - option_->GetFixedLen();
80 : }
81 :
82 0 : return opt_len;
83 0 : }
84 :
85 : // Add option taking a byte followed by a string, from input
86 0 : uint16_t DhcpHandlerBase::AddByteStringOption(uint32_t option, uint16_t opt_len,
87 : const std::string &input) {
88 0 : std::stringstream value(input);
89 0 : uint32_t data = 0;
90 0 : value >> data;
91 0 : if (value.fail() || value.bad() || data > 0xFF) {
92 0 : DHCP_BASE_TRACE("Invalid DHCP option " << option << " data : " <<
93 : input << "is invalid");
94 0 : return opt_len;
95 : }
96 :
97 0 : uint8_t byte = (uint8_t)data;
98 0 : std::string str;
99 0 : value >> str;
100 0 : option_->WriteData(option, 1, &byte, &opt_len);
101 0 : option_->AppendData(str.length(), str.c_str(), &opt_len);
102 :
103 0 : return opt_len;
104 0 : }
105 :
106 : // Add option taking a byte followed by one or more IPs, from input
107 0 : uint16_t DhcpHandlerBase::AddByteIPOption(uint32_t option, uint16_t opt_len,
108 : const std::string &input) {
109 0 : std::stringstream value(input);
110 0 : uint32_t data = 0;
111 0 : value >> data;
112 0 : uint8_t byte = (uint8_t)data;
113 :
114 0 : if (value.fail() || value.bad() || data > 0xFF) {
115 0 : DHCP_BASE_TRACE("Invalid DHCP option " << option << " data : " <<
116 : input << "is invalid");
117 0 : return opt_len;
118 : }
119 :
120 0 : option_->WriteData(option, 1, &byte, &opt_len);
121 0 : while (value.good()) {
122 0 : std::string ipstr;
123 0 : value >> ipstr;
124 0 : opt_len = AddIP(opt_len, ipstr);
125 0 : }
126 :
127 : // if atleast one IP is not added, ignore this option
128 0 : if (option_->GetLen() == 1) {
129 0 : DHCP_BASE_TRACE("Invalid DHCP option " << option << " data : " <<
130 : input << "is invalid");
131 0 : return opt_len - option_->GetLen() - option_->GetFixedLen();
132 : }
133 :
134 0 : return opt_len;
135 0 : }
136 :
137 : // Add option taking string from input
138 0 : uint16_t DhcpHandlerBase::AddStringOption(uint32_t option, uint16_t opt_len,
139 : const std::string &input) {
140 0 : option_->WriteData(option, input.length(), input.c_str(), &opt_len);
141 0 : return opt_len;
142 : }
143 :
144 : // Add option taking integer from input
145 0 : uint16_t DhcpHandlerBase::AddIntegerOption(uint32_t option, uint16_t opt_len,
146 : const std::string &input) {
147 0 : std::stringstream value(input);
148 0 : uint32_t data = 0;
149 0 : value >> data;
150 0 : if (value.bad() || value.fail()) {
151 0 : DHCP_BASE_TRACE("Invalid DHCP option " << option << " data : " <<
152 : input << "is invalid");
153 : } else {
154 0 : data = htonl(data);
155 0 : option_->WriteData(option, 4, &data, &opt_len);
156 : }
157 0 : return opt_len;
158 0 : }
159 :
160 : // Add option taking array of short from input
161 0 : uint16_t DhcpHandlerBase::AddShortArrayOption(uint32_t option, uint16_t opt_len,
162 : const std::string &input,
163 : bool array) {
164 0 : option_->WriteData(option, 0, NULL, &opt_len);
165 0 : std::stringstream value(input);
166 0 : uint16_t data = 0;
167 0 : value >> data;
168 0 : while (!value.bad() && !value.fail()) {
169 0 : data = htons(data);
170 0 : option_->AppendData(2, &data, &opt_len);
171 0 : if (!array || value.eof()) break;
172 0 : value >> data;
173 : }
174 :
175 : // if atleast one short is not added, ignore this option
176 0 : if (!option_->GetLen() || !value.eof()) {
177 0 : DHCP_BASE_TRACE("Invalid DHCP option " << option << " data : " <<
178 : input << "is invalid");
179 0 : return opt_len - option_->GetLen() - option_->GetFixedLen();
180 : }
181 :
182 0 : return opt_len;
183 0 : }
184 :
185 : // Check for exceptions in handling IP options
186 0 : bool DhcpHandlerBase::IsValidIpOption(uint32_t option, const std::string &ipstr,
187 : bool is_v4) {
188 0 : boost::system::error_code ec;
189 0 : if (is_v4) {
190 0 : if (option == DHCP_OPTION_DNS) {
191 0 : return IsValidDnsOption(option, ipstr);
192 : } else {
193 0 : uint32_t ip = Ip4Address::from_string(ipstr, ec).to_ulong();
194 0 : if(!ec.value() && !ip) {
195 0 : return false;
196 : }
197 : }
198 :
199 : } else {
200 0 : if (option == DHCPV6_OPTION_DNS_SERVERS) {
201 0 : return IsValidDnsOption(option, ipstr);
202 : } else {
203 0 : IpAddress ip = IpAddress::from_string(ipstr, ec);
204 0 : if (!ec.value() && ip.is_unspecified()) {
205 0 : return false;
206 : }
207 : }
208 : }
209 :
210 0 : return true;
211 : }
212 :
213 0 : bool DhcpHandlerBase::IsValidDnsOption(uint32_t option,
214 : const std::string &ipstr) {
215 0 : boost::system::error_code ec;
216 0 : IpAddress ip = IpAddress::from_string(ipstr, ec);
217 0 : if (!ec.value()) {
218 : // when DNS server is present in DHCP option, disable vrouter
219 : // proxying for DNS requests from VMs.
220 0 : dns_enable_ = false;
221 0 : if (ip.is_unspecified()) {
222 : // Do not send the option when DNS servers have 0.0.0.0 or ::
223 : // Set option flag so that they are not added later
224 0 : set_flag(option);
225 0 : return false;
226 : }
227 : }
228 :
229 0 : return true;
230 : }
231 :
232 : // Add option taking number of Ipv4 addresses
233 0 : uint16_t DhcpHandlerBase::AddIpv4Option(uint32_t option, uint16_t opt_len,
234 : const std::string &input,
235 : uint8_t min_count,
236 : uint8_t max_count,
237 : uint8_t multiples) {
238 0 : option_->WriteData(option, 0, NULL, &opt_len);
239 0 : std::stringstream value(input);
240 0 : while (value.good()) {
241 0 : std::string ipstr;
242 0 : value >> ipstr;
243 0 : if (!IsValidIpOption(option, ipstr, true)) {
244 0 : return opt_len - option_->GetLen() - option_->GetFixedLen();
245 : }
246 0 : opt_len = AddIP(opt_len, ipstr);
247 0 : }
248 :
249 0 : if (option == DHCP_OPTION_ROUTER) {
250 : // Add our gw as well
251 0 : if (!config_.gw_addr.is_unspecified()) {
252 0 : opt_len = AddIP(opt_len, config_.gw_addr.to_string());
253 : }
254 : }
255 :
256 : // check that atleast min_count IP addresses are added
257 0 : if (min_count && option_->GetLen() < min_count * 4) {
258 0 : DHCP_BASE_TRACE("Invalid DHCP option " << option << " data : " <<
259 : input << "is invalid");
260 0 : return opt_len - option_->GetLen() - option_->GetFixedLen();
261 : }
262 :
263 : // if specified, check that we dont add more than max_count IP addresses
264 0 : if (max_count && option_->GetLen() > max_count * 4) {
265 0 : DHCP_BASE_TRACE("Invalid DHCP option " << option << " data : " <<
266 : input << "is invalid");
267 0 : return opt_len - option_->GetLen() - option_->GetFixedLen();
268 : }
269 :
270 : // if specified, check that we add in multiples of IP addresses
271 0 : if (multiples && option_->GetLen() % (multiples * 4)) {
272 0 : DHCP_BASE_TRACE("Invalid DHCP option " << option << " data : " <<
273 : input << "is invalid");
274 0 : return opt_len - option_->GetLen() - option_->GetFixedLen();
275 : }
276 :
277 0 : return opt_len;
278 0 : }
279 :
280 : // Add option taking number of Ipv6 addresses
281 0 : uint16_t DhcpHandlerBase::AddIpv6Option(uint32_t option, uint16_t opt_len,
282 : const std::string &input, bool list) {
283 0 : option_->WriteData(option, 0, NULL, &opt_len);
284 0 : std::stringstream value(input);
285 0 : while (value.good()) {
286 0 : std::string ipstr;
287 0 : value >> ipstr;
288 0 : if (!IsValidIpOption(option, ipstr, false)) {
289 0 : return opt_len - option_->GetLen() - option_->GetFixedLen();
290 : }
291 0 : opt_len = AddIP(opt_len, ipstr);
292 0 : if (!list) break;
293 0 : }
294 :
295 : // check that atleast one IP address is added
296 0 : if (option_->GetLen() < 16) {
297 0 : DHCPV6_TRACE(Error, "Invalid DHCP option " << option << " for VM " <<
298 : config_.ip_addr.to_string() << "; data missing");
299 0 : return opt_len - option_->GetLen() - option_->GetFixedLen();
300 : }
301 :
302 0 : return opt_len;
303 0 : }
304 :
305 : // Add option taking compressed name
306 0 : uint16_t DhcpHandlerBase::AddCompressedNameOption(uint32_t option,
307 : uint16_t opt_len,
308 : const std::string &input,
309 : bool list) {
310 0 : option_->WriteData(option, 0, NULL, &opt_len);
311 0 : std::stringstream value(input);
312 0 : while (value.good()) {
313 0 : std::string str;
314 0 : value >> str;
315 0 : if (str.size()) {
316 0 : opt_len = AddCompressedName(opt_len, str);
317 0 : if (!list) break;
318 : }
319 0 : }
320 :
321 0 : if (!option_->GetLen()) {
322 0 : DHCP_BASE_TRACE("Invalid DHCP option " << option << " data : " <<
323 : input << "is invalid");
324 0 : return opt_len - option_->GetLen() - option_->GetFixedLen();
325 : }
326 :
327 0 : return opt_len;
328 0 : }
329 :
330 : // Add option taking a byte followed by a compressed name
331 0 : uint16_t DhcpHandlerBase::AddByteCompressedNameOption(uint32_t option,
332 : uint16_t opt_len,
333 : const std::string &input) {
334 0 : option_->WriteData(option, 0, NULL, &opt_len);
335 :
336 0 : std::stringstream value(input);
337 0 : uint32_t data = 0;
338 0 : value >> data;
339 0 : if (value.bad() || value.fail() || data > 0xFF) {
340 0 : DHCP_BASE_TRACE("Invalid DHCP option " << option << " data : " <<
341 : input << "is invalid");
342 0 : return opt_len - option_->GetLen() - option_->GetFixedLen();
343 : } else {
344 0 : uint8_t byte = (uint8_t)data;
345 0 : option_->WriteData(option, 1, &byte, &opt_len);
346 : }
347 :
348 0 : std::string str;
349 0 : value >> str;
350 0 : if (value.bad() || value.fail() || !str.size()) {
351 0 : DHCP_BASE_TRACE("Invalid DHCP option " << option << " data : " <<
352 : input << "is invalid");
353 0 : return opt_len - option_->GetLen() - option_->GetFixedLen();
354 : }
355 0 : return AddCompressedName(opt_len, str);
356 0 : }
357 :
358 0 : uint16_t DhcpHandlerBase::AddCompressedName(uint16_t opt_len,
359 : const std::string &input) {
360 0 : boost::scoped_array<uint8_t> name(new uint8_t[input.size() * 2 + 2]);
361 0 : uint16_t len = 0;
362 0 : BindUtil::AddName(name.get(), input, 0, 0, len);
363 0 : option_->AppendData(len, name.get(), &opt_len);
364 0 : return opt_len;
365 0 : }
366 :
367 : // Add an DNS server addresses from IPAM to the option
368 : // Option code and len are added already; add only the addresses
369 0 : uint16_t DhcpHandlerBase::AddDnsServers(uint16_t opt_len) {
370 0 : if (ipam_type_.ipam_dns_method == "default-dns-server" ||
371 0 : ipam_type_.ipam_dns_method == "virtual-dns-server" ||
372 0 : ipam_type_.ipam_dns_method == "none" ||
373 0 : ipam_type_.ipam_dns_method == "") {
374 0 : if (!config_.dns_addr.is_unspecified()) {
375 0 : opt_len = AddIP(opt_len, config_.dns_addr.to_string());
376 : }
377 0 : } else if (ipam_type_.ipam_dns_method == "tenant-dns-server") {
378 0 : for (unsigned int i = 0; i < ipam_type_.ipam_dns_server.
379 0 : tenant_dns_server_address.ip_address.size(); ++i) {
380 0 : opt_len = AddIP(opt_len, ipam_type_.ipam_dns_server.
381 0 : tenant_dns_server_address.ip_address[i]);
382 : }
383 : }
384 0 : return opt_len;
385 : }
386 :
387 : // Read the list of <subnet/plen, gw> from input and store them
388 : // for later processing in AddClasslessRouteOption
389 0 : void DhcpHandlerBase::ReadClasslessRoute(uint32_t option, uint16_t opt_len,
390 : const std::string &input) {
391 0 : std::stringstream value(input);
392 0 : while (value.good()) {
393 0 : std::string snetstr;
394 0 : value >> snetstr;
395 0 : OperDhcpOptions::HostRoute host_route;
396 0 : boost::system::error_code ec = Ip4PrefixParse(snetstr, &host_route.prefix_,
397 : (int *)&host_route.plen_);
398 0 : if (ec || host_route.plen_ > 32 || !value.good()) {
399 0 : DHCP_BASE_TRACE("Invalid Classless route DHCP option -"
400 : "has to be list of <subnet/plen gw>");
401 0 : break;
402 : }
403 :
404 0 : value >> snetstr;
405 0 : host_route.gw_ = Ip4Address::from_string(snetstr, ec);
406 0 : if (ec) {
407 0 : host_route.gw_ = Ip4Address();
408 : }
409 :
410 0 : host_routes_.push_back(host_route);
411 0 : }
412 0 : }
413 :
414 : // Add host route options coming via config. Config priority is
415 : // 1) options at VM interface level (host routes specifically set)
416 : // 2) options at VM interface level (classless routes from --extra-dhcp-opts)
417 : // 3) options at subnet level (host routes at subnet level - neutron config)
418 : // 4) options at subnet level (classless routes from dhcp options)
419 : // 5) options at IPAM level (host routes from IPAM)
420 : // 6) options at IPAM level (classless routes from IPAM dhcp options)
421 : // Add the options defined at the highest level in priority
422 0 : uint16_t DhcpHandlerBase::AddClasslessRouteOption(uint16_t opt_len) {
423 0 : std::vector<OperDhcpOptions::HostRoute> host_routes;
424 : do {
425 : // Port specific host route options
426 : // TODO: should we remove host routes at port level from schema ?
427 0 : if (vm_itf_->oper_dhcp_options().are_host_routes_set()) {
428 0 : host_routes = vm_itf_->oper_dhcp_options().host_routes();
429 0 : break;
430 : }
431 : // Host routes from port specific DHCP options (neutron configuration)
432 0 : if (host_routes_level_ == InterfaceLevel && host_routes_.size()) {
433 0 : host_routes.swap(host_routes_);
434 0 : break;
435 : }
436 :
437 0 : if (vm_itf_->vn()) {
438 0 : Ip4Address ip = config_.ip_addr.to_v4();
439 0 : const std::vector<VnIpam> &vn_ipam = vm_itf_->vn()->GetVnIpam();
440 : uint32_t index;
441 0 : for (index = 0; index < vn_ipam.size(); ++index) {
442 0 : if (vn_ipam[index].IsSubnetMember(ip)) {
443 0 : break;
444 : }
445 : }
446 0 : if (index < vn_ipam.size()) {
447 : // Subnet level host route options
448 : // Preference to host routes at subnet (neutron configuration)
449 0 : if (vn_ipam[index].oper_dhcp_options.are_host_routes_set()) {
450 0 : host_routes = vn_ipam[index].oper_dhcp_options.host_routes();
451 0 : break;
452 : }
453 : // Host route options from subnet level DHCP options
454 0 : if (host_routes_level_ == SubnetLevel && host_routes_.size()) {
455 0 : host_routes.swap(host_routes_);
456 0 : break;
457 : }
458 : }
459 :
460 : // TODO: should remove host routes at VN level from schema ?
461 0 : vm_itf_->vn()->GetVnHostRoutes(ipam_name_, &host_routes);
462 0 : if (host_routes.size() > 0)
463 0 : break;
464 : }
465 :
466 : // IPAM level host route options
467 0 : OperDhcpOptions oper_dhcp_options;
468 0 : oper_dhcp_options.update_host_routes(ipam_type_.host_routes.route);
469 0 : host_routes = oper_dhcp_options.host_routes();
470 :
471 : // Host route options from IPAM level DHCP options
472 0 : if (!host_routes.size() && host_routes_.size()) {
473 0 : host_routes.swap(host_routes_);
474 0 : break;
475 : }
476 0 : } while (false);
477 :
478 0 : if (host_routes.size()) {
479 0 : option_->SetCode(DHCP_OPTION_CLASSLESS_ROUTE);
480 0 : uint8_t *ptr = option_->GetData();
481 0 : uint8_t len = 0;
482 0 : for (uint32_t i = 0; i < host_routes.size(); ++i) {
483 0 : uint32_t prefix = host_routes[i].prefix_.to_ulong();
484 0 : uint32_t plen = host_routes[i].plen_;
485 0 : uint32_t gw = host_routes[i].gw_.to_ulong();
486 0 : *ptr++ = plen;
487 0 : len++;
488 0 : for (unsigned int j = 0; plen && j <= (plen - 1) / 8; ++j) {
489 0 : *ptr++ = (prefix >> 8 * (3 - j)) & 0xFF;
490 0 : len++;
491 : }
492 : // if GW is not specified, set it to subnet's GW
493 0 : if (gw)
494 0 : *(uint32_t *)ptr = htonl(gw);
495 : else
496 0 : *(uint32_t *)ptr = htonl(config_.gw_addr.to_v4().to_ulong());
497 0 : ptr += sizeof(uint32_t);
498 0 : len += sizeof(uint32_t);
499 : }
500 0 : option_->SetLen(len);
501 0 : opt_len += 2 + len;
502 0 : set_flag(DHCP_OPTION_CLASSLESS_ROUTE);
503 : }
504 0 : return opt_len;
505 0 : }
506 :
507 0 : uint16_t DhcpHandlerBase::AddDhcpOptions(
508 : uint16_t opt_len,
509 : std::vector<autogen::DhcpOptionType> &options,
510 : DhcpOptionLevel level) {
511 0 : for (unsigned int i = 0; i < options.size(); ++i) {
512 : // get the option code
513 0 : uint32_t option = OptionCode(options[i].dhcp_option_name);
514 0 : if (!option) {
515 0 : DHCP_BASE_TRACE("Invalid DHCP option " <<
516 : options[i].dhcp_option_name);
517 0 : continue;
518 0 : }
519 :
520 : // if option is already set in the response (from higher level), ignore
521 0 : if (is_flag_set(option))
522 0 : continue;
523 :
524 0 : uint16_t old_opt_len = opt_len;
525 0 : DhcpOptionCategory category = OptionCategory(option);
526 0 : option_->SetNextOptionPtr(opt_len);
527 :
528 : // if dhcp_option_value_bytes is set, use that for supported categories
529 0 : std::string &opt_value = options[i].dhcp_option_value;
530 0 : if (!options[i].dhcp_option_value_bytes.empty() &&
531 0 : CanOverrideWithBytes(category)) {
532 0 : category = ByteArray;
533 0 : opt_value = options[i].dhcp_option_value_bytes;
534 : }
535 :
536 0 : switch(category) {
537 0 : case None:
538 0 : break;
539 :
540 0 : case NoData:
541 0 : opt_len = AddNoDataOption(option, opt_len);
542 0 : break;
543 :
544 0 : case Bool:
545 : case Byte:
546 0 : opt_len = AddByteOption(option, opt_len,
547 0 : options[i].dhcp_option_value);
548 0 : break;
549 :
550 0 : case ByteArray:
551 0 : opt_len = AddByteArrayOption(option, opt_len, opt_value);
552 0 : break;
553 :
554 0 : case ByteString:
555 0 : opt_len = AddByteStringOption(option, opt_len,
556 0 : options[i].dhcp_option_value);
557 0 : break;
558 :
559 0 : case ByteOneIPPlus:
560 0 : opt_len = AddByteIPOption(option, opt_len,
561 0 : options[i].dhcp_option_value);
562 0 : break;
563 :
564 0 : case String:
565 0 : opt_len = AddStringOption(option, opt_len,
566 0 : options[i].dhcp_option_value);
567 0 : break;
568 :
569 0 : case Int32bit:
570 : case Uint32bit:
571 0 : if (option == DHCP_OPTION_IP_LEASE_TIME) {
572 0 : set_flag(DHCP_OPTION_IP_LEASE_TIME);
573 : }
574 0 : opt_len = AddIntegerOption(option, opt_len,
575 0 : options[i].dhcp_option_value);
576 0 : break;
577 :
578 0 : case Uint16bit:
579 0 : opt_len = AddShortArrayOption(option, opt_len,
580 0 : options[i].dhcp_option_value,
581 : false);
582 0 : break;
583 :
584 0 : case Uint16bitArray:
585 0 : opt_len = AddShortArrayOption(option, opt_len,
586 0 : options[i].dhcp_option_value,
587 : true);
588 0 : break;
589 :
590 0 : case OneIPv4:
591 0 : opt_len = AddIpv4Option(option, opt_len,
592 0 : options[i].dhcp_option_value, 1, 1, 0);
593 0 : break;
594 :
595 0 : case ZeroIPv4Plus:
596 0 : opt_len = AddIpv4Option(option, opt_len,
597 0 : options[i].dhcp_option_value, 0, 0, 0);
598 0 : break;
599 :
600 0 : case OneIPv4Plus:
601 0 : if (option == DHCP_OPTION_ROUTER) {
602 : // Router option is added later
603 0 : routers_ = options[i].dhcp_option_value;
604 0 : set_flag(DHCP_OPTION_ROUTER);
605 : } else {
606 0 : opt_len = AddIpv4Option(option, opt_len,
607 0 : options[i].dhcp_option_value,
608 : 1, 0, 0);
609 : }
610 0 : break;
611 :
612 0 : case TwoIPv4Plus:
613 0 : opt_len = AddIpv4Option(option, opt_len,
614 0 : options[i].dhcp_option_value, 2, 0, 2);
615 0 : break;
616 :
617 0 : case OneIPv6:
618 0 : opt_len = AddIpv6Option(option, opt_len,
619 0 : options[i].dhcp_option_value,
620 : false);
621 0 : break;
622 :
623 0 : case OneIPv6Plus:
624 0 : opt_len = AddIpv6Option(option, opt_len,
625 0 : options[i].dhcp_option_value,
626 : true);
627 0 : break;
628 :
629 0 : case ClasslessRoute:
630 0 : ReadClasslessRoute(option, opt_len,
631 0 : options[i].dhcp_option_value);
632 0 : if (host_routes_.size()) {
633 : // set flag & level for classless route so that we dont
634 : // update these at other level (subnet or ipam)
635 0 : set_flag(DHCP_OPTION_CLASSLESS_ROUTE);
636 0 : host_routes_level_ = level;
637 : }
638 0 : break;
639 :
640 0 : case NameCompression:
641 0 : opt_len = AddCompressedNameOption(option, opt_len,
642 0 : options[i].dhcp_option_value,
643 : false);
644 0 : break;
645 :
646 0 : case NameCompressionArray:
647 0 : opt_len = AddCompressedNameOption(option, opt_len,
648 0 : options[i].dhcp_option_value,
649 : true);
650 0 : break;
651 :
652 0 : case ByteNameCompression:
653 0 : opt_len = AddByteCompressedNameOption(option, opt_len,
654 0 : options[i].dhcp_option_value);
655 0 : break;
656 :
657 0 : default:
658 0 : DHCP_BASE_TRACE("Invalid DHCP option " <<
659 : options[i].dhcp_option_name);
660 0 : break;
661 : }
662 :
663 : // store siaddr for tftp server name to apply it later
664 0 : if (option == DHCP_OPTION_TFTP_SERVER_NAME) {
665 0 : boost::system::error_code ec;
666 : Ip4Address siaddr =
667 0 : Ip4Address::from_string(options[i].dhcp_option_value, ec);
668 0 : if (ec.value() == 0)
669 0 : siaddr_tftp_ = htonl(siaddr.to_ulong());
670 : }
671 :
672 0 : if (opt_len != old_opt_len)
673 0 : set_flag(option);
674 : }
675 :
676 0 : return opt_len;
677 : }
678 :
679 : // Add the option defined at the highest level in priority
680 : // Take all options defined at VM interface level, take those from subnet which
681 : // are not configured at interface, then take those from ipam which are not
682 : // configured at interface or subnet.
683 0 : uint16_t DhcpHandlerBase::AddConfigDhcpOptions(uint16_t opt_len, bool is_v6) {
684 0 : std::vector<autogen::DhcpOptionType> options;
685 0 : if (vm_itf_->GetInterfaceDhcpOptions(&options))
686 0 : opt_len = AddDhcpOptions(opt_len, options, InterfaceLevel);
687 :
688 0 : if (vm_itf_->GetSubnetDhcpOptions(&options, is_v6))
689 0 : opt_len = AddDhcpOptions(opt_len, options, SubnetLevel);
690 :
691 0 : if (vm_itf_->GetIpamDhcpOptions(&options, is_v6))
692 0 : opt_len = AddDhcpOptions(opt_len, options, IpamLevel);
693 :
694 0 : return opt_len;
695 0 : }
696 :
697 0 : void DhcpHandlerBase::FindDomainName(const IpAddress &vm_addr) {
698 0 : if (config_.lease_time != (uint32_t) -1 ||
699 0 : config_.valid_time != (uint32_t) -1)
700 0 : return;
701 :
702 0 : if (!vm_itf_->vn() ||
703 0 : !vm_itf_->vn()->GetIpamData(vm_addr, &ipam_name_, &ipam_type_)) {
704 0 : DHCP_BASE_TRACE("Ipam data not found");
705 0 : return;
706 : }
707 :
708 0 : if (ipam_type_.ipam_dns_method != "virtual-dns-server" ||
709 0 : !agent()->domain_config_table()->GetVDns(ipam_type_.ipam_dns_server.
710 0 : virtual_dns_server_name,
711 : &vdns_type_))
712 0 : return;
713 :
714 0 : if (config_.domain_name_.size() &&
715 0 : config_.domain_name_ != vdns_type_.domain_name) {
716 0 : DHCP_BASE_TRACE("Client domain " << config_.domain_name_ <<
717 : " doesnt match with configured domain " <<
718 : vdns_type_.domain_name);
719 : }
720 : std::size_t pos;
721 0 : if (config_.client_name_.size() &&
722 0 : ((pos = config_.client_name_.find('.', 0)) != std::string::npos) &&
723 0 : (config_.client_name_.substr(pos + 1) != vdns_type_.domain_name)) {
724 0 : DHCP_BASE_TRACE("Client domain doesnt match with configured domain "
725 : << vdns_type_.domain_name << "; Client name = "
726 : << config_.client_name_);
727 0 : config_.client_name_.replace(config_.client_name_.begin() + pos + 1,
728 0 : config_.client_name_.end(),
729 0 : vdns_type_.domain_name);
730 : }
731 :
732 0 : config_.domain_name_ = vdns_type_.domain_name;
733 : }
734 :
735 0 : bool DhcpHandlerBase::CanOverrideWithBytes(DhcpOptionCategory category) {
736 0 : if (category == ByteArray ||
737 0 : category == ByteString ||
738 0 : category == String ||
739 0 : category == NameCompression ||
740 0 : category == NameCompressionArray ||
741 : category == ByteNameCompression)
742 0 : return true;
743 :
744 0 : return false;
745 : }
|