Use route cache function in IP input.
authorbluhm <bluhm@openbsd.org>
Tue, 16 Apr 2024 12:56:39 +0000 (12:56 +0000)
committerbluhm <bluhm@openbsd.org>
Tue, 16 Apr 2024 12:56:39 +0000 (12:56 +0000)
Instaed of passing a struct rtentry from ip_input() to ip_forward()
and then embed it into a struct route for ip_output(), start with
struct route and pass it along.  Then the route cache is used
consistently.  Also the route cache hit and missed counters should
reflect reality after this commit.

There is a small difference in the code.  in_ouraddr() checks for
NULL and not rtisvalid().  Previous discussion showed that the route
RTF_UP flag should only be considered for multipath routing.
Otherwise it does not mean anything.  Especially the local and
broadcast check in in_ouraddr() should not be affected by interface
link status.

When doing cache lookups, route must be valid, but after rtalloc_mpath()
lookup, use any route that route_mpath() returns.

OK claudio@

sys/netinet/ip_input.c
sys/netinet/ip_var.h
sys/netinet6/ip6_forward.c
sys/netinet6/ip6_input.c
sys/netinet6/ip6_output.c
sys/netinet6/ip6_var.h

index 25f9cc5..1d15104 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ip_input.c,v 1.392 2024/04/14 20:46:27 bluhm Exp $    */
+/*     $OpenBSD: ip_input.c,v 1.393 2024/04/16 12:56:39 bluhm Exp $    */
 /*     $NetBSD: ip_input.c,v 1.30 1996/03/16 23:53:58 christos Exp $   */
 
 /*
@@ -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 *);
@@ -424,9 +424,9 @@ 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;
 #if NPF > 0
        struct in_addr odst;
@@ -435,6 +435,7 @@ ip_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet *ifp)
 
        KASSERT(*offp == 0);
 
+       ro.ro_rt = NULL;
        ipstat_inc(ips_total);
        m = *mp = ipv4_check(ifp, *mp);
        if (m == NULL)
@@ -482,7 +483,7 @@ ip_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet *ifp)
                goto out;
        }
 
-       switch(in_ouraddr(m, ifp, &rt)) {
+       switch(in_ouraddr(m, ifp, &ro)) {
        case 2:
                goto bad;
        case 1:
@@ -584,14 +585,14 @@ ip_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet *ifp)
        }
 #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;
 }
 
@@ -805,11 +806,10 @@ ip_deliver(struct mbuf **mp, int *offp, int nxt, int af, int shared)
 #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
@@ -826,13 +826,8 @@ in_ouraddr(struct mbuf *m, struct ifnet *ifp, struct rtentry **prt)
 
        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;
 
@@ -848,7 +843,6 @@ in_ouraddr(struct mbuf *m, struct ifnet *ifp, struct rtentry **prt)
                        m->m_flags |= M_BCAST;
                }
        }
-       *prt = rt;
 
        if (!match) {
                struct ifaddr *ifa;
@@ -1527,11 +1521,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;
        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;
 
@@ -1546,19 +1541,16 @@ ip_forward(struct mbuf *m, struct ifnet *ifp, struct rtentry *rt, int srcrt)
                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
@@ -1609,10 +1601,10 @@ ip_forward(struct mbuf *m, struct ifnet *ifp, struct rtentry *rt, int srcrt)
                }
        }
 
-       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 {
@@ -1680,9 +1672,10 @@ ip_forward(struct mbuf *m, struct ifnet *ifp, struct rtentry *rt, int srcrt)
                icmp_error(mcopy, type, code, dest, destmtu);
 
  done:
+       if (ro == &iproute)
+               rtfree(ro->ro_rt);
        if (fake)
                m_tag_delete_chain(&mfake);
-       rtfree(rt);
 }
 
 int
index c5b9284..cdbdd2d 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ip_var.h,v 1.115 2024/04/14 20:46:27 bluhm Exp $      */
+/*     $OpenBSD: ip_var.h,v 1.116 2024/04/16 12:56:39 bluhm Exp $      */
 /*     $NetBSD: ip_var.h,v 1.16 1996/02/13 23:43:20 christos Exp $     */
 
 /*
@@ -260,7 +260,7 @@ void         ip_savecontrol(struct inpcb *, struct mbuf **, struct ip *,
            struct mbuf *);
 int     ip_input_if(struct mbuf **, int *, int, int, struct ifnet *);
 int     ip_deliver(struct mbuf **, int *, 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 84c872a..913fb64 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ip6_forward.c,v 1.116 2024/02/28 10:57:20 bluhm Exp $ */
+/*     $OpenBSD: ip6_forward.c,v 1.117 2024/04/16 12:56:39 bluhm Exp $ */
 /*     $KAME: ip6_forward.c,v 1.75 2001/06/29 12:42:13 jinmei Exp $    */
 
 /*
  */
 
 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;
@@ -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 != NULL) {
-                               icmp6_error(mcopy, ICMP6_DST_UNREACH,
-                                           ICMP6_DST_UNREACH_NOROUTE, 0);
-                       }
-                       m_freem(m);
-                       goto done;
+       if (rt == NULL) {
+               ip6stat_inc(ip6s_noroute);
+               if (mcopy != NULL) {
+                       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
@@ -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
@@ -308,8 +306,9 @@ 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;
+               if (ro == &iproute)
+                       rtfree(ro->ro_rt);
+               ro = NULL;
                if_put(ifp);
                ifp = NULL;
                goto reroute;
@@ -388,7 +387,8 @@ senderr:
  freecopy:
        m_freem(mcopy);
  done:
-       rtfree(rt);
+       if (ro == &iproute)
+               rtfree(ro->ro_rt);
        if_put(ifp);
 #ifdef IPSEC
        tdb_unref(tdb);
index 5f4e991..e389bc0 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ip6_input.c,v 1.260 2024/04/14 20:46:27 bluhm Exp $   */
+/*     $OpenBSD: ip6_input.c,v 1.261 2024/04/16 12:56:39 bluhm Exp $   */
 /*     $KAME: ip6_input.c,v 1.188 2001/03/29 05:34:31 itojun Exp $     */
 
 /*
@@ -356,10 +356,10 @@ 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
@@ -369,8 +369,8 @@ ip6_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet *ifp)
 
        KASSERT(*offp == 0);
 
+       ro.ro_rt = NULL;
        ip6stat_inc(ip6s_total);
-
        m = *mp = ipv6_check(ifp, *mp);
        if (m == NULL)
                goto bad;
@@ -516,18 +516,14 @@ ip6_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet *ifp)
        /*
         *  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 &&
@@ -617,14 +613,14 @@ ip6_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet *ifp)
        }
 #endif /* IPSEC */
 
-       ip6_forward(m, rt, pfrdr);
+       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 a2ba550..99d494d 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ip6_output.c,v 1.289 2024/04/09 11:05:05 bluhm Exp $  */
+/*     $OpenBSD: ip6_output.c,v 1.290 2024/04/16 12:56:39 bluhm Exp $  */
 /*     $KAME: ip6_output.c,v 1.172 2001/03/25 09:55:56 itojun Exp $    */
 
 /*
@@ -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)
index c1249f7..1b9ae82 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ip6_var.h,v 1.114 2024/02/14 13:18:21 claudio Exp $   */
+/*     $OpenBSD: ip6_var.h,v 1.115 2024/04/16 12:56:39 bluhm Exp $     */
 /*     $KAME: ip6_var.h,v 1.33 2000/06/11 14:59:20 jinmei Exp $        */
 
 /*
@@ -320,7 +320,7 @@ int ip6_process_hopopts(struct mbuf **, u_int8_t *, int, u_int32_t *,
 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,