/* * Look up the route that matches the given "dst" address. * * Route lookup can have the side-effect of creating and returning * a cloned route instead when "dst" matches a cloning route and the * RTF_CLONING and RTF_PRCLONING flags are not being ignored. * * Any route returned has its reference count incremented. */ struct rtentry * _rtlookup(struct sockaddr *dst, boolean_t generate_report, u_long ignore) { struct radix_node_head *rnh = rt_tables[dst->sa_family]; struct rtentry *rt; if (rnh == NULL) goto unreach; /* * Look up route in the radix tree. */ rt = (struct rtentry *) rnh->rnh_matchaddr((char *)dst, rnh); if (rt == NULL) goto unreach; /* * Handle cloning routes. */ if ((rt->rt_flags & ~ignore & (RTF_CLONING | RTF_PRCLONING)) != 0) { struct rtentry *clonedroute; int error; clonedroute = rt; /* copy in/copy out parameter */ error = rtrequest(RTM_RESOLVE, dst, NULL, NULL, 0, &clonedroute); /* clone the route */ if (error != 0) { /* cloning failed */ if (generate_report) rt_dstmsg(RTM_MISS, dst, error); rt->rt_refcnt++; return (rt); /* return the uncloned route */ } if (generate_report) { if (clonedroute->rt_flags & RTF_XRESOLVE) rt_dstmsg(RTM_RESOLVE, dst, 0); else rt_rtmsg(RTM_ADD, clonedroute, clonedroute->rt_ifp, 0); } return (clonedroute); /* return cloned route */ } /* * Increment the reference count of the matched route and return. */ rt->rt_refcnt++; return (rt); unreach: rtstat.rts_unreach++; if (generate_report) rt_dstmsg(RTM_MISS, dst, 0); return (NULL); }