OpenSDN source code
icmpv6_handler.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3  */
4 
5 #include "base/os.h"
6 #include <netinet/icmp6.h>
7 
8 #include <vr_defs.h>
9 #include <cmn/agent_cmn.h>
10 #include <pkt/pkt_init.h>
11 #include <oper/interface_common.h>
12 #include "services/services_types.h"
13 #include <services/services_init.h>
14 #include <services/icmpv6_proto.h>
15 #include <oper/route_common.h>
16 #include <oper/operdb_init.h>
17 #include <oper/path_preference.h>
18 #include <oper/vn.h>
19 #include <boost/scoped_array.hpp>
20 
21 const Ip6Address::bytes_type Icmpv6Handler::kPrefix =
22  { {0xFF, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0xFF, 0, 0, 0} };
23 const Ip6Address::bytes_type Icmpv6Handler::kSuffix =
24  { {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0xFF} };
28 
29 Icmpv6Handler::Icmpv6Handler(Agent *agent, boost::shared_ptr<PktInfo> info,
30  boost::asio::io_context &io)
31  : ProtoHandler(agent, info, io), icmp_(pkt_info_->transp.icmp6) {
32  // payload length - length of ipv6 extension headers
33  if (icmp_)
34  icmp_len_ = ntohs(pkt_info_->ip6->ip6_plen) + sizeof(ip6_hdr) -
35  ((uint8_t *)icmp_ - (uint8_t *)pkt_info_->ip6);
36  else
37  icmp_len_ = 0;
38  refcount_ = 0;
39 }
40 
42 }
43 
45  assert(agent());
46  assert(agent()->icmpv6_proto());
47 
48  switch(pkt_info_->type) {
49  case PktType::MESSAGE:
50  return HandleMessage();
51 
52  default:
53  return HandlePacket();
54  }
55 }
56 
58  Icmpv6Proto *icmpv6_proto = agent()->icmpv6_proto();
59  Interface *itf =
61  if (itf == NULL) {
62  icmpv6_proto->IncrementStatsDrop();
63  ICMPV6_TRACE(Trace, "Received ICMP from invalid interface");
64  return true;
65  }
66  if (itf->type() != Interface::VM_INTERFACE) {
67  icmpv6_proto->IncrementStatsDrop();
68  ICMPV6_TRACE(Trace, "Received ICMP from non-vm interface");
69  return true;
70  }
71  VmInterface *vm_itf = static_cast<VmInterface *>(itf);
72  if (!vm_itf->layer3_forwarding() || !vm_itf->ipv6_active()) {
73  icmpv6_proto->IncrementStatsDrop();
74  ICMPV6_TRACE(Trace, "Received ICMP with l3 disabled / ipv6 inactive");
75  return true;
76  }
77  nd_neighbor_advert *icmp = (nd_neighbor_advert *)icmp_;
78  nd_neighbor_solicit *ns = (nd_neighbor_solicit *)icmp_;
79  switch (icmp_->icmp6_type) {
80  case ND_ROUTER_SOLICIT:
81  icmpv6_proto->IncrementStatsRouterSolicit(vm_itf);
82  if (CheckPacket()) {
83  Ip6Address prefix;
84  uint8_t plen;
85  if (vm_itf->vn() &&
86  vm_itf->vn()->GetPrefix(vm_itf->primary_ip6_addr(),
87  &prefix, &plen)) {
88  boost::system::error_code ec;
89  Ip6Address src_addr = Ip6Address::from_string(PKT0_LINKLOCAL_ADDRESS, ec);
90  uint32_t interface =
91  (pkt_info_->agent_hdr.cmd == AgentHdr::TRAP_TOR_CONTROL_PKT) ?
92  pkt_info_->agent_hdr.cmd_param : GetInterfaceIndex();
93  VmInterface *vmi = NULL;
94  Interface *intf =
95  agent()->interface_table()->FindInterface(interface);
96  if (intf->type() == Interface::VM_INTERFACE) {
97  vmi = static_cast<VmInterface *>(intf);
98  }
99  SendRAResponse(interface,
100  pkt_info_->vrf,
101  src_addr.to_bytes().data(),
102  pkt_info_->ip_saddr.to_v6().to_bytes().data(),
103  MacAddress(pkt_info_->eth->ether_shost), prefix, plen);
104  icmpv6_proto->IncrementStatsRouterAdvert(vmi);
105  return true;
106  }
107  ICMPV6_TRACE(Trace, "Ignoring ND Router Solicit : VN / prefix not present");
108  } else {
109  ICMPV6_TRACE(Trace, "Ignoring Echo request with wrong cksum");
110  }
111  break;
112 
113  case ICMP6_ECHO_REQUEST:
114  icmpv6_proto->IncrementStatsPingRequest(vm_itf);
115  if (CheckPacket()) {
117  icmpv6_proto->IncrementStatsPingResponse(vm_itf);
118  return true;
119  }
120  ICMPV6_TRACE(Trace, "Ignoring Echo request with wrong cksum");
121  break;
122 
123  case ND_NEIGHBOR_ADVERT:
124  if (icmp->nd_na_flags_reserved & ND_NA_FLAG_SOLICITED) {
125  icmpv6_proto->IncrementStatsNeighborAdvertSolicited(vm_itf);
126  } else {
127  icmpv6_proto->IncrementStatsNeighborAdvertUnSolicited(vm_itf);
128  }
129  if (CheckPacket()) {
130  Ip6Address::bytes_type bytes;
131  for (int i = 0; i < 16; i++) {
132  bytes[i] = icmp->nd_na_target.s6_addr[i];
133  }
134  Ip6Address addr(bytes);
135  uint16_t offset = sizeof(nd_neighbor_advert);
136  nd_opt_hdr *opt = (nd_opt_hdr *) (((uint8_t *)icmp) + offset);
137  if (opt->nd_opt_type != ND_OPT_TARGET_LINKADDR) {
138  ICMPV6_TRACE(Trace, "Ignoring Neighbor Advert with no"
139  "Target Link-layer address option");
140  icmpv6_proto->IncrementStatsDrop();
141  return true;
142  }
143 
144  uint8_t *buf = (((uint8_t *)icmp) + offset + 2);
145  MacAddress mac(buf);
146 
147  //Enqueue a request to trigger state machine
149  EnqueueTrafficSeen(addr, 128, itf->id(),
150  itf->vrf()->vrf_id(), mac);
151 
152  icmpv6_proto->HandlePathPreferenceNA(itf->vrf(), itf->id(),
153  IpAddress(addr));
154  NdpKey key(addr, itf->vrf());
155  NdpEntry *entry = icmpv6_proto->FindNdpEntry(key);
156  if (entry) {
157  entry->EnqueueNaIn(*icmp, mac);
158  }
159  return true;
160  }
161  ICMPV6_TRACE(Trace, "Ignoring Neighbor Advert with wrong cksum");
162  break;
163 
164  case ND_NEIGHBOR_SOLICIT:
165  icmpv6_proto->IncrementStatsNeighborSolicited(vm_itf);
166  if (CheckPacket()) {
167  Ip6Address::bytes_type bytes;
168  for (int i = 0; i < 16; i++) {
169  bytes[i] = pkt_info_->ip6->ip6_src.s6_addr[i];
170  }
171  Ip6Address addr(bytes);
172  uint16_t offset = sizeof(nd_neighbor_solicit);
173  nd_opt_hdr *opt = (nd_opt_hdr *) (((uint8_t *)ns) + offset);
174  if (addr.is_unspecified()) {
175  ICMPV6_TRACE(Trace, "Ignoring Neighbor Solicit with "
176  "unspecified address");
177  icmpv6_proto->IncrementStatsDrop();
178  return true;
179  }
180  uint8_t *buf = NULL;
181  if (opt->nd_opt_type == ND_OPT_TARGET_LINKADDR) {
182  offset += 2;
183  buf = (((uint8_t *)icmp) + offset);
184  }
185 
186  //Enqueue a request to trigger state machine
187  NdpKey key(addr, itf->vrf());
188  NdpEntry *entry = icmpv6_proto->FindNdpEntry(key);
189  bool ret = true;
190  if (!entry) {
191  entry = new NdpEntry(io_, this, key, itf->vrf(), itf);
192  if (!icmpv6_proto->AddNdpEntry(entry)) {
193  delete entry;
194  return true;
195  }
196  ret = false;
197  }
198  if (entry) {
199  if (buf) {
200  entry->HandleNsRequest(*ns, MacAddress(buf));
201  } else {
202  entry->HandleNsRequest(*ns, MacAddress());
203  }
204  }
205  return ret;
206  }
207  ICMPV6_TRACE(Trace, "Ignoring Neighbor Solicit with wrong cksum");
208  break;
209  default:
210  break;
211  }
212  icmpv6_proto->IncrementStatsDrop();
213  return true;
214 }
215 
217  bool ret = true;
218  Icmpv6Proto::Icmpv6Ipc *ipc = static_cast<Icmpv6Proto::Icmpv6Ipc *>(
219  pkt_info_->ipc);
220  Icmpv6Proto *icmp_proto = agent()->icmpv6_proto();
221  switch(pkt_info_->ipc->cmd) {
223  NdpEntry *entry = icmp_proto->FindNdpEntry(ipc->key);
224  if (!entry) {
225  entry = new NdpEntry(io_, this, ipc->key, ipc->key.vrf,
226  ipc->interface_.get());
227  if (icmp_proto->AddNdpEntry(entry) == false) {
228  delete entry;
229  break;
230  }
231  ret = false;
232  }
233  const Interface* intf = ipc->interface_.get();
234  const VmInterface *vmi = dynamic_cast<const VmInterface *>(intf);
235  uint32_t vrf_id = intf->vrf_id();;
236  IpAddress ip = agent()->router_id6();
237  if (vrf_id != VrfEntry::kInvalidIndex) {
238  if (ip.is_v6()) {
239  SendNeighborSolicit(ip.to_v6(), ipc->key.ip, vmi, vrf_id);
240  VmInterface *vmif = const_cast<VmInterface *>(vmi);
241  icmp_proto->IncrementStatsNeighborSolicited(vmif);
242  }
243  }
244  break;
245  }
246 
248  EntryDelete(ipc->key);
249  break;
250  }
251 
253  bool key_valid = false;
255  icmp_proto->UnsolNaEntryIterator(ipc->key, &key_valid);
256  if (key_valid && !ipc->interface_->IsDeleted()) {
257  NdpEntry *entry = NULL;
258  Icmpv6Proto::NdpEntrySet::iterator sit = it->second.begin();
259  for (; sit != it->second.end(); sit++) {
260  entry = *sit;
261  if (entry->get_interface() == ipc->interface_.get())
262  break;
263  }
264  if (sit == it->second.end()) {
265  entry = new NdpEntry(io_, this, ipc->key, ipc->key.vrf,
266  ipc->interface_.get());
267  it->second.insert(entry);
268  ret = false;
269  }
270  if (entry) {
271  entry->SendNeighborAdvert(false);
272  const VmInterface *vmi = static_cast<const VmInterface *>(
273  ipc->interface_.get());
274  VmInterface *vmif = const_cast<VmInterface *>(vmi);
275  icmp_proto->IncrementStatsNeighborAdvertUnSolicited(vmif);
276  }
277  }
278  break;
279  }
280 
281  default:
282  ICMPV6_TRACE(Trace, "Received Invalid internal NDP message : " +
283  integerToString(pkt_info_->ipc->cmd));
284  break;
285  }
286 
287  delete ipc;
288  return ret;
289 }
290 
292  Icmpv6Proto *icmp_proto = agent()->icmpv6_proto();
293  NdpEntry *entry = icmp_proto->FindNdpEntry(key);
294  if (entry) {
295  // this request comes when NDP NH is deleted; nothing more to do
296  icmp_proto->DeleteNdpEntry(entry);
297  }
298 }
299 
301  const Icmpv6Proto::VmInterfaceMap &interfaces = proto->vm_interfaces();
302  boost::system::error_code ec;
303  Ip6Address src_addr = Ip6Address::from_string(PKT0_LINKLOCAL_ADDRESS, ec);
304  Ip6Address dest_addr = Ip6Address::from_string(IPV6_ALL_NODES_ADDRESS, ec);
305  // Ethernet mcast address corresponding to IPv6 mcast address ff02::1
306  MacAddress dest_mac(0x33, 0x33, 0x00, 0x00, 0x00, 0x01);
307  for (Icmpv6Proto::VmInterfaceMap::const_iterator it = interfaces.begin();
308  it != interfaces.end(); ++it) {
309  VmInterface *vmi = it->first;
310  if (vmi->vmi_type() == VmInterface::VHOST ||
311  (vmi->vmi_type() == VmInterface::BAREMETAL &&
312  vmi->vn() != NULL && vmi->vn()->lr_vrf() != NULL)) {
313  continue;
314  }
315 
316  if (vmi->IsIpv6Active() && !vmi->HasServiceVlan()) {
317  pkt_info_->AllocPacketBuffer(agent(), PktHandler::ICMPV6, ICMP_PKT_SIZE, 0);
318  pkt_info_->eth = (struct ether_header *)(pkt_info_->pkt);
319  pkt_info_->ip6 = (ip6_hdr *)(pkt_info_->pkt + sizeof(struct ether_header));
320  /* For baremetal/local vm set the appropriate information that will be used
321  * to decide to route/switch the RA packet to the TOR switch
322  */
323  pkt_info_->agent_hdr.cmd =
324  (vmi->vmi_type() == VmInterface::BAREMETAL) ?
326  uint32_t vlan_offset = 0;
327  if (vmi->tx_vlan_id() != VmInterface::kInvalidVlanId &&
328  !(agent()->tsn_enabled())) {
329  vlan_offset += 4;
330  }
331  icmp_ = pkt_info_->transp.icmp6 =
332  (icmp6_hdr *)(pkt_info_->pkt + sizeof(struct ether_header) +
333  vlan_offset + sizeof(ip6_hdr));
334  Ip6Address prefix;
335  uint8_t plen;
336  if (vmi->vn()->GetPrefix(vmi->primary_ip6_addr(), &prefix, &plen)) {
337  SendRAResponse(vmi->id(), vmi->vrf()->vrf_id(),
338  src_addr.to_bytes().data(),
339  dest_addr.to_bytes().data(),
340  dest_mac, prefix, plen);
341  proto->IncrementStatsRouterAdvert(vmi);
342  }
343  }
344  }
345 
346  return true;
347 }
348 
350  if (pkt_info_->len < (sizeof(struct ether_header) + sizeof(ip6_hdr) +
351  ntohs(pkt_info_->ip6->ip6_plen)))
352  return false;
353 
354  uint16_t checksum = icmp_->icmp6_cksum;
355  icmp_->icmp6_cksum = 0;
356  if (checksum == Icmpv6Csum(pkt_info_->ip6->ip6_src.s6_addr,
357  pkt_info_->ip6->ip6_dst.s6_addr,
358  icmp_, icmp_len_))
359  return true;
360 
361  return false;
362 }
363 
364 uint16_t Icmpv6Handler::FillRouterAdvertisement(uint8_t *buf, uint32_t ifindex,
365  uint8_t *src, uint8_t *dest,
366  const Ip6Address &prefix,
367  uint8_t plen) {
368  nd_router_advert *icmp = (nd_router_advert *)buf;
369  icmp->nd_ra_type = ND_ROUTER_ADVERT;
370  icmp->nd_ra_code = 0;
371  icmp->nd_ra_cksum = 0;
372  icmp->nd_ra_curhoplimit = 64;
373  icmp->nd_ra_flags_reserved = ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER; //DHCPv6
374  icmp->nd_ra_reachable = 0;
375  icmp->nd_ra_retransmit = 0;
376 
377  bool def_gw = IsDefaultGatewayConfigured(ifindex, prefix);
378  if (def_gw) {
379  icmp->nd_ra_router_lifetime = htons(9000);
380  } else {
381  icmp->nd_ra_router_lifetime = 0;
382  }
383 
384  // add source linklayer address information
385  uint16_t offset = sizeof(nd_router_advert);
386  nd_opt_hdr *src_linklayer_addr = (nd_opt_hdr *)(buf + offset);
387  src_linklayer_addr->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
388  src_linklayer_addr->nd_opt_len = 1;
389  //XXX instead of ETHER_ADDR_LEN, actual buffer size should be given
390  //to preven buffer overrun.
391  agent()->vrrp_mac().ToArray(buf + offset + 2, ETHER_ADDR_LEN);
392 
393  // add prefix information
394  offset += sizeof(nd_opt_hdr) + ETHER_ADDR_LEN;
395  nd_opt_prefix_info *prefix_info = (nd_opt_prefix_info *)(buf + offset);
396  prefix_info->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
397  prefix_info->nd_opt_pi_len = 4;
398  prefix_info->nd_opt_pi_prefix_len = plen;
399  // not setting ND_OPT_PI_FLAG_AUTO or ND_OPT_PI_FLAG_RADDR
400  prefix_info->nd_opt_pi_flags_reserved = ND_OPT_PI_FLAG_ONLINK;
401  prefix_info->nd_opt_pi_valid_time = htonl(0xFFFFFFFF);
402  prefix_info->nd_opt_pi_preferred_time = htonl(0xFFFFFFFF);
403  prefix_info->nd_opt_pi_reserved2 = 0;
404  memcpy(prefix_info->nd_opt_pi_prefix.s6_addr, prefix.to_bytes().data(), 16);
405 
406  offset += sizeof(nd_opt_prefix_info);
407  icmp->nd_ra_cksum = Icmpv6Csum(src, dest, (icmp6_hdr *)icmp, offset);
408 
409  return offset;
410 }
411 
412 void Icmpv6Handler::SendRAResponse(uint32_t ifindex, uint32_t vrfindex,
413  uint8_t *src_ip, uint8_t *dest_ip,
414  const MacAddress &dest_mac,
415  const Ip6Address &prefix, uint8_t plen) {
416  // fill in the response
417  uint16_t len = FillRouterAdvertisement((uint8_t *)icmp_, ifindex, src_ip,
418  dest_ip, prefix, plen);
419  SendIcmpv6Response(ifindex, vrfindex, src_ip, dest_ip, dest_mac, len);
420 }
421 
423  icmp_->icmp6_type = ICMP6_ECHO_REPLY;
424  icmp_->icmp6_cksum = 0;
425  icmp_->icmp6_cksum =
426  Icmpv6Csum(pkt_info_->ip_daddr.to_v6().to_bytes().data(),
427  pkt_info_->ip_saddr.to_v6().to_bytes().data(),
428  icmp_, ntohs(pkt_info_->ip6->ip6_plen));
429  uint32_t interface =
430  (pkt_info_->agent_hdr.cmd == AgentHdr::TRAP_TOR_CONTROL_PKT) ?
431  pkt_info_->agent_hdr.cmd_param : GetInterfaceIndex();
432  SendIcmpv6Response(interface, pkt_info_->vrf,
433  pkt_info_->ip_daddr.to_v6().to_bytes().data(),
434  pkt_info_->ip_saddr.to_v6().to_bytes().data(),
435  MacAddress(pkt_info_->eth->ether_shost),
436  ntohs(pkt_info_->ip6->ip6_plen));
437 }
438 
439 void Icmpv6Handler::SendIcmpv6Response(uint32_t ifindex, uint32_t vrfindex,
440  uint8_t *src_ip, uint8_t *dest_ip,
441  const MacAddress &dest_mac,
442  uint16_t len) {
443 
444  char *buff = (char *)pkt_info_->pkt;
445  uint16_t buff_len = pkt_info_->packet_buffer()->data_len();
446  boost::scoped_array<char> icmpv6_payload(new char[icmp_len_]);
447  memcpy(icmpv6_payload.get(),icmp_,icmp_len_);
448  uint16_t eth_len = EthHdr(buff, buff_len, ifindex, agent()->vrrp_mac(),
449  dest_mac, ETHERTYPE_IPV6);
450 
451  pkt_info_->ip6 = (struct ip6_hdr *)(buff + eth_len);
452  Ip6Hdr(pkt_info_->ip6, len, IPV6_ICMP_NEXT_HEADER, 255, src_ip, dest_ip);
453  memcpy(buff + sizeof(ip6_hdr) + eth_len, icmpv6_payload.get(), icmp_len_);
454  pkt_info_->set_len(len + sizeof(ip6_hdr) + eth_len);
455  uint16_t command =
456  (pkt_info_->agent_hdr.cmd == AgentHdr::TRAP_TOR_CONTROL_PKT) ?
458  Send(ifindex, vrfindex, command, PktHandler::ICMPV6);
459 }
460 
463 }
464 
466  const Ip6Address &target,
467  uint8_t *sip, uint8_t *dip) {
468  nd_neighbor_solicit *icmp = (nd_neighbor_solicit *)buf;
469  icmp->nd_ns_type = ND_NEIGHBOR_SOLICIT;
470  icmp->nd_ns_code = 0;
471  icmp->nd_ns_cksum = 0;
472  icmp->nd_ns_reserved = 0;
473  memcpy(icmp->nd_ns_target.s6_addr, target.to_bytes().data(), 16);
474  uint16_t offset = sizeof(nd_neighbor_solicit);
475 
476  if (!IsIPv6AddrUnspecifiedBytes(sip)) {
477  // add source linklayer address information
478  nd_opt_hdr *src_linklayer_addr = (nd_opt_hdr *)(buf + offset);
479  src_linklayer_addr->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
480  src_linklayer_addr->nd_opt_len = 1;
481  //XXX instead of ETHER_ADDR_LEN, actual buffer size should be given
482  //to preven buffer overrun.
483  agent()->vrrp_mac().ToArray(buf + offset + 2, ETHER_ADDR_LEN);
484  offset += sizeof(nd_opt_hdr) + ETHER_ADDR_LEN;
485  }
486 
487  icmp->nd_ns_cksum = Icmpv6Csum(sip, dip, (icmp6_hdr *)icmp, offset);
488  return offset;
489 }
490 
492  uint8_t *dip, uint8_t *sip,
493  const Ip6Address &target,
494  const MacAddress &dmac,
495  bool solicited) {
496  nd_neighbor_advert *icmp = (nd_neighbor_advert *)buf;
497  icmp->nd_na_type = ND_NEIGHBOR_ADVERT;
498  icmp->nd_na_code = 0;
499  icmp->nd_na_cksum = 0;
500  icmp->nd_na_flags_reserved = 0;
501  memcpy(icmp->nd_na_target.s6_addr, target.to_bytes().data(), 16);
502  if (solicited)
503  icmp->nd_na_flags_reserved |= ND_NA_FLAG_SOLICITED;
504  uint16_t offset = sizeof(nd_neighbor_advert);
505 
506  // add source linklayer address information
507  nd_opt_hdr *src_linklayer_addr = (nd_opt_hdr *)(buf + offset);
508  src_linklayer_addr->nd_opt_type = ND_OPT_TARGET_LINKADDR;
509  src_linklayer_addr->nd_opt_len = 1;
510  //XXX instead of ETHER_ADDR_LEN, actual buffer size should be given
511  //to preven buffer overrun.
512  dmac.ToArray(buf + offset + 2, ETHER_ADDR_LEN);
513  offset += sizeof(nd_opt_hdr) + ETHER_ADDR_LEN;
514 
515  icmp->nd_na_cksum = Icmpv6Csum(sip, dip, (icmp6_hdr *)icmp, offset);
516  return offset;
517 }
518 
519 void Icmpv6Handler::Ipv6Lower24BitsExtract(uint8_t *dst, uint8_t *src) {
520  for (int i = 0; i < 16; i++) {
521  dst[i] &= src[i];
522  }
523 }
524 
525 void Icmpv6Handler::Ipv6AddressBitwiseOr(uint8_t *dst, uint8_t *src) {
526  for (int i = 0; i < 16; i++) {
527  dst[i] |= src[i];
528  }
529 }
530 
532  uint8_t *ip, MacAddress &mac) {
533  /* A solicited-node multicast address is formed by taking the low-order
534  * 24 bits of an address (unicast or anycast) and appending those bits to
535  * the prefix FF02:0:0:0:0:1:FF00::/104 */
536 
537  /* Copy the higher order 104 bits of solicited node multicast IP */
538  memcpy(ip, kSolicitedNodeIpPrefix.to_bytes().data(), 16);
539 
540  uint8_t ip_bytes[16], suffix_mask_bytes[16];
541  memcpy(ip_bytes, dip.to_bytes().data(), 16);
542  memcpy(suffix_mask_bytes, kSolicitedNodeIpSuffixMask.to_bytes().data(), 16);
543  /* Extract lower order 24 bits of Destination IP */
544  Ipv6Lower24BitsExtract(ip_bytes, suffix_mask_bytes);
545 
546  /* Build the solicited node multicast address by joining upper order 104
547  * bits of FF02:0:0:0:0:1:FF00::/104 with lower 24 bits of destination IP*/
548  Ipv6AddressBitwiseOr(ip, ip_bytes);
549 
550  /* The ethernet address for IPv6 multicast address is 0x33-33-mm-mm-mm-mm,
551  * where mm-mm-mm-mm is a direct mapping of the last 32 bits of the
552  * IPv6 multicast address */
553  mac[0] = mac[1] = 0x33;
554  mac[2] = ip[12];
555  mac[3] = ip[13];
556  mac[4] = ip[14];
557  mac[5] = ip[15];
558 }
559 
561  const Ip6Address &tip,
562  const MacAddress &smac,
563  const MacAddress &dmac,
564  uint32_t itf, uint32_t vrf,
565  bool solicited) {
566  if (pkt_info_->packet_buffer() == NULL) {
567  pkt_info_->AllocPacketBuffer(agent(), PktHandler::ICMPV6, ICMP_PKT_SIZE,
568  0);
569  }
570 
571  char *buf = (char *)pkt_info_->pkt;
572  memset(buf, 0, pkt_info_->max_pkt_len);
573  pkt_info_->eth = (struct ether_header *)buf;
574  pkt_info_->ip6 = (ip6_hdr *)(pkt_info_->pkt + sizeof(struct ether_header));
575  icmp_ = pkt_info_->transp.icmp6 =
576  (icmp6_hdr *)(pkt_info_->pkt + sizeof(struct ether_header) +
577  sizeof(ip6_hdr));
578  uint8_t dip[16], source_ip[16];
579  memcpy(source_ip, sip.to_bytes().data(), sizeof(source_ip));
580  boost::system::error_code ec;
581  Ip6Address ip = Ip6Address::from_string(IPV6_ALL_NODES_ADDRESS, ec);
582  memcpy(dip, ip.to_bytes().data(), sizeof(dip));
583  uint16_t len = FillNeighborAdvertisement((uint8_t *)icmp_, &dip[0], &source_ip[0],
584  tip, dmac, solicited);
585  icmp_len_ = len;
586  SendIcmpv6Response(itf, vrf, source_ip, &dip[0], dmac, len);
587 }
588 
590  const Ip6Address &tip,
591  const VmInterface *vmi,
592  uint32_t vrf, bool send_unicast) {
593  if (pkt_info_->packet_buffer() == NULL) {
594  pkt_info_->AllocPacketBuffer(agent(), PktHandler::ICMPV6, ICMP_PKT_SIZE,
595  0);
596  }
597 
598  pkt_info_->eth = (struct ether_header *)(pkt_info_->pkt);
599  pkt_info_->ip6 = (ip6_hdr *)(pkt_info_->pkt + sizeof(struct ether_header));
600  uint32_t vlan_offset = 0;
601  if (vmi && vmi->tx_vlan_id() != VmInterface::kInvalidVlanId &&
602  !(agent()->tsn_enabled())) {
603  vlan_offset += 4;
604  }
605  icmp_ = pkt_info_->transp.icmp6 =
606  (icmp6_hdr *)(pkt_info_->pkt + sizeof(struct ether_header) +
607  vlan_offset + sizeof(ip6_hdr));
608  uint8_t solicited_mcast_ip[16], source_ip_bytes[16];
609  MacAddress dmac;
610  memcpy(source_ip_bytes, sip.to_bytes().data(), sizeof(source_ip_bytes));
611  if (send_unicast)
612  memcpy(solicited_mcast_ip, tip.to_bytes().data(), sizeof(solicited_mcast_ip));
613  else
614  SolicitedMulticastIpAndMac(tip, solicited_mcast_ip, dmac);
615  uint16_t len = FillNeighborSolicit((uint8_t *)icmp_, tip, source_ip_bytes,
616  solicited_mcast_ip);
617  SendIcmpv6Response(vmi?vmi->id():0, vrf, source_ip_bytes,
618  solicited_mcast_ip, dmac, len);
619 }
620 
622  const Ip6Address &addr) {
623  Interface *intf = agent()->interface_table()->FindInterface(ifindex);
624  if (!intf || intf->type() != Interface::VM_INTERFACE) {
625  return false;
626  }
627  VmInterface *vmi = static_cast<VmInterface *>(intf);
628  if (!vmi->vn()) {
629  return false;
630  }
631  const VnIpam *ipam = vmi->vn()->GetIpam(addr);
632  if (!ipam || !ipam->default_gw.is_v6()) {
633  return false;
634  }
635  return !(ipam->default_gw.to_v6().is_unspecified());
636 }
637 
639  p->refcount_++;
640 }
641 
643  if (p->refcount_.fetch_and_decrement() == 1) {
644  delete p;
645  }
646 }
boost::asio::ip::address_v6 Ip6Address
Definition: address.h:15
boost::asio::ip::address IpAddress
Definition: address.h:13
Definition: agent.h:360
InterfaceTable * interface_table() const
Definition: agent.h:467
OperDB * oper_db() const
Definition: agent.cc:1016
Icmpv6Proto * icmpv6_proto() const
Definition: agent.h:998
bool tsn_enabled() const
Definition: agent.h:1164
IpAddress router_id6() const
Definition: agent.h:669
static const MacAddress & vrrp_mac()
Definition: agent.h:441
void SendIcmpv6Response(uint32_t ifindex, uint32_t vrfindex, uint8_t *src_ip, uint8_t *dest_ip, const MacAddress &dest_mac, uint16_t len)
static const Ip6Address kSolicitedNodeIpPrefix
void SendNeighborSolicit(const Ip6Address &sip, const Ip6Address &dip, const VmInterface *vmi, uint32_t vrf, bool send_unicast=false)
void SendRAResponse(uint32_t ifindex, uint32_t vrfindex, uint8_t *src_ip, uint8_t *dest_ip, const MacAddress &dest_mac, const Ip6Address &prefix, uint8_t plen)
void SendPingResponse()
virtual ~Icmpv6Handler()
bool IsDefaultGatewayConfigured(uint32_t ifindex, const Ip6Address &addr)
void SendNeighborAdvert(const Ip6Address &sip, const Ip6Address &dip, const MacAddress &smac, const MacAddress &dmac, uint32_t itf, uint32_t vrf, bool solicited)
static const Ip6Address::bytes_type kSuffix
icmp6_hdr * icmp_
bool RouterAdvertisement(Icmpv6Proto *proto)
uint16_t FillRouterAdvertisement(uint8_t *buf, uint32_t ifindex, uint8_t *src, uint8_t *dest, const Ip6Address &prefix, uint8_t plen)
void EntryDelete(NdpKey &key)
static const Ip6Address kSolicitedNodeIpSuffixMask
void Ipv6Lower24BitsExtract(uint8_t *dst, uint8_t *src)
void SolicitedMulticastIpAndMac(const Ip6Address &dip, uint8_t *ip, MacAddress &mac)
tbb::atomic< uint32_t > refcount_
static const uint8_t kIPv6AddrUnspecifiedBytes[IPV6_ADDR_SIZE_BYTES]
uint16_t icmp_len_
uint16_t FillNeighborAdvertisement(uint8_t *buf, uint8_t *dip, uint8_t *sip, const Ip6Address &target, const MacAddress &dmac, bool solicited)
void Ipv6AddressBitwiseOr(uint8_t *dst, uint8_t *src)
Icmpv6Handler(Agent *agent, boost::shared_ptr< PktInfo > info, boost::asio::io_context &io)
static const Ip6Address::bytes_type kPrefix
bool IsIPv6AddrUnspecifiedBytes(const uint8_t *ip)
uint16_t FillNeighborSolicit(uint8_t *buf, const Ip6Address &target, uint8_t *sip, uint8_t *dip)
void IncrementStatsRouterSolicit(VmInterface *vmi)
void IncrementStatsNeighborAdvertUnSolicited(VmInterface *vmi)
Icmpv6Proto::UnsolNaIterator UnsolNaEntryIterator(const NdpKey &key, bool *key_valid)
bool DeleteNdpEntry(NdpEntry *entry)
NdpEntry * FindNdpEntry(const NdpKey &key)
std::map< NdpKey, NdpEntrySet >::iterator UnsolNaIterator
Definition: icmpv6_proto.h:86
void IncrementStatsPingResponse(VmInterface *vmi)
void IncrementStatsRouterAdvert(VmInterface *vmi)
void IncrementStatsPingRequest(VmInterface *vmi)
void IncrementStatsDrop()
Definition: icmpv6_proto.h:114
void IncrementStatsNeighborAdvertSolicited(VmInterface *vmi)
bool AddNdpEntry(NdpEntry *entry)
void HandlePathPreferenceNA(const VrfEntry *, uint32_t, IpAddress)
void IncrementStatsNeighborSolicited(VmInterface *vmi)
std::map< VmInterface *, Icmpv6Stats > VmInterfaceMap
Definition: icmpv6_proto.h:77
const VmInterfaceMap & vm_interfaces()
Definition: icmpv6_proto.h:108
const Interface * FindInterface(size_t index) const
Definition: interface.cc:323
@ VM_INTERFACE
Definition: interface.h:35
bool ipv6_active() const
Definition: interface.h:117
VrfEntry * vrf() const
Definition: interface.h:115
uint32_t vrf_id() const
Definition: interface.cc:621
Type type() const
Definition: interface.h:112
const uint32_t id() const
Definition: interface.h:123
bool ToArray(u_int8_t *p, size_t s) const
Definition: mac_address.cc:93
bool EnqueueNaIn(nd_neighbor_advert na, MacAddress mac)
Definition: ndp_entry.cc:720
void HandleNsRequest(nd_neighbor_solicit ns, MacAddress mac)
Definition: ndp_entry.cc:934
void SendNeighborAdvert(bool solicited)
Definition: ndp_entry.cc:899
const Interface * get_interface() const
Definition: ndp_entry.h:58
PathPreferenceModule * route_preference_module() const
Definition: operdb_init.h:58
Agent * agent() const
Definition: proto_handler.h:80
void Send(uint32_t itf, uint32_t vrf, uint16_t, PktHandler::PktModuleName)
int EthHdr(const MacAddress &src, const MacAddress &dest, const uint16_t proto)
uint16_t Icmpv6Csum(const uint8_t *src, const uint8_t *dest, icmp6_hdr *icmp, uint16_t plen) const
boost::asio::io_context & io_
Definition: proto_handler.h:93
void Ip6Hdr(ip6_hdr *ip, uint16_t plen, uint8_t next_header, uint8_t hlim, uint8_t *src, uint8_t *dest)
boost::shared_ptr< PktInfo > pkt_info_
Definition: proto_handler.h:92
uint32_t GetInterfaceIndex() const
Definition: proto_handler.h:82
Definition: trace.h:220
bool layer3_forwarding() const
VmInterface::VmiType vmi_type() const
uint16_t tx_vlan_id() const
bool IsIpv6Active() const
const VnEntry * vn() const
static const uint32_t kInvalidVlanId
Definition: vm_interface.h:360
const Ip6Address & primary_ip6_addr() const
bool HasServiceVlan() const
const VrfEntry * lr_vrf() const
Definition: vn.h:262
const VnIpam * GetIpam(const IpAddress &ip) const
Definition: vn.cc:651
bool GetPrefix(const Ip6Address &ip, Ip6Address *prefix, uint8_t *plen) const
Definition: vn.cc:700
static const uint32_t kInvalidIndex
Definition: vrf.h:88
const uint32_t vrf_id() const
Definition: vrf.h:99
void intrusive_ptr_add_ref(const Icmpv6Handler *p)
void intrusive_ptr_release(const Icmpv6Handler *p)
#define IPV6_ADDR_SIZE_BYTES
#define IPV6_ICMP_NEXT_HEADER
#define PKT0_LINKLOCAL_ADDRESS
Definition: icmpv6_proto.h:15
#define ICMPV6_TRACE(obj, arg)
Definition: icmpv6_proto.h:22
#define IPV6_ALL_NODES_ADDRESS
Definition: icmpv6_proto.h:13
#define ICMP_PKT_SIZE
Definition: icmpv6_proto.h:12
Definition: io_utils.cc:11
static const std::string integerToString(const NumberType &num)
Definition: string_util.h:19
@ TRAP_TOR_CONTROL_PKT
Definition: pkt_handler.h:143
InterfaceConstRef interface_
Definition: icmpv6_proto.h:53
const VrfEntry * vrf
Definition: ndp_entry.h:31
Ip6Address ip
Definition: ndp_entry.h:30
Definition: vn.h:28
IpAddress default_gw
Definition: vn.h:31