From: Claudio Jeker Subject: Re: route cache mpath To: Alexander Bluhm Cc: tech@openbsd.org Date: Mon, 26 Feb 2024 11:56:08 +0100 On Mon, Feb 26, 2024 at 11:44:57AM +0100, Alexander Bluhm wrote: > Hi, > > We can combine route_cache() and rtalloc_mpath() in a new route_mpath() > function. Then the caller does not have to care about the uint32_t > *src pointer and just pass struct in_addr. All the conversions are > done inside the functions. ro->ro_rt is either valid or NULL. > > Also IP input should pass a struct route to IP forward. This is > the same logic that is done when passing a route from IP forward > to IP output. As a result the numbers of route cache lookups in > netstat -s should be correct now. > > Finally I removed some inconsistencies between IPv4 and IPv4 and > IP forward and IP output. > > ok? I would prefer if rtalloc_mpath() is fixed and just takes a struct route * as argument. This uint32_t * in rtalloc_mpath() and rtable_match() needs to be changed. Passing the source as a uint32_t * is bad in many regards. I like the changes to ip_forward and ip6_forward and the general trend to make code more consistent. > Or should I split the diff in smaller pieces? > > bluhm > > Index: net/route.c > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/net/route.c,v > diff -u -p -r1.433 route.c > --- net/route.c 22 Feb 2024 14:25:58 -0000 1.433 > +++ net/route.c 23 Feb 2024 23:58:57 -0000 > @@ -239,6 +239,28 @@ route_cache(struct route *ro, const stru > return (ESRCH); > } > > +/* > + * Check cache for route, else allocate a new one, potentially using multipath > + * to select the peer. Update cache and return valid route or NULL. > + */ > +struct rtentry * > +route_mpath(struct route *ro, const struct in_addr *dst, > + const struct in_addr *src, u_int rtableid) > +{ > + if (route_cache(ro, dst, src, rtableid)) { > + uint32_t *s = NULL; > + > + if (ro->ro_srcin.s_addr != INADDR_ANY) > + s = &ro->ro_srcin.s_addr; > + ro->ro_rt = rtalloc_mpath(&ro->ro_dstsa, s, ro->ro_tableid); > + if (!rtisvalid(ro->ro_rt)) { > + rtfree(ro->ro_rt); > + ro->ro_rt = NULL; > + } > + } > + return (ro->ro_rt); > +} > + > #ifdef INET6 > int > route6_cache(struct route *ro, const struct in6_addr *dst, > @@ -276,6 +298,24 @@ route6_cache(struct route *ro, const str > ro->ro_srcin6 = *src; > > return (ESRCH); > +} > + > +struct rtentry * > +route6_mpath(struct route *ro, const struct in6_addr *dst, > + const struct in6_addr *src, u_int rtableid) > +{ > + if (route6_cache(ro, dst, src, rtableid)) { > + uint32_t *s = NULL; > + > + if (IN6_IS_ADDR_UNSPECIFIED(&ro->ro_srcin6)) > + s = &ro->ro_srcin6.s6_addr32[0]; > + ro->ro_rt = rtalloc_mpath(&ro->ro_dstsa, s, ro->ro_tableid); > + if (!rtisvalid(ro->ro_rt)) { > + rtfree(ro->ro_rt); > + ro->ro_rt = NULL; > + } > + } > + return (ro->ro_rt); > } > #endif > > Index: net/route.h > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/net/route.h,v > diff -u -p -r1.207 route.h > --- net/route.h 22 Feb 2024 14:25:58 -0000 1.207 > +++ net/route.h 23 Feb 2024 23:58:57 -0000 > @@ -465,7 +465,11 @@ struct bfd_config; > void route_init(void); > int route_cache(struct route *, const struct in_addr *, > const struct in_addr *, u_int); > +struct rtentry *route_mpath(struct route *, const struct in_addr *, > + const struct in_addr *, u_int); > int route6_cache(struct route *, const struct in6_addr *, > + const struct in6_addr *, u_int); > +struct rtentry *route6_mpath(struct route *, const struct in6_addr *, > const struct in6_addr *, u_int); > void rtm_ifchg(struct ifnet *); > void rtm_ifannounce(struct ifnet *, int); > Index: netinet/in_pcb.c > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/in_pcb.c,v > diff -u -p -r1.294 in_pcb.c > --- netinet/in_pcb.c 22 Feb 2024 14:25:58 -0000 1.294 > +++ netinet/in_pcb.c 23 Feb 2024 23:58:57 -0000 > @@ -908,23 +908,15 @@ in_pcblookup_local_lock(struct inpcbtabl > struct rtentry * > in_pcbrtentry(struct inpcb *inp) > { > - struct route *ro; > - > #ifdef INET6 > if (ISSET(inp->inp_flags, INP_IPV6)) > return in6_pcbrtentry(inp); > #endif > > - ro = &inp->inp_route; > - > if (inp->inp_faddr.s_addr == INADDR_ANY) > return (NULL); > - if (route_cache(ro, &inp->inp_faddr, &inp->inp_laddr, > - inp->inp_rtableid)) { > - ro->ro_rt = rtalloc_mpath(&ro->ro_dstsa, > - &inp->inp_laddr.s_addr, ro->ro_tableid); > - } > - return (ro->ro_rt); > + return (route_mpath(&inp->inp_route, &inp->inp_faddr, &inp->inp_laddr, > + inp->inp_rtableid)); > } > > /* > @@ -938,7 +930,7 @@ in_pcbselsrc(struct in_addr *insrc, stru > struct inpcb *inp) > { > struct ip_moptions *mopts = inp->inp_moptions; > - struct route *ro = &inp->inp_route; > + struct rtentry *rt; > const struct in_addr *laddr = &inp->inp_laddr; > u_int rtableid = inp->inp_rtableid; > struct sockaddr *ip4_source = NULL; > @@ -983,17 +975,14 @@ in_pcbselsrc(struct in_addr *insrc, stru > * If route is known or can be allocated now, > * our src addr is taken from the i/f, else punt. > */ > - if (route_cache(ro, &sin->sin_addr, NULL, rtableid)) { > - /* No route yet, so try to acquire one */ > - ro->ro_rt = rtalloc_mpath(&ro->ro_dstsa, NULL, ro->ro_tableid); > - } > + rt = route_mpath(&inp->inp_route, &sin->sin_addr, NULL, rtableid); > > /* > * If we found a route, use the address > * corresponding to the outgoing interface. > */ > - if (ro->ro_rt != NULL) > - ia = ifatoia(ro->ro_rt->rt_ifa); > + if (rt != NULL) > + ia = ifatoia(rt->rt_ifa); > > /* > * Use preferred source address if : > @@ -1001,8 +990,7 @@ in_pcbselsrc(struct in_addr *insrc, stru > * - preferred source address is set > * - output interface is UP > */ > - if (ro->ro_rt && !(ro->ro_rt->rt_flags & RTF_LLINFO) && > - !(ro->ro_rt->rt_flags & RTF_HOST)) { > + if (rt && !(rt->rt_flags & RTF_LLINFO) && !(rt->rt_flags & RTF_HOST)) { > ip4_source = rtable_getsource(rtableid, AF_INET); > if (ip4_source != NULL) { > struct ifaddr *ifa; > Index: netinet/ip_input.c > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_input.c,v > diff -u -p -r1.390 ip_input.c > --- netinet/ip_input.c 22 Feb 2024 14:25:58 -0000 1.390 > +++ netinet/ip_input.c 23 Feb 2024 23:58:57 -0000 > @@ -138,7 +138,7 @@ extern struct niqueue arpinq; > > int ip_ours(struct mbuf **, int *, int, int); > int ip_dooptions(struct mbuf *, struct ifnet *); > -int in_ouraddr(struct mbuf *, struct ifnet *, struct rtentry **); > +int in_ouraddr(struct mbuf *, struct ifnet *, struct route *); > > int ip_fragcheck(struct mbuf **, int *); > struct mbuf * ip_reass(struct ipqent *, struct ipq *); > @@ -387,14 +387,18 @@ bad: > int > ip_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet *ifp) > { > - struct mbuf *m; > - struct rtentry *rt = NULL; > - struct ip *ip; > + struct route ro; > + struct mbuf *m; > + struct ip *ip; > int hlen; > - in_addr_t pfrdr = 0; > +#if NPF > 0 > + struct in_addr odst; > +#endif > + int pfrdr = 0; > > KASSERT(*offp == 0); > > + ro.ro_rt = NULL; > ipstat_inc(ips_total); > m = *mp = ipv4_check(ifp, *mp); > if (m == NULL) > @@ -412,7 +416,7 @@ ip_input_if(struct mbuf **mp, int *offp, > /* > * Packet filter > */ > - pfrdr = ip->ip_dst.s_addr; > + odst = ip->ip_dst; > if (pf_test(AF_INET, PF_IN, ifp, mp) != PF_PASS) > goto bad; > m = *mp; > @@ -420,7 +424,7 @@ ip_input_if(struct mbuf **mp, int *offp, > goto bad; > > ip = mtod(m, struct ip *); > - pfrdr = (pfrdr != ip->ip_dst.s_addr); > + pfrdr = odst.s_addr != ip->ip_dst.s_addr; > #endif > > hlen = ip->ip_hl << 2; > @@ -442,7 +446,7 @@ ip_input_if(struct mbuf **mp, int *offp, > goto out; > } > > - switch(in_ouraddr(m, ifp, &rt)) { > + switch(in_ouraddr(m, ifp, &ro)) { > case 2: > goto bad; > case 1: > @@ -544,14 +548,14 @@ ip_input_if(struct mbuf **mp, int *offp, > } > #endif /* IPSEC */ > > - ip_forward(m, ifp, rt, pfrdr); > + ip_forward(m, ifp, &ro, pfrdr); > *mp = NULL; > return IPPROTO_DONE; > bad: > nxt = IPPROTO_DONE; > m_freemp(mp); > out: > - rtfree(rt); > + rtfree(ro.ro_rt); > return nxt; > } > > @@ -748,11 +752,10 @@ ip_deliver(struct mbuf **mp, int *offp, > #undef IPSTAT_INC > > int > -in_ouraddr(struct mbuf *m, struct ifnet *ifp, struct rtentry **prt) > +in_ouraddr(struct mbuf *m, struct ifnet *ifp, struct route *ro) > { > struct rtentry *rt; > struct ip *ip; > - struct sockaddr_in sin; > int match = 0; > > #if NPF > 0 > @@ -769,13 +772,8 @@ in_ouraddr(struct mbuf *m, struct ifnet > > ip = mtod(m, struct ip *); > > - memset(&sin, 0, sizeof(sin)); > - sin.sin_len = sizeof(sin); > - sin.sin_family = AF_INET; > - sin.sin_addr = ip->ip_dst; > - rt = rtalloc_mpath(sintosa(&sin), &ip->ip_src.s_addr, > - m->m_pkthdr.ph_rtableid); > - if (rtisvalid(rt)) { > + rt = route_mpath(ro, &ip->ip_dst, &ip->ip_src, m->m_pkthdr.ph_rtableid); > + if (rt != NULL) { > if (ISSET(rt->rt_flags, RTF_LOCAL)) > match = 1; > > @@ -791,7 +789,6 @@ in_ouraddr(struct mbuf *m, struct ifnet > m->m_flags |= M_BCAST; > } > } > - *prt = rt; > > if (!match) { > struct ifaddr *ifa; > @@ -1470,11 +1467,12 @@ const u_char inetctlerrmap[PRC_NCMDS] = > * via a source route. > */ > void > -ip_forward(struct mbuf *m, struct ifnet *ifp, struct rtentry *rt, int srcrt) > +ip_forward(struct mbuf *m, struct ifnet *ifp, struct route *ro, int srcrt) > { > - struct mbuf mfake, *mcopy = NULL; > + struct mbuf mfake, *mcopy; > struct ip *ip = mtod(m, struct ip *); > - struct route ro; > + struct route iproute; > + struct rtentry *rt; > int error = 0, type = 0, code = 0, destmtu = 0, fake = 0, len; > u_int32_t dest; > > @@ -1482,26 +1480,23 @@ ip_forward(struct mbuf *m, struct ifnet > if (m->m_flags & (M_BCAST|M_MCAST) || in_canforward(ip->ip_dst) == 0) { > ipstat_inc(ips_cantforward); > m_freem(m); > - goto freecopy; > + goto done; > } > if (ip->ip_ttl <= IPTTLDEC) { > icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, dest, 0); > - goto freecopy; > + goto done; > } > > - ro.ro_rt = NULL; > - route_cache(&ro, &ip->ip_dst, &ip->ip_src, m->m_pkthdr.ph_rtableid); > - if (!rtisvalid(rt)) { > - rtfree(rt); > - rt = rtalloc_mpath(&ro.ro_dstsa, &ip->ip_src.s_addr, > - m->m_pkthdr.ph_rtableid); > - if (rt == NULL) { > - ipstat_inc(ips_noroute); > - icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0); > - return; > - } > + if (ro == NULL) { > + ro = &iproute; > + ro->ro_rt = NULL; > + } > + rt = route_mpath(ro, &ip->ip_dst, &ip->ip_src, m->m_pkthdr.ph_rtableid); > + if (rt == NULL) { > + ipstat_inc(ips_noroute); > + icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0); > + goto done; > } > - ro.ro_rt = rt; > > /* > * Save at most 68 bytes of the packet in case > @@ -1552,10 +1547,10 @@ ip_forward(struct mbuf *m, struct ifnet > } > } > > - error = ip_output(m, NULL, &ro, > + error = ip_output(m, NULL, ro, > (IP_FORWARDING | (ip_directedbcast ? IP_ALLOWBROADCAST : 0)), > NULL, NULL, 0); > - rt = ro.ro_rt; > + rt = ro->ro_rt; > if (error) > ipstat_inc(ips_cantforward); > else { > @@ -1563,10 +1558,10 @@ ip_forward(struct mbuf *m, struct ifnet > if (type) > ipstat_inc(ips_redirectsent); > else > - goto freecopy; > + goto done; > } > if (!fake) > - goto freecopy; > + goto done; > > switch (error) { > case 0: /* forwarded, but need redirect */ > @@ -1590,7 +1585,7 @@ ip_forward(struct mbuf *m, struct ifnet > } > ipstat_inc(ips_cantfrag); > if (destmtu == 0) > - goto freecopy; > + goto done; > break; > > case EACCES: > @@ -1598,7 +1593,7 @@ ip_forward(struct mbuf *m, struct ifnet > * pf(4) blocked the packet. There is no need to send an ICMP > * packet back since pf(4) takes care of it. > */ > - goto freecopy; > + goto done; > > case ENOBUFS: > /* > @@ -1607,7 +1602,7 @@ ip_forward(struct mbuf *m, struct ifnet > * source quench could be a big problem under DoS attacks, > * or the underlying interface is rate-limited. > */ > - goto freecopy; > + goto done; > > case ENETUNREACH: /* shouldn't happen, checked above */ > case EHOSTUNREACH: > @@ -1622,10 +1617,11 @@ ip_forward(struct mbuf *m, struct ifnet > if (mcopy) > icmp_error(mcopy, type, code, dest, destmtu); > > -freecopy: > +done: > + if (ro == &iproute && ro->ro_rt) > + rtfree(ro->ro_rt); > if (fake) > m_tag_delete_chain(&mfake); > - rtfree(rt); > } > > int > Index: netinet/ip_var.h > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_var.h,v > diff -u -p -r1.113 ip_var.h > --- netinet/ip_var.h 13 Feb 2024 12:22:09 -0000 1.113 > +++ netinet/ip_var.h 23 Feb 2024 18:59:54 -0000 > @@ -255,7 +255,7 @@ void ip_savecontrol(struct inpcb *, str > struct mbuf *); > int ip_input_if(struct mbuf **, int *, int, int, struct ifnet *); > int ip_deliver(struct mbuf **, int *, int, int); > -void ip_forward(struct mbuf *, struct ifnet *, struct rtentry *, int); > +void ip_forward(struct mbuf *, struct ifnet *, struct route *, int); > int rip_ctloutput(int, struct socket *, int, int, struct mbuf *); > void rip_init(void); > int rip_input(struct mbuf **, int *, int, int); > Index: netinet6/in6_pcb.c > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/in6_pcb.c,v > diff -u -p -r1.139 in6_pcb.c > --- netinet6/in6_pcb.c 22 Feb 2024 14:25:58 -0000 1.139 > +++ netinet6/in6_pcb.c 23 Feb 2024 23:58:57 -0000 > @@ -561,16 +561,10 @@ in6_pcbnotify(struct inpcbtable *table, > struct rtentry * > in6_pcbrtentry(struct inpcb *inp) > { > - struct route *ro = &inp->inp_route; > - > if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) > return (NULL); > - if (route6_cache(ro, &inp->inp_faddr6, &inp->inp_laddr6, > - inp->inp_rtableid)) { > - ro->ro_rt = rtalloc_mpath(&ro->ro_dstsa, > - &inp->inp_laddr6.s6_addr32[0], ro->ro_tableid); > - } > - return (ro->ro_rt); > + return (route6_mpath(&inp->inp_route, &inp->inp_faddr6, > + &inp->inp_laddr6, inp->inp_rtableid)); > } > > struct inpcb * > Index: netinet6/in6_src.c > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/in6_src.c,v > diff -u -p -r1.95 in6_src.c > --- netinet6/in6_src.c 22 Feb 2024 14:25:58 -0000 1.95 > +++ netinet6/in6_src.c 23 Feb 2024 23:58:57 -0000 > @@ -95,7 +95,7 @@ in6_pcbselsrc(const struct in6_addr **in > struct inpcb *inp, struct ip6_pktopts *opts) > { > struct ip6_moptions *mopts = inp->inp_moptions6; > - struct route *ro = &inp->inp_route; > + struct rtentry *rt; > const struct in6_addr *laddr = &inp->inp_laddr6; > u_int rtableid = inp->inp_rtableid; > struct ifnet *ifp = NULL; > @@ -118,7 +118,8 @@ in6_pcbselsrc(const struct in6_addr **in > struct sockaddr_in6 sa6; > > /* get the outgoing interface */ > - error = in6_selectif(dst, opts, mopts, ro, &ifp, rtableid); > + error = in6_selectif(dst, opts, mopts, &inp->inp_route, &ifp, > + rtableid); > if (error) > return (error); > > @@ -179,9 +180,7 @@ in6_pcbselsrc(const struct in6_addr **in > * If route is known or can be allocated now, > * our src addr is taken from the i/f, else punt. > */ > - if (route6_cache(ro, dst, NULL, rtableid)) { > - ro->ro_rt = rtalloc_mpath(&ro->ro_dstsa, NULL, ro->ro_tableid); > - } > + rt = route6_mpath(&inp->inp_route, dst, NULL, rtableid); > > /* > * in_pcbconnect() checks out IFF_LOOPBACK to skip using > @@ -190,14 +189,14 @@ in6_pcbselsrc(const struct in6_addr **in > * so doesn't check out IFF_LOOPBACK. > */ > > - if (ro->ro_rt) { > - ifp = if_get(ro->ro_rt->rt_ifidx); > + if (rt != NULL) { > + ifp = if_get(rt->rt_ifidx); > if (ifp != NULL) { > ia6 = in6_ifawithscope(ifp, dst, rtableid); > if_put(ifp); > } > if (ia6 == NULL) /* xxx scope error ?*/ > - ia6 = ifatoia6(ro->ro_rt->rt_ifa); > + ia6 = ifatoia6(rt->rt_ifa); > } > > /* > @@ -206,8 +205,7 @@ in6_pcbselsrc(const struct in6_addr **in > * - preferred source address is set > * - output interface is UP > */ > - if (ro->ro_rt && !(ro->ro_rt->rt_flags & RTF_LLINFO) && > - !(ro->ro_rt->rt_flags & RTF_HOST)) { > + if (rt && !(rt->rt_flags & RTF_LLINFO) && !(rt->rt_flags & RTF_HOST)) { > ip6_source = rtable_getsource(rtableid, AF_INET6); > if (ip6_source != NULL) { > struct ifaddr *ifa; > @@ -304,11 +302,9 @@ in6_selectroute(const struct in6_addr *d > * a new one. > */ > if (ro) { > - if (route6_cache(ro, dst, NULL, rtableid)) { > - /* No route yet, so try to acquire one */ > - ro->ro_rt = rtalloc_mpath(&ro->ro_dstsa, NULL, > - ro->ro_tableid); > - } > + struct rtentry *rt; > + > + rt = route6_mpath(ro, dst, NULL, rtableid); > > /* > * Check if the outgoing interface conflicts with > @@ -319,15 +315,13 @@ in6_selectroute(const struct in6_addr *d > */ > if (opts && opts->ip6po_pktinfo && > opts->ip6po_pktinfo->ipi6_ifindex) { > - if (ro->ro_rt != NULL && > - !ISSET(ro->ro_rt->rt_flags, RTF_LOCAL) && > - ro->ro_rt->rt_ifidx != > - opts->ip6po_pktinfo->ipi6_ifindex) { > + if (rt != NULL && !ISSET(rt->rt_flags, RTF_LOCAL) && > + rt->rt_ifidx != opts->ip6po_pktinfo->ipi6_ifindex) { > return (NULL); > } > } > > - return (ro->ro_rt); > + return (rt); > } > > return (NULL); > @@ -338,7 +332,7 @@ in6_selectif(const struct in6_addr *dst, > struct ip6_moptions *mopts, struct route *ro, struct ifnet **retifp, > u_int rtableid) > { > - struct rtentry *rt = NULL; > + struct rtentry *rt; > struct in6_pktinfo *pi = NULL; > > /* If the caller specify the outgoing interface explicitly, use it. */ > Index: netinet6/ip6_forward.c > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/ip6_forward.c,v > diff -u -p -r1.115 ip6_forward.c > --- netinet6/ip6_forward.c 22 Feb 2024 14:25:58 -0000 1.115 > +++ netinet6/ip6_forward.c 23 Feb 2024 23:58:57 -0000 > @@ -82,14 +82,15 @@ > */ > > void > -ip6_forward(struct mbuf *m, struct rtentry *rt, int srcrt) > +ip6_forward(struct mbuf *m, struct route *ro, int srcrt) > { > struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); > + struct route iproute; > + struct rtentry *rt; > struct sockaddr *dst; > - struct route ro; > struct ifnet *ifp = NULL; > int error = 0, type = 0, code = 0, destmtu = 0; > - struct mbuf *mcopy = NULL; > + struct mbuf *mcopy; > #ifdef IPSEC > struct tdb *tdb = NULL; > #endif /* IPSEC */ > @@ -121,13 +122,13 @@ ip6_forward(struct mbuf *m, struct rtent > m->m_pkthdr.ph_ifidx); > } > m_freem(m); > - goto out; > + goto done; > } > > if (ip6->ip6_hlim <= IPV6_HLIMDEC) { > icmp6_error(m, ICMP6_TIME_EXCEEDED, > ICMP6_TIME_EXCEED_TRANSIT, 0); > - goto out; > + goto done; > } > ip6->ip6_hlim -= IPV6_HLIMDEC; > > @@ -165,25 +166,22 @@ reroute: > } > #endif /* IPSEC */ > > - ro.ro_rt = NULL; > - route6_cache(&ro, &ip6->ip6_dst, &ip6->ip6_src, > + if (ro == NULL) { > + ro = &iproute; > + ro->ro_rt = NULL; > + } > + rt = route6_mpath(ro, &ip6->ip6_dst, &ip6->ip6_src, > m->m_pkthdr.ph_rtableid); > - dst = &ro.ro_dstsa; > - if (!rtisvalid(rt)) { > - rtfree(rt); > - rt = rtalloc_mpath(dst, &ip6->ip6_src.s6_addr32[0], > - m->m_pkthdr.ph_rtableid); > - if (rt == NULL) { > - ip6stat_inc(ip6s_noroute); > - if (mcopy) { > - icmp6_error(mcopy, ICMP6_DST_UNREACH, > - ICMP6_DST_UNREACH_NOROUTE, 0); > - } > - m_freem(m); > - goto out; > + if (rt == NULL) { > + ip6stat_inc(ip6s_noroute); > + if (mcopy) { > + icmp6_error(mcopy, ICMP6_DST_UNREACH, > + ICMP6_DST_UNREACH_NOROUTE, 0); > } > + m_freem(m); > + goto done; > } > - ro.ro_rt = rt; > + dst = &ro->ro_dstsa; > > /* > * Scope check: if a packet can't be delivered to its destination > @@ -215,7 +213,7 @@ reroute: > icmp6_error(mcopy, ICMP6_DST_UNREACH, > ICMP6_DST_UNREACH_BEYONDSCOPE, 0); > m_freem(m); > - goto out; > + goto done; > } > > #ifdef IPSEC > @@ -225,8 +223,8 @@ reroute: > */ > if (tdb != NULL) { > /* Callee frees mbuf */ > - error = ip6_output_ipsec_send(tdb, m, &ro, 0, 1); > - rt = ro.ro_rt; > + error = ip6_output_ipsec_send(tdb, m, ro, 0, 1); > + rt = ro->ro_rt; > if (error) > goto senderr; > goto freecopy; > @@ -254,7 +252,7 @@ reroute: > ip6_sendredirects && > (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0) { > if ((ifp->if_flags & IFF_POINTOPOINT) && > - nd6_is_addr_neighbor(&ro.ro_dstsin6, ifp)) { > + nd6_is_addr_neighbor(&ro->ro_dstsin6, ifp)) { > /* > * If the incoming interface is equal to the outgoing > * one, the link attached to the interface is > @@ -274,7 +272,7 @@ reroute: > icmp6_error(mcopy, ICMP6_DST_UNREACH, > ICMP6_DST_UNREACH_ADDR, 0); > m_freem(m); > - goto out; > + goto done; > } > type = ND_REDIRECT; > } > @@ -308,8 +306,7 @@ reroute: > /* tag as generated to skip over pf_test on rerun */ > m->m_pkthdr.pf.flags |= PF_TAG_GENERATED; > srcrt = 1; > - rtfree(rt); > - rt = NULL; > + ro = NULL; > if_put(ifp); > ifp = NULL; > goto reroute; > @@ -324,21 +321,21 @@ reroute: > if (error || m == NULL) > goto senderr; > > - if (mcopy != NULL) > + if (mcopy) > icmp6_error(mcopy, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu); > m_freem(m); > - goto out; > + goto done; > > senderr: > if (mcopy == NULL) > - goto out; > + goto done; > > switch (error) { > case 0: > if (type == ND_REDIRECT) { > icmp6_redirect_output(mcopy, rt); > ip6stat_inc(ip6s_redirectsent); > - goto out; > + goto done; > } > goto freecopy; > > @@ -383,12 +380,13 @@ senderr: > break; > } > icmp6_error(mcopy, type, code, destmtu); > - goto out; > + goto done; > > freecopy: > m_freem(mcopy); > -out: > - rtfree(rt); > +done: > + if (ro == &iproute && ro->ro_rt) > + rtfree(ro->ro_rt); > if_put(ifp); > #ifdef IPSEC > tdb_unref(tdb); > Index: netinet6/ip6_input.c > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/ip6_input.c,v > diff -u -p -r1.258 ip6_input.c > --- netinet6/ip6_input.c 22 Feb 2024 14:25:58 -0000 1.258 > +++ netinet6/ip6_input.c 23 Feb 2024 23:58:57 -0000 > @@ -357,21 +357,21 @@ bad: > int > ip6_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet *ifp) > { > + struct route ro; > struct mbuf *m; > struct ip6_hdr *ip6; > - struct sockaddr_in6 sin6; > - struct rtentry *rt = NULL; > + struct rtentry *rt; > int ours = 0; > u_int16_t src_scope, dst_scope; > #if NPF > 0 > struct in6_addr odst; > #endif > - int srcrt = 0; > + int pfrdr = 0; > > KASSERT(*offp == 0); > > + ro.ro_rt = NULL; > ip6stat_inc(ip6s_total); > - > m = *mp = ipv6_check(ifp, *mp); > if (m == NULL) > goto bad; > @@ -413,7 +413,7 @@ ip6_input_if(struct mbuf **mp, int *offp > goto bad; > > ip6 = mtod(m, struct ip6_hdr *); > - srcrt = !IN6_ARE_ADDR_EQUAL(&odst, &ip6->ip6_dst); > + pfrdr = !IN6_ARE_ADDR_EQUAL(&odst, &ip6->ip6_dst); > #endif > > /* > @@ -517,18 +517,14 @@ ip6_input_if(struct mbuf **mp, int *offp > /* > * Unicast check > */ > - memset(&sin6, 0, sizeof(struct sockaddr_in6)); > - sin6.sin6_len = sizeof(struct sockaddr_in6); > - sin6.sin6_family = AF_INET6; > - sin6.sin6_addr = ip6->ip6_dst; > - rt = rtalloc_mpath(sin6tosa(&sin6), &ip6->ip6_src.s6_addr32[0], > + rt = route6_mpath(&ro, &ip6->ip6_dst, &ip6->ip6_src, > m->m_pkthdr.ph_rtableid); > > /* > * Accept the packet if the route to the destination is marked > * as local. > */ > - if (rtisvalid(rt) && ISSET(rt->rt_flags, RTF_LOCAL)) { > + if (rt != NULL && ISSET(rt->rt_flags, RTF_LOCAL)) { > struct in6_ifaddr *ia6 = ifatoia6(rt->rt_ifa); > > if (ip6_forwarding == 0 && rt->rt_ifidx != ifp->if_index && > @@ -618,14 +614,14 @@ ip6_input_if(struct mbuf **mp, int *offp > } > #endif /* IPSEC */ > > - ip6_forward(m, rt, srcrt); > + ip6_forward(m, &ro, pfrdr); > *mp = NULL; > return IPPROTO_DONE; > bad: > nxt = IPPROTO_DONE; > m_freemp(mp); > out: > - rtfree(rt); > + rtfree(ro.ro_rt); > return nxt; > } > > Index: netinet6/ip6_output.c > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/ip6_output.c,v > diff -u -p -r1.287 ip6_output.c > --- netinet6/ip6_output.c 22 Feb 2024 14:25:58 -0000 1.287 > +++ netinet6/ip6_output.c 23 Feb 2024 23:58:57 -0000 > @@ -391,7 +391,7 @@ reroute: > /* initialize cached route */ > if (ro == NULL) { > ro = &iproute; > - bzero((caddr_t)ro, sizeof(*ro)); > + ro->ro_rt = NULL; > } > ro_pmtu = ro; > if (opt && opt->ip6po_rthdr) > @@ -748,7 +748,15 @@ reroute: > (error = if_output_ml(ifp, &ml, sin6tosa(dst), ro->ro_rt))) > goto done; > ip6stat_inc(ip6s_fragmented); > + goto done; > > +freehdrs: > + m_freem(exthdrs.ip6e_hbh); /* m_freem will check if mbuf is 0 */ > + m_freem(exthdrs.ip6e_dest1); > + m_freem(exthdrs.ip6e_rthdr); > + m_freem(exthdrs.ip6e_dest2); > +bad: > + m_freem(m); > done: > if (ro == &iproute && ro->ro_rt) { > rtfree(ro->ro_rt); > @@ -760,16 +768,6 @@ done: > tdb_unref(tdb); > #endif /* IPSEC */ > return (error); > - > -freehdrs: > - m_freem(exthdrs.ip6e_hbh); /* m_freem will check if mbuf is 0 */ > - m_freem(exthdrs.ip6e_dest1); > - m_freem(exthdrs.ip6e_rthdr); > - m_freem(exthdrs.ip6e_dest2); > - /* FALLTHROUGH */ > -bad: > - m_freem(m); > - goto done; > } > > int > Index: netinet6/ip6_var.h > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/ip6_var.h,v > diff -u -p -r1.114 ip6_var.h > --- netinet6/ip6_var.h 14 Feb 2024 13:18:21 -0000 1.114 > +++ netinet6/ip6_var.h 23 Feb 2024 23:21:02 -0000 > @@ -320,7 +320,7 @@ int ip6_process_hopopts(struct mbuf **, > void ip6_savecontrol(struct inpcb *, struct mbuf *, struct mbuf **); > int ip6_sysctl(int *, u_int, void *, size_t *, void *, size_t); > > -void ip6_forward(struct mbuf *, struct rtentry *, int); > +void ip6_forward(struct mbuf *, struct route *, int); > > void ip6_mloopback(struct ifnet *, struct mbuf *, struct sockaddr_in6 *); > int ip6_output(struct mbuf *, struct ip6_pktopts *, struct route *, int, > -- :wq Claudio