Download raw body.
route cache mpath
On Mon, Feb 26, 2024 at 03:51:37PM +0100, Alexander Bluhm wrote:
> On Mon, Feb 26, 2024 at 11:56:08AM +0100, Claudio Jeker wrote:
> > 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.
>
> Do you have a diff to explain what you want?
>
> route6_mpath() takes struct in_addr and writes it into struct route.
> What is bad about this design?
Nothing. I wonder if we need yet another wrapper around a wrapper so that
another wrapper can wrap it into a wrapper before passing it the function
doing the lookup.
If rtalloc_mpath() would be as simple as
struct rtentry *rtalloc_mpath(const struct route *);
then a lot of this would just go away since it is not needed.
Actually most of the code of route_mpath() and route6_mpath() could be
collapsed into rtalloc_mpath() (or vice versa).
Btw. I think the check to set 's' in route6_mpath() is reversed.
> We might get rid of rtalloc_mpath(). But then we have to use route
> cache everywhere. Rewriting the uint32_t * mess in the routing
> code is not on my agenda. I try to improve things in small steps.
> Moving part of rtalloc_mpath() calls to route6_mpath() makes it
> better. Are route6_mpath() parameter the arguments you wish?
> > I like the changes to ip_forward and ip6_forward and the general trend to
> > make code more consistent.
>
> Splitting the diff to change ip_forward() first is hard. The API
> of route6_mpath() or rtalloc_mpath() decides the way how consistent
> code should look like.
>
> How do we proceed? I don't understand how the code you wish looks.
Not against moving on with this but ideally there will be a few more steps
after this that slowly make rtalloc() and rtalloc_mpath() better functions.
As I said I like the trajectory of this work since it does a lot of good
cleanup at higher levels.
> > > 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
>
--
:wq Claudio
route cache mpath