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