While working on the Clearview IPMP IPv6 code, I believe I've found a
serious IPMP-related bug in the existing IPv6 code. Specifically,
ipif_ndp_up() uses ill_move_in_progress to determine whether an IPv6
address is being moved between two interfaces, and sets the
NCE_F_UNSOLV_ADV flag to trigger ndp_add_v6() to send unsolicited
advertisements:
/* Permanent entries don't need NUD */
flags = NCE_F_PERMANENT | NCE_F_NONUD;
if (ill->ill_flags & ILLF_ROUTER)
flags |= NCE_F_ISROUTER;
if (ipif->ipif_flags & IPIF_ANYCAST)
flags |= NCE_F_ANYCAST;
if (ill->ill_net_type == IRE_IF_RESOLVER) {
hw_addr = ill->ill_nd_lla;
if (ill->ill_move_in_progress) {
/*
* Addresses are failing over to this ill.
* Don't wait for NUD to see this change.
* Publish our new link-layer address.
*/
--> flags |= NCE_F_UNSOL_ADV;
}
}
err = ndp_lookup_then_add_v6(ill,
hw_addr,
&ipif->ipif_v6lcl_addr,
&ipv6_all_ones,
&ipv6_all_zeros,
0,
flags,
ND_PROBE, /* Causes Duplicate Address Detection to run */
&nce);
However, looking at ndp_add_v6(), it seems the unsolicited advertisements
will never be sent, since `flags' includes NCE_F_PERMANENT and the
passed-in state (via the penultimate argument to ndp_lookup_then_add_v6()
is ND_PROBE:
--> if ((flags & NCE_F_PERMANENT) && state == ND_PROBE) {
mutex_enter(&nce->nce_lock);
mutex_exit(&ipst->ips_ndp6->ndp_g_lock);
nce->nce_pcnt = ND_MAX_UNICAST_SOLICIT;
mutex_exit(&nce->nce_lock);
dropped = nce_xmit(ill, ND_NEIGHBOR_SOLICIT, NULL, B_FALSE,
&ipv6_all_zeros, addr, NDP_PROBE);
if (dropped) {
mutex_enter(&nce->nce_lock);
nce->nce_pcnt++;
mutex_exit(&nce->nce_lock);
}
NDP_RESTART_TIMER(nce, ILL_PROBE_INTERVAL(ill));
mutex_enter(&ipst->ips_ndp6->ndp_g_lock);
err = EINPROGRESS;
--> } else if (flags & NCE_F_UNSOL_ADV) {
It seems like we should pass `ND_REACHABLE' instead of `ND_PROBE' when
NCE_F_UNSOL_ADV is set. Comments?
--
meem