On Mon, Apr 25, 2016 at 02:40:41PM +0200, Martin Pieuchot wrote:
> Diff below makes ip_forward() use the route entry fetched in in_ouraddr().
>
> As you can imagine a proper caching could be done for forwarding using
> PF statekey.
>
> This diff has been tested by Hrvoje Popovski who confirmed that the
> benchmark performances are similar to the ones using a single cache
> entry.
>
> ok?
OK bluhm@
>
>
> Index: netinet/ip_input.c
> ===================================================================
> RCS file: /cvs/src/sys/netinet/ip_input.c,v
> retrieving revision 1.274
> diff -u -p -r1.274 ip_input.c
> --- netinet/ip_input.c 25 Apr 2016 12:33:48 -0000 1.274
> +++ netinet/ip_input.c 25 Apr 2016 12:34:46 -0000
> @@ -126,8 +126,8 @@ static struct mbuf_queue ipsend_mq;
>
> void ip_ours(struct mbuf *);
> int ip_dooptions(struct mbuf *, struct ifnet *);
> -int in_ouraddr(struct mbuf *, struct ifnet *, struct in_addr);
> -void ip_forward(struct mbuf *, struct ifnet *, int);
> +int in_ouraddr(struct mbuf *, struct ifnet *, struct rtentry **);
> +void ip_forward(struct mbuf *, struct ifnet *, struct rtentry *, int);
> #ifdef IPSEC
> int ip_input_ipsec_fwd_check(struct mbuf *, int);
> int ip_input_ipsec_ours_check(struct mbuf *, int);
> @@ -223,8 +223,9 @@ ipintr(void)
> void
> ipv4_input(struct mbuf *m)
> {
> - struct ifnet *ifp;
> - struct ip *ip;
> + struct ifnet *ifp;
> + struct rtentry *rt = NULL;
> + struct ip *ip;
> int hlen, len;
> #if defined(MROUTING) || defined(IPSEC)
> int rv;
> @@ -341,7 +342,7 @@ ipv4_input(struct mbuf *m)
> goto out;
> }
>
> - if (in_ouraddr(m, ifp, ip->ip_dst)) {
> + if (in_ouraddr(m, ifp, &rt)) {
> ip_ours(m);
> goto out;
> }
> @@ -443,12 +444,13 @@ ipv4_input(struct mbuf *m)
> }
> #endif /* IPSEC */
>
> - ip_forward(m, ifp, pfrdr);
> + ip_forward(m, ifp, rt, pfrdr);
> if_put(ifp);
> return;
> bad:
> m_freem(m);
> out:
> + rtfree(rt);
> if_put(ifp);
> }
>
> @@ -575,9 +577,10 @@ bad:
> }
>
> int
> -in_ouraddr(struct mbuf *m, struct ifnet *ifp, struct in_addr ina)
> +in_ouraddr(struct mbuf *m, struct ifnet *ifp, struct rtentry **prt)
> {
> struct rtentry *rt;
> + struct ip *ip;
> struct sockaddr_in sin;
> int match = 0;
> #if NPF > 0
> @@ -597,10 +600,12 @@ in_ouraddr(struct mbuf *m, struct ifnet
> }
> #endif
>
> + ip = mtod(m, struct ip *);
> +
> memset(&sin, 0, sizeof(sin));
> sin.sin_len = sizeof(sin);
> sin.sin_family = AF_INET;
> - sin.sin_addr = ina;
> + sin.sin_addr = ip->ip_dst;
> rt = rtalloc(sintosa(&sin), 0, m->m_pkthdr.ph_rtableid);
> if (rtisvalid(rt)) {
> if (ISSET(rt->rt_flags, RTF_LOCAL))
> @@ -618,7 +623,7 @@ in_ouraddr(struct mbuf *m, struct ifnet
> m->m_flags |= M_BCAST;
> }
> }
> - rtfree(rt);
> + *prt = rt;
>
> if (!match) {
> struct ifaddr *ifa;
> @@ -630,7 +635,7 @@ in_ouraddr(struct mbuf *m, struct ifnet
> * address on the interface it was received on.
> */
> if (!ISSET(m->m_flags, M_BCAST) ||
> - !IN_CLASSFULBROADCAST(ina.s_addr, ina.s_addr))
> + !IN_CLASSFULBROADCAST(ip->ip_dst.s_addr, ip->ip_dst.s_addr))
> return (0);
>
> if (ifp->if_rdomain != rtable_l2(m->m_pkthdr.ph_rtableid))
> @@ -645,7 +650,7 @@ in_ouraddr(struct mbuf *m, struct ifnet
> if (ifa->ifa_addr->sa_family != AF_INET)
> continue;
>
> - if (IN_CLASSFULBROADCAST(ina.s_addr,
> + if (IN_CLASSFULBROADCAST(ip->ip_dst.s_addr,
> ifatoia(ifa)->ia_addr.sin_addr.s_addr)) {
> match = 1;
> break;
> @@ -1241,7 +1246,7 @@ ip_dooptions(struct mbuf *m, struct ifne
> }
> KERNEL_UNLOCK();
> if (forward && ipforwarding) {
> - ip_forward(m, ifp, 1);
> + ip_forward(m, ifp, NULL, 1);
> return (1);
> }
> return (0);
> @@ -1387,12 +1392,11 @@ int inetctlerrmap[PRC_NCMDS] = {
> * via a source route.
> */
> void
> -ip_forward(struct mbuf *m, struct ifnet *ifp, int srcrt)
> +ip_forward(struct mbuf *m, struct ifnet *ifp, struct rtentry *rt, int srcrt)
> {
> struct mbuf mfake, *mcopy = NULL;
> struct ip *ip = mtod(m, struct ip *);
> struct sockaddr_in *sin;
> - struct rtentry *rt;
> struct route ro;
> int error, type = 0, code = 0, destmtu = 0, fake = 0, len;
> u_int32_t dest;
> @@ -1401,25 +1405,27 @@ ip_forward(struct mbuf *m, struct ifnet
> if (m->m_flags & (M_BCAST|M_MCAST) || in_canforward(ip->ip_dst) == 0) {
> ipstat.ips_cantforward++;
> m_freem(m);
> - return;
> + goto freecopy;
> }
> if (ip->ip_ttl <= IPTTLDEC) {
> icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, dest, 0);
> - return;
> + goto freecopy;
> }
>
> -
> sin = satosin(&ro.ro_dst);
> memset(sin, 0, sizeof(*sin));
> sin->sin_family = AF_INET;
> sin->sin_len = sizeof(*sin);
> sin->sin_addr = ip->ip_dst;
>
> - rt = rtalloc_mpath(sintosa(sin), &ip->ip_src.s_addr,
> - m->m_pkthdr.ph_rtableid);
> - if (rt == NULL) {
> - icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0);
> - return;
> + if (!rtisvalid(rt)) {
> + rtfree(rt);
> + rt = rtalloc_mpath(sintosa(sin), &ip->ip_src.s_addr,
> + m->m_pkthdr.ph_rtableid);
> + if (rt == NULL) {
> + icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0);
> + return;
> + }
> }
>
> /*