6 #include <netinet/icmp6.h>
12 #include "services/services_types.h"
19 #include <boost/scoped_array.hpp>
22 { {0xFF, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0xFF, 0, 0, 0} };
24 { {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0xFF} };
30 boost::asio::io_context &io)
31 :
ProtoHandler(agent, info, io), icmp_(pkt_info_->transp.icmp6) {
46 assert(
agent()->icmpv6_proto());
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:
88 boost::system::error_code ec;
101 src_addr.to_bytes().data(),
102 pkt_info_->ip_saddr.to_v6().to_bytes().data(),
113 case ICMP6_ECHO_REQUEST:
123 case ND_NEIGHBOR_ADVERT:
124 if (icmp->nd_na_flags_reserved & ND_NA_FLAG_SOLICITED) {
130 Ip6Address::bytes_type bytes;
131 for (
int i = 0; i < 16; i++) {
132 bytes[i] = icmp->nd_na_target.s6_addr[i];
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) {
139 "Target Link-layer address option");
144 uint8_t *buf = (((uint8_t *)icmp) + offset + 2);
149 EnqueueTrafficSeen(addr, 128, itf->
id(),
164 case ND_NEIGHBOR_SOLICIT:
167 Ip6Address::bytes_type bytes;
168 for (
int i = 0; i < 16; i++) {
169 bytes[i] =
pkt_info_->ip6->ip6_src.s6_addr[i];
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()) {
176 "unspecified address");
181 if (opt->nd_opt_type == ND_OPT_TARGET_LINKADDR) {
183 buf = (((uint8_t *)icmp) + offset);
234 uint32_t vrf_id = intf->
vrf_id();;
252 bool key_valid =
false;
255 if (key_valid && !ipc->
interface_->IsDeleted()) {
257 Icmpv6Proto::NdpEntrySet::iterator sit = it->second.begin();
258 for (; sit != it->second.end(); sit++) {
263 if (sit == it->second.end()) {
266 it->second.insert(entry);
301 boost::system::error_code ec;
305 MacAddress dest_mac(0x33, 0x33, 0x00, 0x00, 0x00, 0x01);
306 for (Icmpv6Proto::VmInterfaceMap::const_iterator it = interfaces.begin();
307 it != interfaces.end(); ++it) {
311 vmi->
vn() != NULL && vmi->
vn()->
lr_vrf() != NULL)) {
325 uint32_t vlan_offset = 0;
331 (icmp6_hdr *)(
pkt_info_->pkt +
sizeof(
struct ether_header) +
332 vlan_offset +
sizeof(ip6_hdr));
337 src_addr.to_bytes().data(),
338 dest_addr.to_bytes().data(),
339 dest_mac, prefix, plen);
349 if (
pkt_info_->len < (
sizeof(
struct ether_header) +
sizeof(ip6_hdr) +
353 uint16_t checksum =
icmp_->icmp6_cksum;
354 icmp_->icmp6_cksum = 0;
364 uint8_t *src, uint8_t *dest,
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;
373 icmp->nd_ra_reachable = 0;
374 icmp->nd_ra_retransmit = 0;
378 icmp->nd_ra_router_lifetime = htons(9000);
380 icmp->nd_ra_router_lifetime = 0;
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;
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;
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);
405 offset +=
sizeof(nd_opt_prefix_info);
406 icmp->nd_ra_cksum =
Icmpv6Csum(src, dest, (icmp6_hdr *)icmp, offset);
412 uint8_t *src_ip, uint8_t *dest_ip,
417 dest_ip, prefix, plen);
422 icmp_->icmp6_type = ICMP6_ECHO_REPLY;
423 icmp_->icmp6_cksum = 0;
426 pkt_info_->ip_saddr.to_v6().to_bytes().data(),
432 pkt_info_->ip_daddr.to_v6().to_bytes().data(),
433 pkt_info_->ip_saddr.to_v6().to_bytes().data(),
439 uint8_t *src_ip, uint8_t *dest_ip,
444 uint16_t buff_len =
pkt_info_->packet_buffer()->data_len();
445 boost::scoped_array<char> icmpv6_payload(
new char[
icmp_len_]);
447 uint16_t eth_len =
EthHdr(buff, buff_len, ifindex,
agent()->vrrp_mac(),
448 dest_mac, ETHERTYPE_IPV6);
450 pkt_info_->ip6 = (
struct ip6_hdr *)(buff + eth_len);
452 memcpy(buff +
sizeof(ip6_hdr) + eth_len, icmpv6_payload.get(),
icmp_len_);
453 pkt_info_->set_len(len +
sizeof(ip6_hdr) + eth_len);
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);
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;
483 offset +=
sizeof(nd_opt_hdr) + ETHER_ADDR_LEN;
486 icmp->nd_ns_cksum =
Icmpv6Csum(sip, dip, (icmp6_hdr *)icmp, offset);
491 uint8_t *dip, uint8_t *sip,
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);
502 icmp->nd_na_flags_reserved |= ND_NA_FLAG_SOLICITED;
503 uint16_t offset =
sizeof(nd_neighbor_advert);
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;
511 dmac.
ToArray(buf + offset + 2, ETHER_ADDR_LEN);
512 offset +=
sizeof(nd_opt_hdr) + ETHER_ADDR_LEN;
514 icmp->nd_na_cksum =
Icmpv6Csum(sip, dip, (icmp6_hdr *)icmp, offset);
519 for (
int i = 0; i < 16; i++) {
525 for (
int i = 0; i < 16; i++) {
539 uint8_t ip_bytes[16], suffix_mask_bytes[16];
540 memcpy(ip_bytes, dip.to_bytes().data(), 16);
552 mac[0] = mac[1] = 0x33;
563 uint32_t itf, uint32_t vrf,
565 if (
pkt_info_->packet_buffer() == NULL) {
572 pkt_info_->eth = (
struct ether_header *)buf;
575 (icmp6_hdr *)(
pkt_info_->pkt +
sizeof(
struct ether_header) +
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;
581 memcpy(dip, ip.to_bytes().data(),
sizeof(dip));
583 tip, dmac, solicited);
591 uint32_t vrf,
bool send_unicast) {
592 if (
pkt_info_->packet_buffer() == NULL) {
599 uint32_t vlan_offset = 0;
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];
609 memcpy(source_ip_bytes, sip.to_bytes().data(),
sizeof(source_ip_bytes));
611 memcpy(solicited_mcast_ip, tip.to_bytes().data(),
sizeof(solicited_mcast_ip));
617 solicited_mcast_ip, dmac, len);
634 return !(ipam->
default_gw.to_v6().is_unspecified());
642 if (p->
refcount_.fetch_and_decrement() == 1) {
static const Ip6Address::bytes_type kSuffix
std::map< NdpKey, NdpEntrySet >::iterator UnsolNaIterator
int intrusive_ptr_add_ref(const AsPath *cpath)
std::map< VmInterface *, Icmpv6Stats > VmInterfaceMap
NdpEntry * FindNdpEntry(const NdpKey &key)
void HandlePathPreferenceNA(const VrfEntry *, uint32_t, IpAddress)
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
const uint32_t id() const
static const Ip6Address::bytes_type kPrefix
const VnIpam * GetIpam(const IpAddress &ip) const
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
static const MacAddress & vrrp_mac()
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
bool RouterAdvertisement(Icmpv6Proto *proto)
boost::shared_ptr< PktInfo > pkt_info_
uint16_t tx_vlan_id() const
void IncrementStatsDrop()
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)
static const uint32_t kInvalidVlanId
void IncrementStatsNeighborAdvertSolicited(VmInterface *vmi)
uint32_t GetInterfaceIndex() const
void IncrementStatsRouterAdvert(VmInterface *vmi)
tbb::atomic< uint32_t > refcount_
PathPreferenceModule * route_preference_module() const
boost::asio::ip::address_v6 Ip6Address
void Send(uint32_t itf, uint32_t vrf, uint16_t, PktHandler::PktModuleName)
bool layer3_forwarding() const
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_
#define PKT0_LINKLOCAL_ADDRESS
void SolicitedMulticastIpAndMac(const Ip6Address &dip, uint8_t *ip, MacAddress &mac)
bool IsDefaultGatewayConfigured(uint32_t ifindex, const Ip6Address &addr)
const Interface * get_interface() const
const VnEntry * vn() const
void SendNeighborAdvert(bool solicited)
const uint32_t vrf_id() const
Icmpv6Proto::UnsolNaIterator UnsolNaEntryIterator(const NdpKey &key, bool *key_valid)
IpAddress router_id6() const
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)
void Ipv6AddressBitwiseOr(uint8_t *dst, uint8_t *src)
VmInterface::VmiType vmi_type() const
const Ip6Address & primary_ip6_addr() const
const Interface * FindInterface(size_t index) const
Icmpv6Proto * icmpv6_proto() const
static const uint32_t kInvalidIndex
void EntryDelete(NdpKey &key)
const VmInterfaceMap & vm_interfaces()
void intrusive_ptr_release(const AsPath *cpath)
bool AddNdpEntry(NdpEntry *entry)
InterfaceConstRef interface_
void IncrementStatsPingRequest(VmInterface *vmi)
const VrfEntry * lr_vrf() const
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
bool EnqueueNaIn(nd_neighbor_advert *na, MacAddress mac)
#define IPV6_ALL_NODES_ADDRESS
#define ICMPV6_TRACE(obj, arg)
Icmpv6Handler(Agent *agent, boost::shared_ptr< PktInfo > info, boost::asio::io_context &io)