|
Description
|
While diagnosing an issue with Clearview IPMP, I found that ip_ndp_conflict()
would report:
node 00:00:00:00:00:00 is using our IP address 2007:56::f0a3:df91:b7dd:432d on bge2
Note in particular the all-zeroes hardware address. Some rummaging around
revealed the source of the problem: the packet in question that caused this
message was actually an unsolicited neighbor advertisement that got looped
back by ip_wput_ire_v6() -> ip_wput_ire_local_v6() and wasn't getting
properly detected in ndp_input_advert(). Nonetheless, ndp_input_advert()
called ip_ndp_conflict() which then called ip_ndp_find_solicitation(),
even though this was an advertisement. While the layouts of advertisements
and solicitations are identical, the option codes are different. Thus, when
we took this path:
ns = (nd_neighbor_solicit_t *)((char *)ip6h + IPV6_HDR_LEN);
nslen = mp->b_wptr - (uchar_t *)ns;
if ((nslen -= sizeof (*ns)) > 0) {
(1) --> opt = ndp_get_option((nd_opt_hdr_t *)(ns + 1), nslen,
ND_OPT_SOURCE_LINKADDR);
if (opt != NULL &&
opt->nd_opt_len * 8 - sizeof (*opt) >=
ill->ill_nd_lla_len) {
addr = (uchar_t *)(opt + 1);
alen = ill->ill_nd_lla_len;
}
}
/*
* We cheat a bit here for the sake of printing usable log
* messages in the rare case where the reply we got was unicast
* without a source linkaddr option, and the interface is in
* fastpath mode. (Sigh.)
*/
if (alen == 0 && ill->ill_type == IFT_ETHER &&
(2) --> MBLKHEAD(mp) >= sizeof (struct ether_header)) {
struct ether_header *pether;
pether = (struct ether_header *)((char *)ip6h -
sizeof (*pether));
addr = pether->ether_shost.ether_addr_octet;
alen = ETHERADDRL;
}
... the ndp_get_option() call at (1) returned NULL (since the option is
ND_OPT_TARGET_LINKADDR for an advertisement). We then continued on to
(2), and since this was an Ethernet interface and there was space before
the Ethernet header (for the fastpath header, which has not been added
since this is a loopback packet), we printed whatever garbage happened
to be there (all zeroes).
|