Index: if_ethersubr.c =================================================================== RCS file: /cvs/src/sys/net/if_ethersubr.c,v retrieving revision 1.266 diff -u -p -r1.266 if_ethersubr.c --- if_ethersubr.c 22 Jul 2020 02:16:01 -0000 1.266 +++ if_ethersubr.c 27 Jul 2020 04:28:28 -0000 @@ -203,6 +203,7 @@ ether_resolve(struct ifnet *ifp, struct struct rtentry *rt, struct ether_header *eh) { struct arpcom *ac = (struct arpcom *)ifp; + struct rtentry *crt = NULL; sa_family_t af = dst->sa_family; int error = 0; @@ -220,11 +221,18 @@ ether_resolve(struct ifnet *ifp, struct } #endif + if (rt != NULL && ISSET(rt->rt_flags, RTF_CLONING)) { + error = rt_clone(&crt, rt, dst, ifp->if_rdomain); + if (error != 0) + senderr(error); + rt = crt; + } + switch (af) { case AF_INET: error = arpresolve(ifp, rt, m, dst, eh->ether_dhost); if (error) - return (error); + goto error; eh->ether_type = htons(ETHERTYPE_IP); /* If broadcasting on a simplex interface, loopback a copy */ @@ -243,7 +251,7 @@ ether_resolve(struct ifnet *ifp, struct case AF_INET6: error = nd6_resolve(ifp, rt, m, dst, eh->ether_dhost); if (error) - return (error); + goto error; eh->ether_type = htons(ETHERTYPE_IPV6); break; #endif @@ -269,13 +277,13 @@ ether_resolve(struct ifnet *ifp, struct case AF_INET6: error = nd6_resolve(ifp, rt, m, dst, eh->ether_dhost); if (error) - return (error); + goto error; break; #endif case AF_INET: error = arpresolve(ifp, rt, m, dst, eh->ether_dhost); if (error) - return (error); + goto error; break; default: senderr(EHOSTUNREACH); @@ -290,7 +298,7 @@ ether_resolve(struct ifnet *ifp, struct case pseudo_AF_HDRCMPLT: /* take the whole header from the sa */ memcpy(eh, dst->sa_data, sizeof(*eh)); - return (0); + goto done; case AF_UNSPEC: /* take the dst and type from the sa, but get src below */ @@ -304,10 +312,14 @@ ether_resolve(struct ifnet *ifp, struct memcpy(eh->ether_shost, ac->ac_enaddr, sizeof(eh->ether_shost)); +done: + rtfree(crt); return (0); bad: m_freem(m); +error: + rtfree(crt); return (error); } Index: route.c =================================================================== RCS file: /cvs/src/sys/net/route.c,v retrieving revision 1.394 diff -u -p -r1.394 route.c --- route.c 24 Jun 2020 22:03:43 -0000 1.394 +++ route.c 27 Jul 2020 04:28:28 -0000 @@ -159,7 +159,6 @@ int rtflushclone1(struct rtentry *, void int rtflushclone(struct rtentry *, unsigned int); int rt_ifa_purge_walker(struct rtentry *, void *, unsigned int); struct rtentry *rt_match(struct sockaddr *, uint32_t *, int, unsigned int); -int rt_clone(struct rtentry **, struct sockaddr *, unsigned int); struct sockaddr *rt_plentosa(sa_family_t, int, struct sockaddr_in6 *); static int rt_copysa(struct sockaddr *, struct sockaddr *, struct sockaddr **); @@ -238,22 +237,32 @@ rt_match(struct sockaddr *dst, uint32_t return (NULL); } - if (ISSET(rt->rt_flags, RTF_CLONING) && ISSET(flags, RT_RESOLVE)) - rt_clone(&rt, dst, tableid); - rt->rt_use++; return (rt); } int -rt_clone(struct rtentry **rtp, struct sockaddr *dst, unsigned int rtableid) +rt_clone(struct rtentry **nrtp, struct rtentry *rt, struct sockaddr *dst, + unsigned int rtableid) { struct rt_addrinfo info; - struct rtentry *rt = *rtp; int error = 0; + struct sockaddr_rtlabel sa_rl; + struct sockaddr_dl sa_dl = { sizeof(sa_dl), AF_LINK }; + struct rtentry *nrt = rt; + + if (!ISSET(rt->rt_flags, RTF_CLONING)) + return (EINVAL); memset(&info, 0, sizeof(info)); + info.rti_ifa = rt->rt_ifa; + info.rti_flags = rt->rt_flags; + CLR(info.rti_flags, RTF_CLONING|RTF_CONNECTED|RTF_STATIC); + SET(info.rti_flags, RTF_CLONED|RTF_HOST); info.rti_info[RTAX_DST] = dst; + info.rti_info[RTAX_GATEWAY] = sdltosa(&sa_dl); + info.rti_info[RTAX_NETMASK] = NULL; + info.rti_info[RTAX_LABEL] = rtlabel_id2sa(rt->rt_labelid, &sa_rl); /* * The priority of cloned route should be different @@ -263,18 +272,19 @@ rt_clone(struct rtentry **rtp, struct so * cloned routes instead of the cloning one. */ KERNEL_LOCK(); - error = rtrequest(RTM_RESOLVE, &info, rt->rt_priority - 1, &rt, + error = rtrequest(RTM_RESOLVE, &info, rt->rt_priority - 1, &nrt, rtableid); KERNEL_UNLOCK(); if (error) { rtm_miss(RTM_MISS, &info, 0, RTP_NONE, 0, error, rtableid); - } else { - /* Inform listeners of the new route */ - rtm_send(rt, RTM_ADD, 0, rtableid); - rtfree(*rtp); - *rtp = rt; + return (error); } - return (error); + + /* Inform listeners of the new route */ + rtm_send(nrt, RTM_ADD, 0, rtableid); + *nrtp = nrt; + + return (0); } /* @@ -415,17 +425,18 @@ rt_setgwroute(struct rtentry *rt, u_int while (prt != NULL && prt->rt_ifidx != rt->rt_ifidx) prt = rtable_iterate(prt); - /* We found nothing or a non-cloning MPATH route. */ - if (prt == NULL || !ISSET(prt->rt_flags, RTF_CLONING)) { - rtfree(prt); + /* We found nothing. */ + if (prt == NULL) return (EHOSTUNREACH); - } - error = rt_clone(&prt, rt->rt_gateway, rdomain); - if (error) { - rtfree(prt); + nhrt = prt; + } + + if (ISSET(nhrt->rt_flags, RTF_CLONING)) { + error = rt_clone(&prt, nhrt, rt->rt_gateway, rdomain); + rtfree(nhrt); + if (error) return (error); - } nhrt = prt; } @@ -433,7 +444,7 @@ rt_setgwroute(struct rtentry *rt, u_int * Next hop must be reachable, this also prevents rtentry * loops for example when rt->rt_gwroute points to rt. */ - if (ISSET(nhrt->rt_flags, RTF_CLONING|RTF_GATEWAY)) { + if (ISSET(nhrt->rt_flags, RTF_GATEWAY)) { rtfree(nhrt); return (ENETUNREACH); } @@ -826,8 +837,7 @@ rtrequest(int req, struct rt_addrinfo *i struct rtentry *rt, *crt; struct ifaddr *ifa; struct sockaddr *ndst; - struct sockaddr_rtlabel *sa_rl, sa_rl2; - struct sockaddr_dl sa_dl = { sizeof(sa_dl), AF_LINK }; + struct sockaddr_rtlabel *sa_rl; int error; NET_ASSERT_LOCKED(); @@ -841,19 +851,6 @@ rtrequest(int req, struct rt_addrinfo *i return (EINVAL); case RTM_RESOLVE: - if (ret_nrt == NULL || (rt = *ret_nrt) == NULL) - return (EINVAL); - if ((rt->rt_flags & RTF_CLONING) == 0) - return (EINVAL); - KASSERT(rt->rt_ifa->ifa_ifp != NULL); - info->rti_ifa = rt->rt_ifa; - info->rti_flags = rt->rt_flags | (RTF_CLONED|RTF_HOST); - info->rti_flags &= ~(RTF_CLONING|RTF_CONNECTED|RTF_STATIC); - info->rti_info[RTAX_GATEWAY] = sdltosa(&sa_dl); - info->rti_info[RTAX_LABEL] = - rtlabel_id2sa(rt->rt_labelid, &sa_rl2); - /* FALLTHROUGH */ - case RTM_ADD: if (info->rti_ifa == NULL) return (EINVAL); Index: route.h =================================================================== RCS file: /cvs/src/sys/net/route.h,v retrieving revision 1.181 diff -u -p -r1.181 route.h --- route.h 10 Mar 2020 21:35:41 -0000 1.181 +++ route.h 27 Jul 2020 04:28:28 -0000 @@ -441,6 +441,8 @@ void rtm_miss(int, struct rt_addrinfo * void rtm_proposal(struct ifnet *, struct rt_addrinfo *, int, uint8_t); int rt_setgate(struct rtentry *, struct sockaddr *, u_int); struct rtentry *rt_getll(struct rtentry *); +int rt_clone(struct rtentry **, struct rtentry *, struct sockaddr *, + unsigned int); int rt_timer_add(struct rtentry *, void(*)(struct rtentry *, struct rttimer *),