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

Reply via email to