OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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  return ret;
205  }
206  ICMPV6_TRACE(Trace, "Ignoring Neighbor Solicit with wrong cksum");
207  break;
208  default:
209  break;
210  }
211  icmpv6_proto->IncrementStatsDrop();
212  return true;
213 }
214 
216  bool ret = true;
217  Icmpv6Proto::Icmpv6Ipc *ipc = static_cast<Icmpv6Proto::Icmpv6Ipc *>(
218  pkt_info_->ipc);
219  Icmpv6Proto *icmp_proto = agent()->icmpv6_proto();
220  switch(pkt_info_->ipc->cmd) {
222  NdpEntry *entry = icmp_proto->FindNdpEntry(ipc->key);
223  if (!entry) {
224  entry = new NdpEntry(io_, this, ipc->key, ipc->key.vrf,
225  ipc->interface_.get());
226  if (icmp_proto->AddNdpEntry(entry) == false) {
227  delete entry;
228  break;
229  }
230  ret = false;
231  }
232  const Interface* intf = ipc->interface_.get();
233  const VmInterface *vmi = dynamic_cast<const VmInterface *>(intf);
234  uint32_t vrf_id = intf->vrf_id();;
235  IpAddress ip = agent()->router_id6();
236  if (vrf_id != VrfEntry::kInvalidIndex) {
237  if (ip.is_v6()) {
238  SendNeighborSolicit(ip.to_v6(), ipc->key.ip, vmi, vrf_id);
239  VmInterface *vmif = const_cast<VmInterface *>(vmi);
240  icmp_proto->IncrementStatsNeighborSolicited(vmif);
241  }
242  }
243  break;
244  }
245 
247  EntryDelete(ipc->key);
248  break;
249  }
250 
252  bool key_valid = false;
254  icmp_proto->UnsolNaEntryIterator(ipc->key, &key_valid);
255  if (key_valid && !ipc->interface_->IsDeleted()) {
256  NdpEntry *entry = NULL;
257  Icmpv6Proto::NdpEntrySet::iterator sit = it->second.begin();
258  for (; sit != it->second.end(); sit++) {
259  entry = *sit;
260  if (entry->get_interface() == ipc->interface_.get())
261  break;
262  }
263  if (sit == it->second.end()) {
264  entry = new NdpEntry(io_, this, ipc->key, ipc->key.vrf,
265  ipc->interface_.get());
266  it->second.insert(entry);
267  ret = false;
268  }
269  if (entry) {
270  entry->SendNeighborAdvert(false);
271  const VmInterface *vmi = static_cast<const VmInterface *>(
272  ipc->interface_.get());
273  VmInterface *vmif = const_cast<VmInterface *>(vmi);
274  icmp_proto->IncrementStatsNeighborAdvertUnSolicited(vmif);
275  }
276  }
277  break;
278  }
279 
280  default:
281  ICMPV6_TRACE(Trace, "Received Invalid internal NDP message : " +
282  integerToString(pkt_info_->ipc->cmd));
283  break;
284  }
285 
286  delete ipc;
287  return ret;
288 }
289 
291  Icmpv6Proto *icmp_proto = agent()->icmpv6_proto();
292  NdpEntry *entry = icmp_proto->FindNdpEntry(key);
293  if (entry) {
294  // this request comes when NDP NH is deleted; nothing more to do
295  icmp_proto->DeleteNdpEntry(entry);
296  }
297 }
298 
300  const Icmpv6Proto::VmInterfaceMap &interfaces = proto->vm_interfaces();
301  boost::system::error_code ec;
302  Ip6Address src_addr = Ip6Address::from_string(PKT0_LINKLOCAL_ADDRESS, ec);
303  Ip6Address dest_addr = Ip6Address::from_string(IPV6_ALL_NODES_ADDRESS, ec);
304  // Ethernet mcast address corresponding to IPv6 mcast address ff02::1
305  MacAddress dest_mac(0x33, 0x33, 0x00, 0x00, 0x00, 0x01);
306  for (Icmpv6Proto::VmInterfaceMap::const_iterator it = interfaces.begin();
307  it != interfaces.end(); ++it) {
308  VmInterface *vmi = it->first;
309  if (vmi->vmi_type() == VmInterface::VHOST ||
310  (vmi->vmi_type() == VmInterface::BAREMETAL &&
311  vmi->vn() != NULL && vmi->vn()->lr_vrf() != NULL)) {
312  continue;
313  }
314 
315  if (vmi->IsIpv6Active() && !vmi->HasServiceVlan()) {
316  pkt_info_->AllocPacketBuffer(agent(), PktHandler::ICMPV6, ICMP_PKT_SIZE, 0);
317  pkt_info_->eth = (struct ether_header *)(pkt_info_->pkt);
318  pkt_info_->ip6 = (ip6_hdr *)(pkt_info_->pkt + sizeof(struct ether_header));
319  /* For baremetal/local vm set the appropriate information that will be used
320  * to decide to route/switch the RA packet to the TOR switch
321  */
322  pkt_info_->agent_hdr.cmd =
323  (vmi->vmi_type() == VmInterface::BAREMETAL) ?
325  uint32_t vlan_offset = 0;
326  if (vmi->tx_vlan_id() != VmInterface::kInvalidVlanId &&
327  !(agent()->tsn_enabled())) {
328  vlan_offset += 4;
329  }
330  icmp_ = pkt_info_->transp.icmp6 =
331  (icmp6_hdr *)(pkt_info_->pkt + sizeof(struct ether_header) +
332  vlan_offset + sizeof(ip6_hdr));
333  Ip6Address prefix;
334  uint8_t plen;
335  if (vmi->vn()->GetPrefix(vmi->primary_ip6_addr(), &prefix, &plen)) {
336  SendRAResponse(vmi->id(), vmi->vrf()->vrf_id(),
337  src_addr.to_bytes().data(),
338  dest_addr.to_bytes().data(),
339  dest_mac, prefix, plen);
340  proto->IncrementStatsRouterAdvert(vmi);
341  }
342  }
343  }
344 
345  return true;
346 }
347 
349  if (pkt_info_->len < (sizeof(struct ether_header) + sizeof(ip6_hdr) +
350  ntohs(pkt_info_->ip6->ip6_plen)))
351  return false;
352 
353  uint16_t checksum = icmp_->icmp6_cksum;
354  icmp_->icmp6_cksum = 0;
355  if (checksum == Icmpv6Csum(pkt_info_->ip6->ip6_src.s6_addr,
356  pkt_info_->ip6->ip6_dst.s6_addr,
357  icmp_, icmp_len_))
358  return true;
359 
360  return false;
361 }
362 
363 uint16_t Icmpv6Handler::FillRouterAdvertisement(uint8_t *buf, uint32_t ifindex,
364  uint8_t *src, uint8_t *dest,
365  const Ip6Address &prefix,
366  uint8_t plen) {
367  nd_router_advert *icmp = (nd_router_advert *)buf;
368  icmp->nd_ra_type = ND_ROUTER_ADVERT;
369  icmp->nd_ra_code = 0;
370  icmp->nd_ra_cksum = 0;
371  icmp->nd_ra_curhoplimit = 64;
372  icmp->nd_ra_flags_reserved = ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER; //DHCPv6
373  icmp->nd_ra_reachable = 0;
374  icmp->nd_ra_retransmit = 0;
375 
376  bool def_gw = IsDefaultGatewayConfigured(ifindex, prefix);
377  if (def_gw) {
378  icmp->nd_ra_router_lifetime = htons(9000);
379  } else {
380  icmp->nd_ra_router_lifetime = 0;
381  }
382 
383  // add source linklayer address information
384  uint16_t offset = sizeof(nd_router_advert);
385  nd_opt_hdr *src_linklayer_addr = (nd_opt_hdr *)(buf + offset);
386  src_linklayer_addr->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
387  src_linklayer_addr->nd_opt_len = 1;
388  //XXX instead of ETHER_ADDR_LEN, actual buffer size should be given
389  //to preven buffer overrun.
390  agent()->vrrp_mac().ToArray(buf + offset + 2, ETHER_ADDR_LEN);
391 
392  // add prefix information
393  offset += sizeof(nd_opt_hdr) + ETHER_ADDR_LEN;
394  nd_opt_prefix_info *prefix_info = (nd_opt_prefix_info *)(buf + offset);
395  prefix_info->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
396  prefix_info->nd_opt_pi_len = 4;
397  prefix_info->nd_opt_pi_prefix_len = plen;
398  // not setting ND_OPT_PI_FLAG_AUTO or ND_OPT_PI_FLAG_RADDR
399  prefix_info->nd_opt_pi_flags_reserved = ND_OPT_PI_FLAG_ONLINK;
400  prefix_info->nd_opt_pi_valid_time = htonl(0xFFFFFFFF);
401  prefix_info->nd_opt_pi_preferred_time = htonl(0xFFFFFFFF);
402  prefix_info->nd_opt_pi_reserved2 = 0;
403  memcpy(prefix_info->nd_opt_pi_prefix.s6_addr, prefix.to_bytes().data(), 16);
404 
405  offset += sizeof(nd_opt_prefix_info);
406  icmp->nd_ra_cksum = Icmpv6Csum(src, dest, (icmp6_hdr *)icmp, offset);
407 
408  return offset;
409 }
410 
411 void Icmpv6Handler::SendRAResponse(uint32_t ifindex, uint32_t vrfindex,
412  uint8_t *src_ip, uint8_t *dest_ip,
413  const MacAddress &dest_mac,
414  const Ip6Address &prefix, uint8_t plen) {
415  // fill in the response
416  uint16_t len = FillRouterAdvertisement((uint8_t *)icmp_, ifindex, src_ip,
417  dest_ip, prefix, plen);
418  SendIcmpv6Response(ifindex, vrfindex, src_ip, dest_ip, dest_mac, len);
419 }
420 
422  icmp_->icmp6_type = ICMP6_ECHO_REPLY;
423  icmp_->icmp6_cksum = 0;
424  icmp_->icmp6_cksum =
425  Icmpv6Csum(pkt_info_->ip_daddr.to_v6().to_bytes().data(),
426  pkt_info_->ip_saddr.to_v6().to_bytes().data(),
427  icmp_, ntohs(pkt_info_->ip6->ip6_plen));
428  uint32_t interface =
429  (pkt_info_->agent_hdr.cmd == AgentHdr::TRAP_TOR_CONTROL_PKT) ?
430  pkt_info_->agent_hdr.cmd_param : GetInterfaceIndex();
431  SendIcmpv6Response(interface, pkt_info_->vrf,
432  pkt_info_->ip_daddr.to_v6().to_bytes().data(),
433  pkt_info_->ip_saddr.to_v6().to_bytes().data(),
434  MacAddress(pkt_info_->eth->ether_shost),
435  ntohs(pkt_info_->ip6->ip6_plen));
436 }
437 
438 void Icmpv6Handler::SendIcmpv6Response(uint32_t ifindex, uint32_t vrfindex,
439  uint8_t *src_ip, uint8_t *dest_ip,
440  const MacAddress &dest_mac,
441  uint16_t len) {
442 
443  char *buff = (char *)pkt_info_->pkt;
444  uint16_t buff_len = pkt_info_->packet_buffer()->data_len();
445  boost::scoped_array<char> icmpv6_payload(new char[icmp_len_]);
446  memcpy(icmpv6_payload.get(),icmp_,icmp_len_);
447  uint16_t eth_len = EthHdr(buff, buff_len, ifindex, agent()->vrrp_mac(),
448  dest_mac, ETHERTYPE_IPV6);
449 
450  pkt_info_->ip6 = (struct ip6_hdr *)(buff + eth_len);
451  Ip6Hdr(pkt_info_->ip6, len, IPV6_ICMP_NEXT_HEADER, 255, src_ip, dest_ip);
452  memcpy(buff + sizeof(ip6_hdr) + eth_len, icmpv6_payload.get(), icmp_len_);
453  pkt_info_->set_len(len + sizeof(ip6_hdr) + eth_len);
454  uint16_t command =
455  (pkt_info_->agent_hdr.cmd == AgentHdr::TRAP_TOR_CONTROL_PKT) ?
457  Send(ifindex, vrfindex, command, PktHandler::ICMPV6);
458 }
459 
462 }
463 
465  const Ip6Address &target,
466  uint8_t *sip, uint8_t *dip) {
467  nd_neighbor_solicit *icmp = (nd_neighbor_solicit *)buf;
468  icmp->nd_ns_type = ND_NEIGHBOR_SOLICIT;
469  icmp->nd_ns_code = 0;
470  icmp->nd_ns_cksum = 0;
471  icmp->nd_ns_reserved = 0;
472  memcpy(icmp->nd_ns_target.s6_addr, target.to_bytes().data(), 16);
473  uint16_t offset = sizeof(nd_neighbor_solicit);
474 
475  if (!IsIPv6AddrUnspecifiedBytes(sip)) {
476  // add source linklayer address information
477  nd_opt_hdr *src_linklayer_addr = (nd_opt_hdr *)(buf + offset);
478  src_linklayer_addr->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
479  src_linklayer_addr->nd_opt_len = 1;
480  //XXX instead of ETHER_ADDR_LEN, actual buffer size should be given
481  //to preven buffer overrun.
482  agent()->vrrp_mac().ToArray(buf + offset + 2, ETHER_ADDR_LEN);
483  offset += sizeof(nd_opt_hdr) + ETHER_ADDR_LEN;
484  }
485 
486  icmp->nd_ns_cksum = Icmpv6Csum(sip, dip, (icmp6_hdr *)icmp, offset);
487  return offset;
488 }
489 
491  uint8_t *dip, uint8_t *sip,
492  const Ip6Address &target,
493  const MacAddress &dmac,
494  bool solicited) {
495  nd_neighbor_advert *icmp = (nd_neighbor_advert *)buf;
496  icmp->nd_na_type = ND_NEIGHBOR_ADVERT;
497  icmp->nd_na_code = 0;
498  icmp->nd_na_cksum = 0;
499  icmp->nd_na_flags_reserved = 0;
500  memcpy(icmp->nd_na_target.s6_addr, target.to_bytes().data(), 16);
501  if (solicited)
502  icmp->nd_na_flags_reserved |= ND_NA_FLAG_SOLICITED;
503  uint16_t offset = sizeof(nd_neighbor_advert);
504 
505  // add source linklayer address information
506  nd_opt_hdr *src_linklayer_addr = (nd_opt_hdr *)(buf + offset);
507  src_linklayer_addr->nd_opt_type = ND_OPT_TARGET_LINKADDR;
508  src_linklayer_addr->nd_opt_len = 1;
509  //XXX instead of ETHER_ADDR_LEN, actual buffer size should be given
510  //to preven buffer overrun.
511  dmac.ToArray(buf + offset + 2, ETHER_ADDR_LEN);
512  offset += sizeof(nd_opt_hdr) + ETHER_ADDR_LEN;
513 
514  icmp->nd_na_cksum = Icmpv6Csum(sip, dip, (icmp6_hdr *)icmp, offset);
515  return offset;
516 }
517 
518 void Icmpv6Handler::Ipv6Lower24BitsExtract(uint8_t *dst, uint8_t *src) {
519  for (int i = 0; i < 16; i++) {
520  dst[i] &= src[i];
521  }
522 }
523 
524 void Icmpv6Handler::Ipv6AddressBitwiseOr(uint8_t *dst, uint8_t *src) {
525  for (int i = 0; i < 16; i++) {
526  dst[i] |= src[i];
527  }
528 }
529 
531  uint8_t *ip, MacAddress &mac) {
532  /* A solicited-node multicast address is formed by taking the low-order
533  * 24 bits of an address (unicast or anycast) and appending those bits to
534  * the prefix FF02:0:0:0:0:1:FF00::/104 */
535 
536  /* Copy the higher order 104 bits of solicited node multicast IP */
537  memcpy(ip, kSolicitedNodeIpPrefix.to_bytes().data(), 16);
538 
539  uint8_t ip_bytes[16], suffix_mask_bytes[16];
540  memcpy(ip_bytes, dip.to_bytes().data(), 16);
541  memcpy(suffix_mask_bytes, kSolicitedNodeIpSuffixMask.to_bytes().data(), 16);
542  /* Extract lower order 24 bits of Destination IP */
543  Ipv6Lower24BitsExtract(ip_bytes, suffix_mask_bytes);
544 
545  /* Build the solicited node multicast address by joining upper order 104
546  * bits of FF02:0:0:0:0:1:FF00::/104 with lower 24 bits of destination IP*/
547  Ipv6AddressBitwiseOr(ip, ip_bytes);
548 
549  /* The ethernet address for IPv6 multicast address is 0x33-33-mm-mm-mm-mm,
550  * where mm-mm-mm-mm is a direct mapping of the last 32 bits of the
551  * IPv6 multicast address */
552  mac[0] = mac[1] = 0x33;
553  mac[2] = ip[12];
554  mac[3] = ip[13];
555  mac[4] = ip[14];
556  mac[5] = ip[15];
557 }
558 
560  const Ip6Address &tip,
561  const MacAddress &smac,
562  const MacAddress &dmac,
563  uint32_t itf, uint32_t vrf,
564  bool solicited) {
565  if (pkt_info_->packet_buffer() == NULL) {
566  pkt_info_->AllocPacketBuffer(agent(), PktHandler::ICMPV6, ICMP_PKT_SIZE,
567  0);
568  }
569 
570  char *buf = (char *)pkt_info_->pkt;
571  memset(buf, 0, pkt_info_->max_pkt_len);
572  pkt_info_->eth = (struct ether_header *)buf;
573  pkt_info_->ip6 = (ip6_hdr *)(pkt_info_->pkt + sizeof(struct ether_header));
574  icmp_ = pkt_info_->transp.icmp6 =
575  (icmp6_hdr *)(pkt_info_->pkt + sizeof(struct ether_header) +
576  sizeof(ip6_hdr));
577  uint8_t dip[16], source_ip[16];
578  memcpy(source_ip, sip.to_bytes().data(), sizeof(source_ip));
579  boost::system::error_code ec;
580  Ip6Address ip = Ip6Address::from_string(IPV6_ALL_NODES_ADDRESS, ec);
581  memcpy(dip, ip.to_bytes().data(), sizeof(dip));
582  uint16_t len = FillNeighborAdvertisement((uint8_t *)icmp_, &dip[0], &source_ip[0],
583  tip, dmac, solicited);
584  icmp_len_ = len;
585  SendIcmpv6Response(itf, vrf, source_ip, &dip[0], dmac, len);
586 }
587 
589  const Ip6Address &tip,
590  const VmInterface *vmi,
591  uint32_t vrf, bool send_unicast) {
592  if (pkt_info_->packet_buffer() == NULL) {
593  pkt_info_->AllocPacketBuffer(agent(), PktHandler::ICMPV6, ICMP_PKT_SIZE,
594  0);
595  }
596 
597  pkt_info_->eth = (struct ether_header *)(pkt_info_->pkt);
598  pkt_info_->ip6 = (ip6_hdr *)(pkt_info_->pkt + sizeof(struct ether_header));
599  uint32_t vlan_offset = 0;
600  if (vmi && vmi->tx_vlan_id() != VmInterface::kInvalidVlanId &&
601  !(agent()->tsn_enabled())) {
602  vlan_offset += 4;
603  }
604  icmp_ = pkt_info_->transp.icmp6 =
605  (icmp6_hdr *)(pkt_info_->pkt + sizeof(struct ether_header) +
606  vlan_offset + sizeof(ip6_hdr));
607  uint8_t solicited_mcast_ip[16], source_ip_bytes[16];
608  MacAddress dmac;
609  memcpy(source_ip_bytes, sip.to_bytes().data(), sizeof(source_ip_bytes));
610  if (send_unicast)
611  memcpy(solicited_mcast_ip, tip.to_bytes().data(), sizeof(solicited_mcast_ip));
612  else
613  SolicitedMulticastIpAndMac(tip, solicited_mcast_ip, dmac);
614  uint16_t len = FillNeighborSolicit((uint8_t *)icmp_, tip, source_ip_bytes,
615  solicited_mcast_ip);
616  SendIcmpv6Response(vmi?vmi->id():0, vrf, source_ip_bytes,
617  solicited_mcast_ip, dmac, len);
618 }
619 
621  const Ip6Address &addr) {
622  Interface *intf = agent()->interface_table()->FindInterface(ifindex);
623  if (!intf || intf->type() != Interface::VM_INTERFACE) {
624  return false;
625  }
626  VmInterface *vmi = static_cast<VmInterface *>(intf);
627  if (!vmi->vn()) {
628  return false;
629  }
630  const VnIpam *ipam = vmi->vn()->GetIpam(addr);
631  if (!ipam || !ipam->default_gw.is_v6()) {
632  return false;
633  }
634  return !(ipam->default_gw.to_v6().is_unspecified());
635 }
636 
638  p->refcount_++;
639 }
640 
642  if (p->refcount_.fetch_and_decrement() == 1) {
643  delete p;
644  }
645 }
icmp6_hdr * icmp_
static const Ip6Address::bytes_type kSuffix
std::map< NdpKey, NdpEntrySet >::iterator UnsolNaIterator
Definition: icmpv6_proto.h:86
int intrusive_ptr_add_ref(const AsPath *cpath)
Definition: bgp_aspath.h:147
std::map< VmInterface *, Icmpv6Stats > VmInterfaceMap
Definition: icmpv6_proto.h:77
NdpEntry * FindNdpEntry(const NdpKey &key)
Type type() const
Definition: interface.h:112
void HandlePathPreferenceNA(const VrfEntry *, uint32_t, IpAddress)
bool tsn_enabled() const
Definition: agent.h:1162
Ip6Address ip
Definition: ndp_entry.h:30
bool DeleteNdpEntry(NdpEntry *entry)
static const uint8_t kIPv6AddrUnspecifiedBytes[IPV6_ADDR_SIZE_BYTES]
bool HasServiceVlan() const
bool ToArray(u_int8_t *p, size_t s) const
Definition: mac_address.cc:93
uint16_t icmp_len_
const uint32_t id() const
Definition: interface.h:123
static const Ip6Address::bytes_type kPrefix
const VnIpam * GetIpam(const IpAddress &ip) const
Definition: vn.cc:651
Definition: vn.h:28
uint16_t FillNeighborSolicit(uint8_t *buf, const Ip6Address &target, uint8_t *sip, uint8_t *dip)
static const Ip6Address kSolicitedNodeIpPrefix
void IncrementStatsNeighborAdvertUnSolicited(VmInterface *vmi)
void Ipv6Lower24BitsExtract(uint8_t *dst, uint8_t *src)
boost::asio::ip::address IpAddress
Definition: address.h:13
static const MacAddress & vrrp_mac()
Definition: agent.h:439
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)
#define IPV6_ADDR_SIZE_BYTES
InterfaceTable * interface_table() const
Definition: agent.h:465
bool RouterAdvertisement(Icmpv6Proto *proto)
VrfEntry * vrf() const
Definition: interface.h:115
Agent * agent() const
Definition: proto_handler.h:80
void SendPingResponse()
boost::shared_ptr< PktInfo > pkt_info_
Definition: proto_handler.h:92
OperDB * oper_db() const
Definition: agent.cc:1013
uint16_t tx_vlan_id() const
void IncrementStatsDrop()
Definition: icmpv6_proto.h:114
void IncrementStatsRouterSolicit(VmInterface *vmi)
void IncrementStatsPingResponse(VmInterface *vmi)
int EthHdr(const MacAddress &src, const MacAddress &dest, const uint16_t proto)
void IncrementStatsNeighborSolicited(VmInterface *vmi)
void SendNeighborAdvert(const Ip6Address &sip, const Ip6Address &dip, const MacAddress &smac, const MacAddress &dmac, uint32_t itf, uint32_t vrf, bool solicited)
static const std::string integerToString(const NumberType &num)
Definition: string_util.h:19
IpAddress default_gw
Definition: vn.h:31
static const uint32_t kInvalidVlanId
Definition: vm_interface.h:360
void IncrementStatsNeighborAdvertSolicited(VmInterface *vmi)
Definition: agent.h:358
uint32_t GetInterfaceIndex() const
Definition: proto_handler.h:82
void IncrementStatsRouterAdvert(VmInterface *vmi)
uint32_t vrf_id() const
Definition: interface.cc:621
tbb::atomic< uint32_t > refcount_
PathPreferenceModule * route_preference_module() const
Definition: operdb_init.h:58
boost::asio::ip::address_v6 Ip6Address
Definition: address.h:15
void Send(uint32_t itf, uint32_t vrf, uint16_t, PktHandler::PktModuleName)
const VrfEntry * vrf
Definition: ndp_entry.h:31
bool layer3_forwarding() const
Definition: trace.h:220
uint16_t FillNeighborAdvertisement(uint8_t *buf, uint8_t *dip, uint8_t *sip, const Ip6Address &target, const MacAddress &dmac, bool solicited)
boost::asio::io_context & io_
Definition: proto_handler.h:93
#define PKT0_LINKLOCAL_ADDRESS
Definition: icmpv6_proto.h:15
void SolicitedMulticastIpAndMac(const Ip6Address &dip, uint8_t *ip, MacAddress &mac)
bool IsDefaultGatewayConfigured(uint32_t ifindex, const Ip6Address &addr)
const Interface * get_interface() const
Definition: ndp_entry.h:58
const VnEntry * vn() const
void SendNeighborAdvert(bool solicited)
Definition: ndp_entry.cc:899
const uint32_t vrf_id() const
Definition: vrf.h:99
Icmpv6Proto::UnsolNaIterator UnsolNaEntryIterator(const NdpKey &key, bool *key_valid)
IpAddress router_id6() const
Definition: agent.h:667
void Ip6Hdr(ip6_hdr *ip, uint16_t plen, uint8_t next_header, uint8_t hlim, uint8_t *src, uint8_t *dest)
uint16_t FillRouterAdvertisement(uint8_t *buf, uint32_t ifindex, uint8_t *src, uint8_t *dest, const Ip6Address &prefix, uint8_t plen)
void SendNeighborSolicit(const Ip6Address &sip, const Ip6Address &dip, const VmInterface *vmi, uint32_t vrf, bool send_unicast=false)
void HandleNsRequest(nd_neighbor_solicit *ns, MacAddress mac)
Definition: ndp_entry.cc:934
void Ipv6AddressBitwiseOr(uint8_t *dst, uint8_t *src)
VmInterface::VmiType vmi_type() const
const Ip6Address & primary_ip6_addr() const
#define ICMP_PKT_SIZE
Definition: icmpv6_proto.h:12
const Interface * FindInterface(size_t index) const
Definition: interface.cc:323
Icmpv6Proto * icmpv6_proto() const
Definition: agent.h:996
static const uint32_t kInvalidIndex
Definition: vrf.h:88
void EntryDelete(NdpKey &key)
const VmInterfaceMap & vm_interfaces()
Definition: icmpv6_proto.h:108
void intrusive_ptr_release(const AsPath *cpath)
Definition: bgp_aspath.h:155
bool AddNdpEntry(NdpEntry *entry)
InterfaceConstRef interface_
Definition: icmpv6_proto.h:53
void IncrementStatsPingRequest(VmInterface *vmi)
const VrfEntry * lr_vrf() const
Definition: vn.h:261
virtual ~Icmpv6Handler()
bool IsIPv6AddrUnspecifiedBytes(const uint8_t *ip)
#define IPV6_ICMP_NEXT_HEADER
void SendIcmpv6Response(uint32_t ifindex, uint32_t vrfindex, uint8_t *src_ip, uint8_t *dest_ip, const MacAddress &dest_mac, uint16_t len)
uint16_t Icmpv6Csum(const uint8_t *src, const uint8_t *dest, icmp6_hdr *icmp, uint16_t plen) const
bool IsIpv6Active() const
static const Ip6Address kSolicitedNodeIpSuffixMask
bool GetPrefix(const Ip6Address &ip, Ip6Address *prefix, uint8_t *plen) const
Definition: vn.cc:700
bool ipv6_active() const
Definition: interface.h:117
bool EnqueueNaIn(nd_neighbor_advert *na, MacAddress mac)
Definition: ndp_entry.cc:720
#define IPV6_ALL_NODES_ADDRESS
Definition: icmpv6_proto.h:13
#define ICMPV6_TRACE(obj, arg)
Definition: icmpv6_proto.h:22
Icmpv6Handler(Agent *agent, boost::shared_ptr< PktInfo > info, boost::asio::io_context &io)