Download raw body.
ipv4 icmp_reflect() source address selection optimisation
On Sat, Jun 07, 2025 at 01:57:45PM +1000, David Gwynne wrote:
> how about i make this a bit easier for you and split the changes
> in this diff up?
This diff passed all my tests. OK bluhm@
> this one has icmp_reflect respect the route sourceaddr like
> in_pcbselsrc, but doesn't use the rcvif to pick an address.
>
> Index: ip_icmp.c
> ===================================================================
> RCS file: /cvs/src/sys/netinet/ip_icmp.c,v
> diff -u -p -r1.199 ip_icmp.c
> --- ip_icmp.c 2 Mar 2025 21:28:32 -0000 1.199
> +++ ip_icmp.c 7 Jun 2025 03:51:30 -0000
> @@ -691,7 +691,8 @@ icmp_reflect(struct mbuf *m, struct mbuf
> struct ip *ip = mtod(m, struct ip *);
> struct mbuf *opts = NULL;
> struct sockaddr_in sin;
> - struct rtentry *rt = NULL;
> + struct rtentry *rt;
> + struct in_addr ip_src = { INADDR_ANY };
> int optlen = (ip->ip_hl << 2) - sizeof(struct ip);
> u_int rtableid;
> u_int8_t pfflags;
> @@ -708,10 +709,6 @@ icmp_reflect(struct mbuf *m, struct mbuf
> return (ELOOP);
> }
> rtableid = m->m_pkthdr.ph_rtableid;
> - pfflags = m->m_pkthdr.pf.flags;
> - m_resethdr(m);
> - m->m_pkthdr.ph_rtableid = rtableid;
> - m->m_pkthdr.pf.flags = pfflags & PF_TAG_GENERATED;
>
> /*
> * If the incoming packet was addressed directly to us,
> @@ -725,19 +722,24 @@ icmp_reflect(struct mbuf *m, struct mbuf
> sin.sin_addr = ip->ip_dst;
>
> rt = rtalloc(sintosa(&sin), 0, rtableid);
> - if (rtisvalid(rt) &&
> - ISSET(rt->rt_flags, RTF_LOCAL|RTF_BROADCAST))
> - ia = ifatoia(rt->rt_ifa);
> - }
> + if (rtisvalid(rt)) {
> + if (ISSET(rt->rt_flags, RTF_LOCAL))
> + ip_src = ip->ip_dst;
> + else if (ISSET(rt->rt_flags, RTF_BROADCAST)) {
> + ia = ifatoia(rt->rt_ifa);
> + ip_src = ia->ia_addr.sin_addr;
> + }
> + }
> + rtfree(rt);
> + } else
> + ip_src = ia->ia_addr.sin_addr;
>
> /*
> * The following happens if the packet was not addressed to us.
> - * Use the new source address and do a route lookup. If it fails
> - * drop the packet as there is no path to the host.
> + * If we're directly connected use the closest address, otherwise
> + * try to use the sourceaddr from the routing table.
> */
> - if (ia == NULL) {
> - rtfree(rt);
> -
> + if (ip_src.s_addr == INADDR_ANY) {
> memset(&sin, 0, sizeof(sin));
> sin.sin_len = sizeof(sin);
> sin.sin_family = AF_INET;
> @@ -745,21 +747,38 @@ icmp_reflect(struct mbuf *m, struct mbuf
>
> /* keep packet in the original virtual instance */
> rt = rtalloc(sintosa(&sin), RT_RESOLVE, rtableid);
> - if (rt == NULL) {
> - ipstat_inc(ips_noroute);
> - m_freem(m);
> - return (EHOSTUNREACH);
> + if (rtisvalid(rt) &&
> + ISSET(rt->rt_flags, RTF_LLINFO|RTF_HOST)) {
> + ia = ifatoia(rt->rt_ifa);
> + ip_src = ia->ia_addr.sin_addr;
> + } else {
> + struct sockaddr *sourceaddr;
> + struct ifaddr *ifa;
> +
> + sourceaddr = rtable_getsource(rtableid, AF_INET);
> + if (sourceaddr != NULL) {
> + ifa = ifa_ifwithaddr(sourceaddr, rtableid);
> + if (ifa != NULL &&
> + ISSET(ifa->ifa_ifp->if_flags, IFF_UP))
> + ip_src = satosin(sourceaddr)->sin_addr;
> + }
> }
> -
> - ia = ifatoia(rt->rt_ifa);
> + rtfree(rt);
> }
>
> + /*
> + * If the above didn't find an ip_src, ip_output() will try
> + * and fill it in for us.
> + */
> +
> + pfflags = m->m_pkthdr.pf.flags;
> +
> + m_resethdr(m);
> + m->m_pkthdr.ph_rtableid = rtableid;
> + m->m_pkthdr.pf.flags = pfflags & PF_TAG_GENERATED;
> ip->ip_dst = ip->ip_src;
> + ip->ip_src = ip_src;
> ip->ip_ttl = MAXTTL;
> -
> - /* It is safe to dereference ``ia'' iff ``rt'' is valid. */
> - ip->ip_src = ia->ia_addr.sin_addr;
> - rtfree(rt);
>
> if (optlen > 0) {
> u_char *cp;
ipv4 icmp_reflect() source address selection optimisation