On 13/11/14(Thu) 15:42, Martin Pieuchot wrote:
> In order to do *only one* route lookup without using a global variable
> (yes, I'm looking at you netinet6) and without doing too much spaghetti,
> here's a refactoring of ip_input().
>
> It basically merges in_ouraddr() into ip_input(), but some operations
> are shuffled, when possible, to reduces differences with the IPv6
> version.
>
> It also increments rt_use counters for the local routes, (say yeah!).
>
> Comment, bikeshed, ok?
I'm still looking for reviews, nobody?
>
> Index: netinet/ip_input.c
> ===================================================================
> RCS file: /home/ncvs/src/sys/netinet/ip_input.c,v
> retrieving revision 1.240
> diff -u -p -r1.240 ip_input.c
> --- netinet/ip_input.c 4 Nov 2014 15:24:40 -0000 1.240
> +++ netinet/ip_input.c 5 Nov 2014 13:52:25 -0000
> @@ -123,7 +123,6 @@ struct ipstat ipstat;
>
> 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);
>
> /*
> @@ -222,6 +221,8 @@ ipintr(void)
> void
> ipv4_input(struct mbuf *m)
> {
> + struct sockaddr_in sin;
> + struct rtentry *rt;
> struct ifnet *ifp;
> struct ip *ip;
> int hlen, len;
> @@ -341,11 +342,25 @@ ipv4_input(struct mbuf *m)
> return;
> }
>
> - if (in_ouraddr(m, ifp, ip->ip_dst)) {
> + if (ip->ip_dst.s_addr == INADDR_BROADCAST ||
> + ip->ip_dst.s_addr == INADDR_ANY) {
> + ip_ours(m);
> + return;
> + }
> +
> +#if NPF > 0
> + /* No need for a route lookup if we already know it's for us. */
> + if (m->m_pkthdr.pf.flags & PF_TAG_DIVERTED ||
> + (m->m_pkthdr.pf.statekey && m->m_pkthdr.pf.statekey->inp)) {
> ip_ours(m);
> return;
> }
>
> + /* If we have linked state keys it is certainly forwarded. */
> + if (m->m_pkthdr.pf.statekey && m->m_pkthdr.pf.statekey->reverse)
> + goto forward;
> +#endif
> +
> if (IN_MULTICAST(ip->ip_dst.s_addr)) {
> struct in_multi *inm;
> #ifdef MROUTING
> @@ -401,12 +416,79 @@ ipv4_input(struct mbuf *m)
> return;
> }
>
> - if (ip->ip_dst.s_addr == INADDR_BROADCAST ||
> - ip->ip_dst.s_addr == INADDR_ANY) {
> - ip_ours(m);
> - return;
> + memset(&sin, 0, sizeof(sin));
> + sin.sin_len = sizeof(sin);
> + sin.sin_family = AF_INET;
> + sin.sin_addr = ip->ip_dst;
> +
> + rt = rtalloc(sintosa(&sin), 0, m->m_pkthdr.ph_rtableid);
> + if (rt != NULL) {
> + /*
> + * We consider a packet as local if its destination
> + * matches a local route and the associated interface
> + * is up.
> + */
> + if (ISSET(rt->rt_flags, RTF_LOCAL)) {
> + /*
> + * XXX Since local routes' rt_ifp points to lo0
> + * we cannot rely on the rtentry flags.
> + */
> + if (ISSET(rt->rt_ifa->ifa_ifp->if_flags, IFF_UP)) {
> + rt->rt_use++;
> + rtfree(rt);
> + ip_ours(m);
> + return;
> + }
> + }
> +
> + /*
> + * This matches a broadcast address on one of our interfaces.
> + * If directedbcast is enabled we only consider it local if it
> + * is received on the interface with that address.
> + */
> + if (ISSET(rt->rt_flags, RTF_BROADCAST) &&
> + ISSET(rt->rt_flags, RTF_UP) &&
> + (!ip_directedbcast || rt->rt_ifp == ifp)) {
> + rt->rt_use++;
> + rtfree(rt);
> +
> + /* Make sure M_BCAST is set */
> + m->m_flags |= M_BCAST;
> + ip_ours(m);
> + return;
> + }
> +
> + rtfree(rt);
> + }
> +
> + /*
> + * No local address or broadcast address found, so check for
> + * ancient classful broadcast addresses.
> + * It must have been broadcast on the link layer, and for an
> + * address on the interface it was received on.
> + */
> + if (ISSET(m->m_flags, M_BCAST) &&
> + IN_CLASSFULBROADCAST(ip->ip_dst.s_addr, ip->ip_dst.s_addr)) {
> + struct ifaddr *ifa;
> +
> + /*
> + * The check in the loop assumes you only rx a packet
> + * on an UP interface, and that M_BCAST will only be
> + * set on a BROADCAST interface.
> + */
> + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
> + if (ifa->ifa_addr->sa_family != AF_INET)
> + continue;
> +
> + if (IN_CLASSFULBROADCAST(ip->ip_dst.s_addr,
> + ifatoia(ifa)->ia_addr.sin_addr.s_addr)) {
> + ip_ours(m);
> + return;
> + }
> + }
> }
>
> +forward:
> #if NCARP > 0
> if (ifp->if_type == IFT_CARP && ip->ip_p == IPPROTO_ICMP &&
> carp_lsdrop(m, AF_INET, &ip->ip_src.s_addr, &ip->ip_dst.s_addr))
> @@ -636,89 +718,6 @@ found:
> return;
> bad:
> m_freem(m);
> -}
> -
> -int
> -in_ouraddr(struct mbuf *m, struct ifnet *ifp, struct in_addr ina)
> -{
> - struct in_ifaddr *ia = NULL;
> - struct rtentry *rt;
> - struct sockaddr_in sin;
> -#if NPF > 0
> - struct pf_state_key *key;
> -
> - if (m->m_pkthdr.pf.flags & PF_TAG_DIVERTED)
> - return (1);
> -
> - key = m->m_pkthdr.pf.statekey;
> - if (key != NULL) {
> - if (key->inp != NULL)
> - return (1);
> -
> - /* If we have linked state keys it is certainly forwarded. */
> - if (key->reverse != NULL)
> - return (0);
> - }
> -#endif
> -
> - memset(&sin, 0, sizeof(sin));
> - sin.sin_len = sizeof(sin);
> - sin.sin_family = AF_INET;
> - sin.sin_addr = ina;
> - rt = rtalloc(sintosa(&sin), 0, m->m_pkthdr.ph_rtableid);
> - if (rt != NULL) {
> - if (rt->rt_flags & (RTF_LOCAL|RTF_BROADCAST))
> - ia = ifatoia(rt->rt_ifa);
> - rtfree(rt);
> - }
> -
> - if (ia == NULL) {
> - struct ifaddr *ifa;
> -
> - /*
> - * No local address or broadcast address found, so check for
> - * ancient classful broadcast addresses.
> - * It must have been broadcast on the link layer, and for an
> - * address on the interface it was received on.
> - */
> - if (!ISSET(m->m_flags, M_BCAST) ||
> - !IN_CLASSFULBROADCAST(ina.s_addr, ina.s_addr))
> - return (0);
> -
> - if (ifp->if_rdomain != rtable_l2(m->m_pkthdr.ph_rtableid))
> - return (0);
> - /*
> - * The check in the loop assumes you only rx a packet on an UP
> - * interface, and that M_BCAST will only be set on a BROADCAST
> - * interface.
> - */
> - TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
> - if (ifa->ifa_addr->sa_family != AF_INET)
> - continue;
> -
> - if (IN_CLASSFULBROADCAST(ina.s_addr,
> - ifatoia(ifa)->ia_addr.sin_addr.s_addr))
> - return (1);
> - }
> -
> - return (0);
> - }
> -
> - if (ina.s_addr != ia->ia_addr.sin_addr.s_addr) {
> - /*
> - * This matches a broadcast address on one of our interfaces.
> - * If directedbcast is enabled we only consider it local if it
> - * is received on the interface with that address.
> - */
> - if (ip_directedbcast && ia->ia_ifp != ifp)
> - return (0);
> -
> - /* Make sure M_BCAST is set */
> - if (m)
> - m->m_flags |= M_BCAST;
> - }
> -
> - return (ISSET(ia->ia_ifp->if_flags, IFF_UP));
> }
>
> struct in_ifaddr *
>