OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
dhcpv6_handler.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3  */
4 
5 #include <stdint.h>
6 #include "base/os.h"
7 #include "base/address_util.h"
8 #include "vr_defs.h"
9 #include "cmn/agent_cmn.h"
10 #include "oper/route_common.h"
11 #include "pkt/pkt_init.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"
17 #include "bind/bind_util.h"
18 #include "bind/xmpp_dns_agent.h"
19 
20 #include <boost/assign/list_of.hpp>
21 #include <boost/scoped_array.hpp>
22 using namespace boost::assign;
23 
24 // since the DHCPv4 and DHCPv6 option codes mean different things
25 // and since we get only one set of DHCP options from the config or
26 // from Neutron, it is assumed that if the option code is a number,
27 // it represents DHCPv4 code and the code string for DHCPv6 and
28 // DHCPv4 do not overlap.
30  map_list_of<std::string, uint32_t>
31  ("v6-client-id", DHCPV6_OPTION_CLIENTID)
32  ("v6-server-id", DHCPV6_OPTION_SERVERID)
33  ("v6-ia-na", DHCPV6_OPTION_IA_NA)
34  ("v6-ia-ta", DHCPV6_OPTION_IA_TA)
35  ("v6-ia-addr", DHCPV6_OPTION_IAADDR)
36  ("v6-oro", DHCPV6_OPTION_ORO)
37  ("v6-preference", DHCPV6_OPTION_PREFERENCE)
38  ("v6-elapsed-time", DHCPV6_OPTION_ELAPSED_TIME)
39  ("v6-relay-msg", DHCPV6_OPTION_RELAY_MSG)
40  ("v6-auth", DHCPV6_OPTION_AUTH)
41  ("v6-unicast", DHCPV6_OPTION_UNICAST)
42  ("v6-status-code", DHCPV6_OPTION_STATUS_CODE)
43  ("v6-rapid-commit", DHCPV6_OPTION_RAPID_COMMIT)
44  ("v6-user-class", DHCPV6_OPTION_USER_CLASS)
45  ("v6-vendor-class", DHCPV6_OPTION_VENDOR_CLASS)
46  ("v6-vendor-opts", DHCPV6_OPTION_VENDOR_OPTS)
47  ("v6-interface-id", DHCPV6_OPTION_INTERFACE_ID)
48  ("v6-reconf-msg", DHCPV6_OPTION_RECONF_MSG)
49  ("v6-reconf-accept", DHCPV6_OPTION_RECONF_ACCEPT)
50  ("v6-sip-server-names", DHCPV6_OPTION_SIP_SERVER_D)
51  ("v6-sip-server-addresses", DHCPV6_OPTION_SIP_SERVER_A)
52  ("v6-name-servers", DHCPV6_OPTION_DNS_SERVERS)
53  ("v6-domain-search", DHCPV6_OPTION_DOMAIN_LIST)
54  ("v6-ia-pd", DHCPV6_OPTION_IA_PD)
55  ("v6-ia-prefix", DHCPV6_OPTION_IAPREFIX)
56  ("v6-nis-servers", DHCPV6_OPTION_NIS_SERVERS)
57  ("v6-nisp-servers", DHCPV6_OPTION_NISP_SERVERS)
58  ("v6-nis-domain-name", DHCPV6_OPTION_NIS_DOMAIN_NAME)
59  ("v6-nisp-domain-name", DHCPV6_OPTION_NISP_DOMAIN_NAME)
60  ("v6-sntp-servers", DHCPV6_OPTION_SNTP_SERVERS)
61  ("v6-info-refresh-time", DHCPV6_OPTION_INFORMATION_REFRESH_TIME)
62  ("v6-bcms-server-d", DHCPV6_OPTION_BCMCS_SERVER_D)
63  ("v6-bcms-server-a", DHCPV6_OPTION_BCMCS_SERVER_A)
64  ("v6-geoconf-civic", DHCPV6_OPTION_GEOCONF_CIVIC)
65  ("v6-remote-id", DHCPV6_OPTION_REMOTE_ID)
66  ("v6-subscriber-id", DHCPV6_OPTION_SUBSCRIBER_ID)
67  ("v6-client-fqdn", DHCPV6_OPTION_CLIENT_FQDN)
68  ("v6-pana-agent", DHCPV6_OPTION_PANA_AGENT)
69  ("v6-posiz-timezone", DHCPV6_OPTION_NEW_POSIX_TIMEZONE)
70  ("v6-tzdc-timezone", DHCPV6_OPTION_NEW_TZDB_TIMEZONE)
71  ("v6-ero", DHCPV6_OPTION_ERO)
72  ("v6-lq-query", DHCPV6_OPTION_LQ_QUERY)
73  ("v6-client-data", DHCPV6_OPTION_CLIENT_DATA)
74  ("v6-clt-time", DHCPV6_OPTION_CLT_TIME)
75  ("v6-lq-relay-data", DHCPV6_OPTION_LQ_RELAY_DATA)
76  ("v6-lq-client-link", DHCPV6_OPTION_LQ_CLIENT_LINK)
77  ("mip6-hnidf", DHCPV6_OPTION_MIP6_HNIDF)
78  ("mip6-vdinf", DHCPV6_OPTION_MIP6_VDINF)
79  ("v6-lost", DHCPV6_OPTION_V6_LOST)
80  ("v6-capwap-ac", DHCPV6_OPTION_CAPWAP_AC_V6)
81  ("v6-relay-id", DHCPV6_OPTION_RELAY_ID)
82  ("v6-address-mos", DHCPV6_OPTION_IPv6_Address_MoS)
83  ("v6-fqdn-mos", DHCPV6_OPTION_IPv6_FQDN_MoS)
84  ("v6-ntp-server", DHCPV6_OPTION_NTP_SERVER)
85  ("v6-access-domain", DHCPV6_OPTION_V6_ACCESS_DOMAIN)
86  ("v6-sip-ua-cs-list", DHCPV6_OPTION_SIP_UA_CS_LIST)
87  ("v6-bootfile-url", DHCPV6_OPT_BOOTFILE_URL)
88  ("v6-bootfile-param", DHCPV6_OPT_BOOTFILE_PARAM)
89  ("v6-client-arch-type", DHCPV6_OPTION_CLIENT_ARCH_TYPE)
90  ("v6-nii", DHCPV6_OPTION_NII)
91  ("v6-geolocation", DHCPV6_OPTION_GEOLOCATION)
92  ("v6-aftr-name", DHCPV6_OPTION_AFTR_NAME)
93  ("v6-erp-local-domain-name", DHCPV6_OPTION_ERP_LOCAL_DOMAIN_NAME)
94  ("v6-rsoo", DHCPV6_OPTION_RSOO)
95  ("v6-pd-exclude", DHCPV6_OPTION_PD_EXCLUDE)
96  ("v6-vss", DHCPV6_OPTION_VSS)
97  ("mip6-idinf", DHCPV6_OPTION_MIP6_IDINF)
98  ("mip6-udinf", DHCPV6_OPTION_MIP6_UDINF)
99  ("mip6-hnp", DHCPV6_OPTION_MIP6_HNP)
100  ("mip6-haa", DHCPV6_OPTION_MIP6_HAA)
101  ("mip6-haf", DHCPV6_OPTION_MIP6_HAF)
102  ("v6-rdnss-selection", DHCPV6_OPTION_RDNSS_SELECTION)
103  ("v6-krb-principal-name", DHCPV6_OPTION_KRB_PRINCIPAL_NAME)
104  ("v6-krb-realm-name", DHCPV6_OPTION_KRB_REALM_NAME)
105  ("v6-krb-default-realm-name", DHCPV6_OPTION_KRB_DEFAULT_REALM_NAME)
106  ("v6-krb-kdc", DHCPV6_OPTION_KRB_KDC)
107  ("v6-client-linklayer-addr", DHCPV6_OPTION_CLIENT_LINKLAYER_ADDR)
108  ("v6-link-address", DHCPV6_OPTION_LINK_ADDRESS)
109  ("v6-radius", DHCPV6_OPTION_RADIUS)
110  ("v6-sol-max-rt", DHCPV6_OPTION_SOL_MAX_RT)
111  ("v6-inf-max-rt", DHCPV6_OPTION_INF_MAX_RT)
112  ("v6-addrsel", DHCPV6_OPTION_ADDRSEL)
113  ("v6-addrsel-table", DHCPV6_OPTION_ADDRSEL_TABLE)
114  ("v6-pcp-server", DHCPV6_OPTION_V6_PCP_SERVER)
115  ("v6-dhcpv4-msg", DHCPV6_OPTION_DHCPV4_MSG)
116  ("v6-dhcpv4-o-dhcpv6-server", DHCPV6_OPTION_DHCP4_O_DHCP6_SERVER)
117  ("v6-s46-rule", DHCPV6_OPTION_S46_RULE)
118  ("v6-s46-br", DHCPV6_OPTION_S46_BR)
119  ("v6-s46-dmr", DHCPV6_OPTION_S46_DMR)
120  ("v6-s46-v4v6bind", DHCPV6_OPTION_S46_V4V6BIND)
121  ("v6-s46-portparams", DHCPV6_OPTION_S46_PORTPARAMS)
122  ("v6-s46-cont-mape", DHCPV6_OPTION_S46_CONT_MAPE)
123  ("v6-s46-cont-mapt", DHCPV6_OPTION_S46_CONT_MAPT)
124  ("v6-s46-cont-lw", DHCPV6_OPTION_S46_CONT_LW)
125  ("v6-address-andsf", DHCPV6_OPTION_IPv6_ADDRESS_ANDSF);
126 
128  map_list_of<uint32_t, Dhcpv6Handler::DhcpOptionCategory>
129  // the following are sent from Agent
130  // (DHCPV6_OPTION_CLIENTID, Dhcpv6Handler::ByteArray)
131  // (DHCPV6_OPTION_SERVERID, Dhcpv6Handler::ByteArray)
132  // (DHCPV6_OPTION_IA_NA, Dhcpv6Handler::ByteArray)
133  // (DHCPV6_OPTION_IA_TA, Dhcpv6Handler::ByteArray)
134  // (DHCPV6_OPTION_IAADDR, Dhcpv6Handler::ByteArray)
135  // (DHCPV6_OPTION_ORO, Dhcpv6Handler::ByteArray)
137  // (DHCPV6_OPTION_ELAPSED_TIME, Dhcpv6Handler::Uint16bit)
138  // (DHCPV6_OPTION_RELAY_MSG, Dhcpv6Handler::ByteArray)
139  // (DHCPV6_OPTION_AUTH, Dhcpv6Handler::ByteArray)
140  // (DHCPV6_OPTION_UNICAST, Dhcpv6Handler::OneIPv6)
141  // (DHCPV6_OPTION_STATUS_CODE, Dhcpv6Handler::ByteArray)
225 
226 Dhcpv6Handler::Dhcpv6Handler(Agent *agent, boost::shared_ptr<PktInfo> info,
227  boost::asio::io_context &io)
228  : DhcpHandlerBase(agent, info, io),
229  msg_type_(DHCPV6_UNKNOWN), out_msg_type_(DHCPV6_UNKNOWN),
230  rapid_commit_(false), reconfig_accept_(false),
231  client_duid_len_(0), server_duid_len_(0),
232  client_duid_(NULL), server_duid_(NULL), is_ia_na_(true) {
233  memset(xid_, 0, sizeof(xid_));
234  option_.reset(new Dhcpv6OptionHandler(NULL));
235 }
236 
238 }
239 
241  Dhcpv6Proto *dhcp_proto = agent()->dhcpv6_proto();
242  // options length = pkt length - size of headers
243  int16_t options_len = pkt_info_->len -
244  (pkt_info_->data - (uint8_t *)pkt_info_->pkt)
246  if (options_len < 0) {
247  dhcp_proto->IncrStatsError();
248  DHCPV6_TRACE(Error, "Improper DHCPv6 packet length; vrf = " <<
249  pkt_info_->vrf << " ifindex = " << GetInterfaceIndex());
250  return true;
251  }
252 
253  dhcp_ = (Dhcpv6Hdr *) pkt_info_->data;
254  option_->SetDhcpOptionPtr((uint8_t *)dhcp_ + DHCPV6_FIXED_LEN);
255  // request_.UpdateData(dhcp_->xid, ntohs(dhcp_->flags), dhcp_->chaddr);
256  Interface *itf =
258  if (itf == NULL) {
259  dhcp_proto->IncrStatsError();
260  DHCPV6_TRACE(Error, "Received DHCP packet on invalid interface : "
261  << GetInterfaceIndex());
262  return true;
263  }
264 
265  if (itf->type() != Interface::VM_INTERFACE) {
266  dhcp_proto->IncrStatsError();
267  DHCPV6_TRACE(Error, "Received DHCP packet on non VM port interface : "
268  << GetInterfaceIndex());
269  return true;
270  }
271  vm_itf_ = static_cast<VmInterface *>(itf);
272  if (!vm_itf_->dhcp_enable_v6_config()) {
273  dhcp_proto->IncrStatsError();
274  DHCPV6_TRACE(Error, "DHCP request on VM port with dhcp services disabled: "
275  << GetInterfaceIndex());
276  return true;
277  }
278 
279  msg_type_ = dhcp_->type;
280  memcpy(xid_, dhcp_->xid, 3);
281  ReadOptions(options_len);
282 
283  switch (msg_type_) {
284  case DHCPV6_SOLICIT:
286  dhcp_proto->IncrStatsSolicit();
287  DHCPV6_TRACE(Trace, "DHCP solicit received on interface : "
288  << vm_itf_->name());
289  break;
290 
291  case DHCPV6_REQUEST:
293  dhcp_proto->IncrStatsRequest();
294  DHCPV6_TRACE(Trace, "DHCP request received on interface : "
295  << vm_itf_->name());
296  break;
297 
298  // TODO: following messages require special handling
299  case DHCPV6_CONFIRM:
301  dhcp_proto->IncrStatsConfirm();
302  DHCPV6_TRACE(Trace, "DHCP confirm received on interface : "
303  << vm_itf_->name());
304  break;
305 
306  case DHCPV6_RENEW:
308  dhcp_proto->IncrStatsRenew();
309  DHCPV6_TRACE(Trace, "DHCP renew received on interface : "
310  << vm_itf_->name());
311  break;
312 
313  case DHCPV6_REBIND:
315  dhcp_proto->IncrStatsRebind();
316  DHCPV6_TRACE(Trace, "DHCP bind received on interface : "
317  << vm_itf_->name());
318  break;
319 
320  case DHCPV6_RELEASE:
322  dhcp_proto->IncrStatsRelease();
323  DHCPV6_TRACE(Trace, "DHCP release received on interface : "
324  << vm_itf_->name());
325  break;
326 
327  case DHCPV6_DECLINE:
329  dhcp_proto->IncrStatsDecline();
330  DHCPV6_TRACE(Trace, "DHCP decline received on interface : "
331  << vm_itf_->name());
332  break;
333 
334  case DHCPV6_RECONFIGURE:
335  dhcp_proto->IncrStatsReconfigure();
336  DHCPV6_TRACE(Trace, "DHCP reconfigure received on interface : "
337  << vm_itf_->name());
338  break;
339 
341  dhcp_proto->IncrStatsInformationRequest();
343  "DHCP information request received on interface : "
344  << vm_itf_->name());
345  break;
346 
347  default:
348  DHCPV6_TRACE(Trace, "DHCP message " << msg_type_ <<
349  " received on interface : " << vm_itf_->name() <<
350  "; ignoring");
351  dhcp_proto->IncrStatsError();
352  return true;
353  }
354 
355  if (FindLeaseData()) {
357  DHCPV6_TRACE(Trace, "DHCP response sent; message = " <<
359  "; ip = " << config_.ip_addr.to_string());
360  }
361 
362  return true;
363 }
364 
365 // read DHCP options in the incoming packet
366 void Dhcpv6Handler::ReadOptions(int16_t opt_rem_len) {
367  Dhcpv6Options *opt = reinterpret_cast<Dhcpv6Options *>(
368  (uint8_t *)dhcp_ + DHCPV6_FIXED_LEN);
369  // parse thru the option fields
370  while (opt_rem_len > 0) {
371  uint16_t option_code = ntohs(opt->code);
372  uint16_t option_len = ntohs(opt->len);
373  if (option_len > opt_rem_len) {
374  DHCPV6_TRACE(Error, "DHCP option parsing error");
375  break;
376  }
377  switch (option_code) {
379  client_duid_len_ = option_len;
380  client_duid_.reset(new uint8_t[client_duid_len_]);
381  memcpy(client_duid_.get(), opt->data, client_duid_len_);
382  break;
383 
385  server_duid_len_ = option_len;
386  server_duid_.reset(new uint8_t[server_duid_len_]);
387  memcpy(server_duid_.get(), opt->data, server_duid_len_);
388  break;
389 
390  case DHCPV6_OPTION_IA_NA:
391  is_ia_na_ = true;
392  ReadIA(opt->data, option_len, option_code);
393  break;
394 
395  case DHCPV6_OPTION_IA_TA:
396  is_ia_na_ = false;
397  ReadIA(opt->data, option_len, option_code);
398  break;
399 
401  rapid_commit_ = true;
402  break;
403 
405  reconfig_accept_ = true;
406  break;
407 
408  case DHCPV6_OPTION_ORO: // list of requested options
409  case DHCPV6_OPTION_PREFERENCE: // server preference, sent by server
410  case DHCPV6_OPTION_ELAPSED_TIME: // time client has been trying
411  case DHCPV6_OPTION_RELAY_MSG: // relay DHCP types are not handled
412  case DHCPV6_OPTION_AUTH: // authentication
413  case DHCPV6_OPTION_UNICAST: // server option, sent to get ucast msgs
414  case DHCPV6_OPTION_USER_CLASS: // type of user
415  case DHCPV6_OPTION_VENDOR_CLASS: // vendor
417  case DHCPV6_OPTION_INTERFACE_ID: // used by relay agent
418  case DHCPV6_OPTION_RECONF_MSG: // can only appear in reconfigure msg
419  // ignore these options
420  break;
421 
422  default:
423  break;
424  }
425  opt_rem_len -= (4 + option_len);
426  opt = (Dhcpv6Options *)((uint8_t *)opt + 4 + option_len);
427  }
428 }
429 
430 bool Dhcpv6Handler::ReadIA(uint8_t *ptr, uint16_t len, uint16_t code) {
431  if (ia_na_.get() == NULL) {
432  ia_na_.reset(new Dhcpv6IaData());
433  }
434 
435  ia_na_->AddIa((Dhcpv6Ia *)ptr);
436 
437  int16_t iana_rem_len = len - sizeof(Dhcpv6Ia);
438  Dhcpv6Options *iana_option = (Dhcpv6Options *)(ptr + sizeof(Dhcpv6Ia));
439  while (iana_rem_len > 0) {
440  uint16_t iana_option_code = ntohs(iana_option->code);
441  uint16_t iana_option_len = ntohs(iana_option->len);
442  switch (iana_option_code) {
443  case DHCPV6_OPTION_IAADDR: {
444  ia_na_->AddIaAddr((Dhcpv6IaAddr *)iana_option->data);
445  break;
446  }
447 
449  uint16_t *s_ptr = reinterpret_cast<uint16_t *>
450  (iana_option->data);
451  uint16_t status = ntohs(*s_ptr);
452  if (status != DHCPV6_SUCCESS) {
453  std::string msg((const char *)iana_option->data + 2,
454  iana_option_len - 2);
455  DHCPV6_TRACE(Trace, "DHCP message with error status : " <<
456  status << " error msg : " << msg <<
457  "; received on interface : " <<
458  vm_itf_->name() << "; ignoring");
459  }
460  return false;
461  }
462 
463  default:
464  break;
465  }
466  iana_rem_len -= (4 + iana_option_len);
467  iana_option = (Dhcpv6Options *)((uint8_t *)iana_option + 4 + iana_option_len);
468  }
469 
470  return true;
471 }
472 
474  Ip6Address &gw, Ip6Address &dns) {
475  config_.ip_addr = addr;
476  config_.plen = plen;
477  config_.gw_addr = gw;
478  config_.dns_addr = dns;
479 }
480 
483  FindDomainName(ip);
484  if (vm_itf_->IsActive()) {
485  if (vm_itf_->fabric_port()) {
486  // TODO
488  DHCPV6_TRACE(Error, "DHCP fabric port request failed for : "
489  << ip.to_string());
490  return false;
491  }
492 
493  const std::vector<VnIpam> &ipam = vm_itf_->vn()->GetVnIpam();
494  for (uint32_t i = 0; i < ipam.size(); ++i) {
495  if (!ipam[i].IsV6()) {
496  continue;
497  }
498  if (IsIp6SubnetMember(ip, ipam[i].ip_prefix.to_v6(),
499  ipam[i].plen)) {
500  Ip6Address default_gw;
501  if (ipam[i].default_gw.is_v6()) {
502  default_gw = ipam[i].default_gw.to_v6();
503  }
504  Ip6Address service_address;
505  if (ipam[i].dns_server.is_unspecified()) {
506  service_address = default_gw;
507  } else {
508  if (ipam[i].dns_server.is_v6()) {
509  service_address = ipam[i].dns_server.to_v6();
510  }
511  }
512  FillDhcpInfo(ip, ipam[i].plen, default_gw, service_address);
513  return true;
514  }
515  }
516  }
517 
518  // We dont have the config yet; give a short lease
521  // Give address received from Nova
522  Ip6Address empty;
523  FillDhcpInfo(ip, 128, empty, empty);
524  DHCPV6_TRACE(Trace, "DHCP giving short lease given for : " << ip.to_string()
525  << "; IPv6 not active in Agent");
526  return true;
527 }
528 
529 // Add an IP address to the option
530 uint16_t Dhcpv6Handler::AddIP(uint16_t opt_len, const std::string &input) {
531  boost::system::error_code ec;
532  Ip6Address ip = Ip6Address::from_string(input, ec);
533  if (!ec.value()) {
534  option_->AppendData(16, ip.to_bytes().data(), &opt_len);
535  } else {
536  DHCPV6_TRACE(Error, "Invalid DHCP option " << option_->GetCode() <<
537  " for VM " << config_.ip_addr.to_string() <<
538  "; has to be IP address");
539  }
540  return opt_len;
541 }
542 
543 // Add domain name from IPAM to the option
544 uint16_t Dhcpv6Handler::AddDomainNameOption(uint16_t opt_len) {
545  if (ipam_type_.ipam_dns_method == "virtual-dns-server") {
546  if (is_dns_enabled() && config_.domain_name_.size()) {
547  // encode the domain name in the dns encoding format
548  boost::scoped_array<uint8_t> domain_name(new uint8_t[config_.domain_name_.size() * 2 + 2]);
549  uint16_t len = 0;
550  BindUtil::AddName(domain_name.get(), config_.domain_name_, 0, 0, len);
551  option_->WriteData(DHCPV6_OPTION_DOMAIN_LIST, len,
552  domain_name.get(), &opt_len);
553  }
554  }
555  return opt_len;
556 }
557 
559  Dhcpv6Proto *dhcp_proto = agent()->dhcpv6_proto();
560 
562  memcpy(dhcp_->xid, xid_, 3);
563 
564  uint16_t opt_len = 0;
565 
566  // server duid
567  option_->SetNextOptionPtr(opt_len);
569  (void *)dhcp_proto->server_duid(), &opt_len);
570 
571  // client duid
572  if (client_duid_len_) {
573  option_->SetNextOptionPtr(opt_len);
575  (void *)client_duid_.get(), &opt_len);
576  }
577 
578  // IA
579  option_->SetNextOptionPtr(opt_len);
580  WriteIaOption(opt_len);
581 
582  // Add dhcp options coming from Config
583  opt_len = AddConfigDhcpOptions(opt_len, true);
584 
585  // GW doesnt come in DHCPV6, it should come via router advertisement
586 
588  uint16_t old_opt_len = opt_len;
589  option_->SetNextOptionPtr(opt_len);
590  option_->WriteData(DHCPV6_OPTION_DNS_SERVERS, 0, NULL, &opt_len);
591  opt_len = AddDnsServers(opt_len);
592  // if there was no DNS server, revert the option
593  if (opt_len == old_opt_len + option_->GetFixedLen())
594  opt_len = old_opt_len;
595  }
596 
598  option_->SetNextOptionPtr(opt_len);
599  opt_len = AddDomainNameOption(opt_len);
600  }
601 
602  return (DHCPV6_FIXED_LEN + opt_len);
603 }
604 
605 void Dhcpv6Handler::IncrementByteInAddress(Ip6Address::bytes_type &bytes, uint8_t index) {
606  if (index > 15) {
607  return;
608  }
609  bytes[index]++;
610  if (bytes[index] != 0) {
611  return;
612  } else {
613  IncrementByteInAddress(bytes, index - 1);
614  }
615 }
616 
618  Ip6Address::bytes_type bytes;
619  for (int i = 0; i < 16; i++) {
620  bytes[i] = addr[i];
621  }
622  IncrementByteInAddress(bytes, 15);
623  return Ip6Address(bytes);
624 }
625 
626 void Dhcpv6Handler::WriteIaOption(uint16_t &optlen) {
627  if (ia_na_.get() == NULL) {
628  return;
629  }
630 
631  uint32_t alloc_unit = 1;
632  // for ia_ta, send only one address
633  if (vm_itf_ && vm_itf_->vn() && is_ia_na_) {
634  alloc_unit = vm_itf_->vn()->GetAllocUnitFromIpam(config_.ip_addr);
635  }
636  if (alloc_unit > 128) {
637  DHCPV6_TRACE(Error, "Alloc-unit(" << alloc_unit << ") in Ipam is"
638  " higher than supported value(128), using max supported"
639  " value");
640  alloc_unit = 128;
641  }
642  Dhcpv6IaAddr ia_addr(config_.ip_addr.to_v6().to_bytes().data(),
645 
646  uint16_t ia_option = (is_ia_na_)? DHCPV6_OPTION_IA_NA : DHCPV6_OPTION_IA_TA;
647  uint16_t ia_option_length = (is_ia_na_)? sizeof(Dhcpv6Ia) : 16;
648  option_->WriteData(ia_option, ia_option_length, (void *)&ia_na_->ia, &optlen);
649 
650  for (uint32_t i = 0; i < alloc_unit; i++) {
651  Dhcpv6Options *ia_addr_opt = GetNextOptionPtr(optlen);
652  if (msg_type_ != DHCPV6_CONFIRM ||
653  (msg_type_ == DHCPV6_CONFIRM && ia_na_->DelIaAddr(ia_addr))) {
654  ia_addr_opt->WriteData(DHCPV6_OPTION_IAADDR, sizeof(Dhcpv6IaAddr),
655  (void *)&ia_addr, &optlen);
656  option_->AddLen(sizeof(Dhcpv6IaAddr) + 4);
657  }
658  Ip6Address next_ip = GetNextV6Address(ia_addr.address);
659  memcpy(ia_addr.address, next_ip.to_bytes().data(), 16);
660  }
661 
662  // in case of confirm, if there are any remaining addresses in ia_na_
663  // add them with status as "NotOnLink".
664  if (msg_type_ == DHCPV6_CONFIRM && !ia_na_->ia_addr.empty()) {
665  for (std::vector<Dhcpv6IaAddr>::iterator it = ia_na_->ia_addr.begin();
666  it != ia_na_->ia_addr.end(); ++it) {
667  memcpy(ia_addr.address, it->address, 16);
668  Dhcpv6Options *ia_addr_opt = GetNextOptionPtr(optlen);
669  ia_addr_opt->WriteData(DHCPV6_OPTION_IAADDR, sizeof(Dhcpv6IaAddr),
670  (void *)&ia_addr, &optlen);
671  option_->AddLen(sizeof(Dhcpv6IaAddr) + 4);
672  ia_addr_opt = GetNextOptionPtr(optlen);
673  std::string message = "Some of the addresses are not on link";
674  uint16_t status_code = htons(DHCPV6_NOT_ON_LINK);
675  ia_addr_opt->WriteData(DHCPV6_OPTION_STATUS_CODE, 2,
676  (void *)&status_code, &optlen);
677  ia_addr_opt->AppendData(message.length(), message.c_str(), &optlen);
678  option_->AddLen(message.length() + 6);
679  }
680  }
681 }
682 
684  Ip6Address src_ip, Ip6Address dest_ip) {
685  pkt_info_->eth = (struct ether_header *)(pkt_info_->pkt);
686  uint16_t eth_len = 0;
687  eth_len = EthHdr((char *)pkt_info_->eth,
688  pkt_info_->packet_buffer()->data_len(),
690  agent()->vhost_interface()->mac(), dest_mac,
691  ETHERTYPE_IPV6);
692  pkt_info_->ip6 = (struct ip6_hdr *)((char *)pkt_info_->eth + eth_len);
693  pkt_info_->transp.udp = (udphdr *)(pkt_info_->ip6 + 1);
694  dhcp_ = (Dhcpv6Hdr *)(pkt_info_->transp.udp + 1);
695  option_->SetDhcpOptionPtr((uint8_t *)dhcp_ + DHCPV6_FIXED_LEN);
696 
697  uint16_t len = FillDhcpv6Hdr();
698  len += sizeof(udphdr);
699  UdpHdr(len, src_ip.to_bytes().data(), DHCPV6_SERVER_PORT,
700  dest_ip.to_bytes().data(), DHCPV6_CLIENT_PORT, IPPROTO_UDP);
701  Ip6Hdr(pkt_info_->ip6, len, IPPROTO_UDP, 64, src_ip.to_bytes().data(),
702  dest_ip.to_bytes().data());
703  len += sizeof(ip6_hdr);
704 
705  pkt_info_->set_len(len + eth_len);
706  return pkt_info_->packet_buffer()->data_len();
707 }
708 
710  UpdateStats();
711  // In TSN, the source address for DHCP response should be the address
712  // in the subnet reserved for service node. Otherwise, it will be the
713  // GW address. dns_addr field has this address, use it as the source IP.
714  FillDhcpResponse(MacAddress(pkt_info_->eth->ether_shost),
715  config_.dns_addr.to_v6(),
716  pkt_info_->ip_saddr.to_v6());
717  uint32_t interface =
718  (pkt_info_->agent_hdr.cmd == AgentHdr::TRAP_TOR_CONTROL_PKT) ?
719  pkt_info_->agent_hdr.cmd_param : GetInterfaceIndex();
720  uint16_t command =
721  (pkt_info_->agent_hdr.cmd == AgentHdr::TRAP_TOR_CONTROL_PKT) ?
723  Send(interface, pkt_info_->vrf, command, PktHandler::DHCPV6);
724 }
725 
727  Dhcpv6Proto *dhcp_proto = agent()->dhcpv6_proto();
728  (out_msg_type_ == DHCPV6_ADVERTISE) ? dhcp_proto->IncrStatsAdvertise() :
729  dhcp_proto->IncrStatsReply();
730 }
731 
733 Dhcpv6Handler::OptionCategory(uint32_t option) const {
734  Dhcpv6CategoryIter iter = g_dhcpv6_category_map.find(option);
735  if (iter == g_dhcpv6_category_map.end())
736  return None;
737  return iter->second;
738 }
739 
740 uint32_t Dhcpv6Handler::OptionCode(const std::string &option) const {
741  Dhcpv6NameCodeIter iter =
742  g_dhcpv6_namecode_map.find(boost::to_lower_copy(option));
743  return (iter == g_dhcpv6_namecode_map.end()) ? 0 : iter->second;
744 }
745 
746 void Dhcpv6Handler::DhcpTrace(const std::string &msg) const {
747  DHCPV6_TRACE(Error, "VM " << config_.ip_addr.to_string() << " : " << msg);
748 }
#define DHCPV6_OPTION_S46_CONT_MAPE
#define DHCPV6_NOT_ON_LINK
#define DHCPV6_OPTION_SIP_SERVER_D
std::map< std::string, uint32_t >::const_iterator Dhcpv6NameCodeIter
#define DHCPV6_OPTION_MIP6_IDINF
#define DHCPV6_OPTION_USER_CLASS
#define DHCPV6_OPTION_PANA_AGENT
void IncrStatsAdvertise()
Definition: dhcpv6_proto.h:64
Type type() const
Definition: interface.h:112
bool dhcp_enable_v6_config() const
#define DHCPV6_OPTION_BCMCS_SERVER_A
void FindDomainName(const IpAddress &vm_addr)
#define DHCPV6_OPTION_S46_CONT_MAPT
uint16_t AddConfigDhcpOptions(uint16_t opt_len, bool is_v6)
#define DHCPV6_OPTION_CLIENT_ARCH_TYPE
#define DHCPV6_OPTION_MIP6_UDINF
boost::scoped_ptr< DhcpOptionHandler > option_
void IncrStatsReply()
Definition: dhcpv6_proto.h:69
uint8_t xid[3]
void IncrStatsConfirm()
Definition: dhcpv6_proto.h:66
void IncrStatsDecline()
Definition: dhcpv6_proto.h:71
#define DHCPV6_OPTION_IPv6_Address_MoS
#define DHCPV6_OPTION_SNTP_SERVERS
void IncrementByteInAddress(Ip6Address::bytes_type &bytes, uint8_t index)
#define DHCPV6_OPTION_RADIUS
uint32_t OptionCode(const std::string &option) const
bool ReadIA(uint8_t *ptr, uint16_t len, uint16_t code)
static std::string & Dhcpv6MsgType(uint32_t msg_type)
#define DHCPV6_OPTION_NEW_POSIX_TIMEZONE
void WriteData(uint16_t c, uint16_t l, const void *d, uint16_t *optlen)
#define DHCPV6_OPTION_KRB_DEFAULT_REALM_NAME
#define DHCPV6_OPTION_AUTH
#define DHCPV6_SERVER_PORT
Definition: pkt_handler.h:31
#define DHCPV6_SUCCESS
#define DHCPV6_OPTION_IA_NA
#define DHCPV6_OPTION_BCMCS_SERVER_D
#define DHCPV6_OPTION_RSOO
const Interface * vhost_interface() const
Definition: agent.h:935
#define DHCPV6_OPT_BOOTFILE_URL
Ip6Address GetNextV6Address(uint8_t addr[])
#define DHCPV6_CONFIRM
#define DHCPV6_OPTION_V6_PCP_SERVER
#define DHCPV6_OPTION_NIS_DOMAIN_NAME
#define DHCPV6_OPT_BOOTFILE_PARAM
#define DHCPV6_OPTION_IA_PD
#define DHCPV6_OPTION_STATUS_CODE
#define DHCPV6_OPTION_INTERFACE_ID
#define DHCPV6_OPTION_NISP_DOMAIN_NAME
ConfigRecord config_
InterfaceTable * interface_table() const
Definition: agent.h:465
uint16_t server_duid_len_
#define DHCPV6_OPTION_V6_ACCESS_DOMAIN
#define DHCPV6_OPTION_RELAY_ID
#define DHCPV6_OPTION_GEOCONF_CIVIC
#define DHCPV6_OPTION_ELAPSED_TIME
boost::scoped_ptr< Dhcpv6IaData > ia_na_
Dhcpv6CategoryMap g_dhcpv6_category_map
#define DHCPV6_OPTION_MIP6_HNIDF
const MacAddress & mac() const
Definition: interface.h:131
#define DHCPV6_OPTION_DNS_SERVERS
#define DHCPV6_OPTION_GEOLOCATION
#define DHCPV6_OPTION_DHCPV4_MSG
uint16_t AddIP(uint16_t opt_len, const std::string &input)
uint8_t out_msg_type_
#define DHCPV6_OPTION_NEW_TZDB_TIMEZONE
#define DHCPV6_OPTION_NISP_SERVERS
#define DHCPV6_OPTION_PREFERENCE
Agent * agent() const
Definition: proto_handler.h:80
#define DHCPV6_OPTION_RELAY_MSG
boost::shared_ptr< PktInfo > pkt_info_
Definition: proto_handler.h:92
#define DHCPV6_OPTION_S46_BR
#define DHCPV6_OPTION_S46_RULE
void IncrStatsRebind()
Definition: dhcpv6_proto.h:68
#define DHCPV6_OPTION_MIP6_HAF
const Duid * server_duid() const
Definition: dhcpv6_proto.h:61
#define DHCPV6_SOLICIT
#define DHCPV6_OPTION_S46_PORTPARAMS
#define DHCPV6_OPTION_INFORMATION_REFRESH_TIME
#define DHCPV6_OPTION_MIP6_HNP
#define DHCPV6_REPLY
#define DHCPV6_SHORTLEASE_TIME
#define DHCPV6_OPTION_SERVERID
Dhcpv6Proto * dhcpv6_proto() const
Definition: agent.h:984
uint16_t AddDnsServers(uint16_t opt_len)
int EthHdr(const MacAddress &src, const MacAddress &dest, const uint16_t proto)
#define DHCPV6_OPTION_KRB_KDC
bool IsActive() const
#define DHCPV6_OPTION_VENDOR_CLASS
#define DHCPV6_OPTION_KRB_REALM_NAME
std::map< std::string, uint32_t > Dhcpv6NameCodeMap
#define DHCPV6_RENEW
Definition: agent.h:358
uint32_t GetInterfaceIndex() const
Definition: proto_handler.h:82
uint16_t FillDhcpResponse(const MacAddress &dest_mac, Ip6Address src_ip, Ip6Address dest_ip)
#define DHCPV6_OPTION_SUBSCRIBER_ID
#define DHCPV6_OPTION_CLIENTID
#define DHCPV6_OPTION_RECONF_MSG
#define DHCPV6_OPTION_LQ_QUERY
uint32_t GetAllocUnitFromIpam(const IpAddress &ip) const
Definition: vn.cc:676
bool fabric_port() const
#define DHCPV6_OPTION_DHCP4_O_DHCP6_SERVER
uint8_t data[0]
#define DHCPV6_OPTION_SIP_UA_CS_LIST
boost::asio::ip::address_v6 Ip6Address
Definition: address.h:15
static uint8_t * AddName(uint8_t *ptr, const std::string &addr, uint16_t plen, uint16_t offset, uint16_t &length)
Definition: bind_util.cc:146
#define DHCPV6_OPTION_RAPID_COMMIT
#define DHCPV6_OPTION_ADDRSEL_TABLE
void Send(uint32_t itf, uint32_t vrf, uint16_t, PktHandler::PktModuleName)
#define DHCPV6_OPTION_ADDRSEL
Definition: trace.h:220
uint8_t type
#define DHCPV6_OPTION_LINK_ADDRESS
void IncrStatsSolicit()
Definition: dhcpv6_proto.h:63
#define DHCPV6_DECLINE
uint16_t client_duid_len_
#define DHCPV6_ADVERTISE
Dhcpv6Hdr * dhcp_
const std::vector< VnIpam > & GetVnIpam() const
Definition: vn.h:171
void IncrStatsError()
Definition: dhcpv6_proto.h:74
const VnEntry * vn() const
std::map< uint32_t, Dhcpv6Handler::DhcpOptionCategory > Dhcpv6CategoryMap
#define DHCPV6_OPTION_S46_V4V6BIND
uint16_t AddDomainNameOption(uint16_t opt_len)
void SendDhcpResponse()
void WriteIaOption(uint16_t &optlen)
#define DHCPV6_OPTION_AFTR_NAME
void Ip6Hdr(ip6_hdr *ip, uint16_t plen, uint8_t next_header, uint8_t hlim, uint8_t *src, uint8_t *dest)
#define DHCPV6_OPTION_RECONF_ACCEPT
#define DHCPV6_OPTION_VSS
#define DHCPV6_OPTION_CLIENT_FQDN
#define DHCPV6_UNKNOWN
#define DHCPV6_OPTION_V6_LOST
#define DHCPV6_OPTION_VENDOR_OPTS
#define DHCPV6_OPTION_LQ_CLIENT_LINK
void IncrStatsRenew()
Definition: dhcpv6_proto.h:67
#define DHCPV6_TRACE(obj, arg)
Definition: dhcpv6_proto.h:11
DhcpOptionCategory OptionCategory(uint32_t option) const
#define DHCPV6_OPTION_SIP_SERVER_A
#define DHCPV6_OPTION_CLIENT_LINKLAYER_ADDR
void AppendData(uint16_t l, const void *d, uint16_t *optlen)
#define DHCPV6_OPTION_NII
void UdpHdr(uint16_t len, in_addr_t src, uint16_t src_port, in_addr_t dest, uint16_t dest_port)
#define DHCPV6_OPTION_DOMAIN_LIST
const Ip6Address & primary_ip6_addr() const
#define DHCPV6_OPTION_RDNSS_SELECTION
#define DHCPV6_OPTION_IPv6_ADDRESS_ANDSF
#define DHCPV6_OPTION_CLT_TIME
#define DHCPV6_OPTION_PD_EXCLUDE
#define DHCPV6_OPTION_NIS_SERVERS
#define DHCPV6_OPTION_IPv6_FQDN_MoS
#define DHCPV6_OPTION_ERP_LOCAL_DOMAIN_NAME
const Interface * FindInterface(size_t index) const
Definition: interface.cc:323
void IncrStatsRequest()
Definition: dhcpv6_proto.h:65
void IncrStatsInformationRequest()
Definition: dhcpv6_proto.h:73
std::map< uint32_t, Dhcpv6Handler::DhcpOptionCategory >::const_iterator Dhcpv6CategoryIter
#define DHCPV6_OPTION_ORO
#define DHCPV6_OPTION_KRB_PRINCIPAL_NAME
const std::string & name() const
Definition: interface.h:114
#define DHCPV6_OPTION_CLIENT_DATA
#define DHCPV6_OPTION_S46_DMR
void IncrStatsReconfigure()
Definition: dhcpv6_proto.h:72
#define DHCPV6_OPTION_IAPREFIX
#define DHCPV6_OPTION_INF_MAX_RT
#define DHCPV6_OPTION_S46_CONT_LW
#define DHCPV6_RECONFIGURE
void IncrStatsRelease()
Definition: dhcpv6_proto.h:70
#define DHCPV6_OPTION_UNICAST
bool is_dns_enabled() const
Dhcpv6Handler(Agent *agent, boost::shared_ptr< PktInfo > info, boost::asio::io_context &io)
#define DHCPV6_REQUEST
#define DHCPV6_FIXED_LEN
VmInterface * vm_itf_
#define DHCPV6_OPTION_MIP6_HAA
autogen::IpamType ipam_type_
#define DHCPV6_OPTION_ERO
#define DHCPV6_OPTION_IA_TA
#define DHCPV6_RELEASE
bool IsIp6SubnetMember(const Ip6Address &ip, const Ip6Address &subnet, uint8_t plen)
Definition: address_util.cc:29
Dhcpv6Options * GetNextOptionPtr(uint16_t optlen)
#define DHCPV6_OPTION_IAADDR
bool is_flag_set(uint8_t flag) const
virtual ~Dhcpv6Handler()
#define DHCPV6_OPTION_NTP_SERVER
void DhcpTrace(const std::string &msg) const
Dhcpv6NameCodeMap g_dhcpv6_namecode_map
#define DHCPV6_REBIND
#define DHCPV6_INFORMATION_REQUEST
#define DHCPV6_OPTION_LQ_RELAY_DATA
void FillDhcpInfo(Ip6Address &addr, int plen, Ip6Address &gw, Ip6Address &dns)
#define DHCPV6_OPTION_MIP6_VDINF
uint16_t FillDhcpv6Hdr()
#define DHCPV6_OPTION_SOL_MAX_RT
#define DHCPV6_OPTION_CAPWAP_AC_V6
void ReadOptions(int16_t opt_rem_len)
uint8_t xid_[3]
#define DHCPV6_CLIENT_PORT
Definition: pkt_handler.h:32
#define DHCPV6_OPTION_REMOTE_ID