Fix default route selection The primary issue was that in revision 1.79 a check was added in the nd6_defrouter_select() search loop to ignore the entry if RA processing is enabled on its interface. In practice this results in all entries being ignored. This fix reverses the condition, so that an entry is ignored when RA processing is NOT enabled on its interface. Further, the entry is only ignored for being selected as the default router. The currently installed router must be identified regardless of the (current) status of its interface, so that we can delete the route before installing a new one. I also added error logging when adding or deleting a route fails. This should help the administrator (or kernel developer) in noticing possible problems. Finally, if deleting a route fails, the corresponding default route entry no longer has its "installed" flag cleared, so that deletion will be retried. At a minimum, this will cause repeated messages about the failed deletion as opposed to only getting repeated messages about the installation of a new default route failing. diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c index 712b4740c4d3..3e939be9855d 100644 --- a/sys/netinet6/nd6_rtr.c +++ b/sys/netinet6/nd6_rtr.c @@ -472,6 +472,10 @@ defrouter_addreq(struct nd_defrouter *new) } if (error == 0) new->installed = 1; + else + log(LOG_ERR, "defrouter_addreq: " + "error %d adding default router %s on %s\n", + error, ip6_sprintf(&new->rtaddr), new->ifp->if_xname); splx(s); return; } @@ -559,6 +563,7 @@ defrouter_delreq(struct nd_defrouter *dr) struct sockaddr sa; } def, mask, gw; struct rtentry *oldrt = NULL; + int error; #ifdef DIAGNOSTIC if (dr == NULL) @@ -577,7 +582,7 @@ defrouter_delreq(struct nd_defrouter *dr) gw.sin6.sin6_scope_id = 0; /* XXX */ #endif - rtrequest(RTM_DELETE, &def.sa, &gw.sa, &mask.sa, RTF_GATEWAY, &oldrt); + error = rtrequest(RTM_DELETE, &def.sa, &gw.sa, &mask.sa, RTF_GATEWAY, &oldrt); if (oldrt) { nd6_rtmsg(RTM_DELETE, oldrt); if (oldrt->rt_refcnt <= 0) { @@ -591,7 +596,12 @@ defrouter_delreq(struct nd_defrouter *dr) } } - dr->installed = 0; + if (error == 0) + dr->installed = 0; + else + log(LOG_ERR, "defrouter_delreq: " + "error %d deleting default router %s on %s\n", + error, ip6_sprintf(&dr->rtaddr), dr->ifp->if_xname); } /* @@ -672,8 +682,16 @@ defrouter_select(void) */ for (dr = TAILQ_FIRST(&nd_defrouter); dr; dr = TAILQ_NEXT(dr, dr_entry)) { + if (dr->installed && !installed_dr) + installed_dr = dr; + else if (dr->installed && installed_dr) { + /* this should not happen. warn for diagnosis. */ + log(LOG_ERR, "defrouter_select: more than one router" + " is installed\n"); + } + ndi = ND_IFINFO(dr->ifp); - if (nd6_accepts_rtadv(ndi)) + if (!nd6_accepts_rtadv(ndi)) continue; if (selected_dr == NULL && @@ -682,14 +700,6 @@ defrouter_select(void) ND6_IS_LLINFO_PROBREACH(ln)) { selected_dr = dr; } - - if (dr->installed && !installed_dr) - installed_dr = dr; - else if (dr->installed && installed_dr) { - /* this should not happen. warn for diagnosis. */ - log(LOG_ERR, "defrouter_select: more than one router" - " is installed\n"); - } } /* * If none of the default routers was found to be reachable,