The IP in IP input function strips the outer header and reinserts
authorbluhm <bluhm@openbsd.org>
Wed, 5 Jul 2017 11:34:10 +0000 (11:34 +0000)
committerbluhm <bluhm@openbsd.org>
Wed, 5 Jul 2017 11:34:10 +0000 (11:34 +0000)
the inner IP packet into the internet queue.  The IPv6 local delivery
code has a loop to deal with header chains.  The idea is to use
this loop and avoid the queueing and rescheduling.  The IPsec packet
will be processed in a single flow.
Merge the IP deliver loop from both IP versions into a single
ip_deliver() function that can handle both addresss families.  This
allows to process an IP in IP header like a normal extension header.
If af != AF_UNSPEC, we are already in a deliver loop and have the
kernel look.  Then we can just return the next protocol.  Otherwise
we enqueue.  The dequeue thread has the kernel lock and starts an
IP delivery loop.
OK mpi@

sys/netinet/ip_input.c
sys/netinet/ip_ipip.c
sys/netinet/ipsec_input.c
sys/netinet6/ip6_input.c
sys/netinet6/ip6_var.h

index 65b2784..3437337 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ip_input.c,v 1.313 2017/06/26 19:06:12 bluhm Exp $    */
+/*     $OpenBSD: ip_input.c,v 1.314 2017/07/05 11:34:10 bluhm Exp $    */
 /*     $NetBSD: ip_input.c,v 1.30 1996/03/16 23:53:58 christos Exp $   */
 
 /*
 #include <netinet/ip_var.h>
 #include <netinet/ip_icmp.h>
 
+#ifdef INET6
+#include <netinet6/ip6protosw.h>
+#include <netinet6/ip6_var.h>
+#endif
+
 #if NPF > 0
 #include <net/pfvar.h>
 #endif
@@ -216,6 +221,10 @@ ip_init(void)
 int
 ip_ours(struct mbuf **mp, int *offp, int nxt, int af)
 {
+       /* We are already in a IPv4/IPv6 local deliver loop. */
+       if (af != AF_UNSPEC)
+               return ip_local(mp, offp, nxt, af);
+
        niq_enqueue(&ipintrq, *mp);
        *mp = NULL;
        return IPPROTO_DONE;
@@ -595,36 +604,118 @@ found:
        }
 
        *offp = hlen;
-       return ip_deliver(mp, offp, ip->ip_p, AF_INET);
+       nxt = ip->ip_p;
+       /* Check wheter we are already in a IPv4/IPv6 local deliver loop. */
+       if (af == AF_UNSPEC)
+               nxt = ip_deliver(mp, offp, nxt, AF_INET);
+       return nxt;
  bad:
        m_freemp(mp);
        return IPPROTO_DONE;
 }
 
+#ifndef INET6
+#define IPSTAT_INC(name)       ipstat_inc(ips_##name)
+#else
+#define IPSTAT_INC(name)       (af == AF_INET ?        \
+    ipstat_inc(ips_##name) : ip6stat_inc(ip6s_##name))
+#endif
+
 int
 ip_deliver(struct mbuf **mp, int *offp, int nxt, int af)
 {
+       struct protosw *psw;
+       int naf = af;
+#ifdef INET6
+       int nest = 0;
+#endif /* INET6 */
+
        KERNEL_ASSERT_LOCKED();
 
        /* pf might have modified stuff, might have to chksum */
-       in_proto_cksum_out(*mp, NULL);
+       switch (af) {
+       case AF_INET:
+               in_proto_cksum_out(*mp, NULL);
+               break;
+#ifdef INET6
+       case AF_INET6:
+               in6_proto_cksum_out(*mp, NULL);
+               break;
+#endif /* INET6 */
+       }
 
-#ifdef IPSEC
-       if (ipsec_in_use) {
-               if (ipsec_local_check(*mp, *offp, nxt, af) != 0) {
-                       ipstat_inc(ips_cantforward);
+       /*
+        * Tell launch routine the next header
+        */
+       IPSTAT_INC(delivered);
+
+       while (nxt != IPPROTO_DONE) {
+#ifdef INET6
+               if (af == AF_INET6 &&
+                   ip6_hdrnestlimit && (++nest > ip6_hdrnestlimit)) {
+                       ip6stat_inc(ip6s_toomanyhdr);
                        goto bad;
                }
-       }
-       /* Otherwise, just fall through and deliver the packet */
+#endif /* INET6 */
+
+               /*
+                * protection against faulty packet - there should be
+                * more sanity checks in header chain processing.
+                */
+               if ((*mp)->m_pkthdr.len < *offp) {
+                       IPSTAT_INC(tooshort);
+                       goto bad;
+               }
+
+#ifdef INET6
+               /* draft-itojun-ipv6-tcp-to-anycast */
+               if (af == AF_INET6 &&
+                   ISSET((*mp)->m_flags, M_ACAST) && (nxt == IPPROTO_TCP)) {
+                       if ((*mp)->m_len >= sizeof(struct ip6_hdr)) {
+                               icmp6_error(*mp, ICMP6_DST_UNREACH,
+                                       ICMP6_DST_UNREACH_ADDR,
+                                       offsetof(struct ip6_hdr, ip6_dst));
+                               *mp = NULL;
+                       }
+                       goto bad;
+               }
+#endif /* INET6 */
+
+#ifdef IPSEC
+               if (ipsec_in_use) {
+                       if (ipsec_local_check(*mp, *offp, nxt, af) != 0) {
+                               IPSTAT_INC(cantforward);
+                               goto bad;
+                       }
+               }
+               /* Otherwise, just fall through and deliver the packet */
 #endif /* IPSEC */
 
-       /*
-        * Switch out to protocol's input routine.
-        */
-       ipstat_inc(ips_delivered);
-       nxt = (*inetsw[ip_protox[nxt]].pr_input)(mp, offp, nxt, af);
-       KASSERT(nxt == IPPROTO_DONE);
+               switch (nxt) {
+               case IPPROTO_IPV4:
+                       naf = AF_INET;
+                       ipstat_inc(ips_delivered);
+                       break;
+#ifdef INET6
+               case IPPROTO_IPV6:
+                       naf = AF_INET6;
+                       ip6stat_inc(ip6s_delivered);
+                       break;
+#endif /* INET6 */
+               }
+               switch (af) {
+               case AF_INET:
+                       psw = &inetsw[ip_protox[nxt]];
+                       break;
+#ifdef INET6
+               case AF_INET6:
+                       psw = &inet6sw[ip6_protox[nxt]];
+                       break;
+#endif /* INET6 */
+               }
+               nxt = (*psw->pr_input)(mp, offp, nxt, af);
+               af = naf;
+       }
        return nxt;
 #ifdef IPSEC
  bad:
@@ -632,6 +723,7 @@ ip_deliver(struct mbuf **mp, int *offp, int nxt, int af)
        m_freemp(mp);
        return IPPROTO_DONE;
 }
+#undef IPSTAT_INC
 
 int
 in_ouraddr(struct mbuf *m, struct ifnet *ifp, struct rtentry **prt)
index a7de325..1eb94e0 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ip_ipip.c,v 1.85 2017/06/20 11:12:13 bluhm Exp $ */
+/*     $OpenBSD: ip_ipip.c,v 1.86 2017/07/05 11:34:10 bluhm Exp $ */
 /*
  * The authors of this code are John Ioannidis (ji@tla.org),
  * Angelos D. Keromytis (kermit@csd.uch.gr) and
@@ -316,14 +316,10 @@ ipip_input_if(struct mbuf **mp, int *offp, int proto, int oaf,
 
        switch (proto) {
        case IPPROTO_IPV4:
-               ipv4_input(ifp, m);
-               *mp = NULL;
-               return IPPROTO_DONE;
+               return ip_input_if(mp, offp, proto, oaf, ifp);
 #ifdef INET6
        case IPPROTO_IPV6:
-               ipv6_input(ifp, m);
-               *mp = NULL;
-               return IPPROTO_DONE;
+               return ip6_input_if(mp, offp, proto, oaf, ifp);
 #endif
        }
  bad:
index 05c0ae4..a3fad48 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ipsec_input.c,v 1.155 2017/06/19 17:58:49 bluhm Exp $ */
+/*     $OpenBSD: ipsec_input.c,v 1.156 2017/07/05 11:34:10 bluhm Exp $ */
 /*
  * The authors of this code are John Ioannidis (ji@tla.org),
  * Angelos D. Keromytis (kermit@csd.uch.gr) and
@@ -607,21 +607,7 @@ ipsec_common_input_cb(struct mbuf *m, struct tdb *tdbp, int skip, int protoff)
        }
 #endif
        /* Call the appropriate IPsec transform callback. */
-       switch (af) {
-       case AF_INET:
-               ip_deliver(&m, &skip, prot, af);
-               return;
-#ifdef INET6
-       case AF_INET6:
-               ip6_deliver(&m, &skip, prot, af);
-               return;
-#endif /* INET6 */
-       default:
-               DPRINTF(("ipsec_common_input_cb(): unknown/unsupported "
-                   "protocol family %d\n", af));
-               m_freem(m);
-               return;
-       }
+       ip_deliver(&m, &skip, prot, af);
 #undef IPSEC_ISTAT
 }
 
index ce15307..ed8702f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ip6_input.c,v 1.197 2017/06/27 13:28:02 bluhm Exp $   */
+/*     $OpenBSD: ip6_input.c,v 1.198 2017/07/05 11:34:10 bluhm Exp $   */
 /*     $KAME: ip6_input.c,v 1.188 2001/03/29 05:34:31 itojun Exp $     */
 
 /*
@@ -169,6 +169,10 @@ ip6_init(void)
 int
 ip6_ours(struct mbuf **mp, int *offp, int nxt, int af)
 {
+       /* We are already in a IPv4/IPv6 local deliver loop. */
+       if (af != AF_UNSPEC)
+               return ip6_local(mp, offp, nxt, af);
+
        niq_enqueue(&ip6intrq, *mp);
        *mp = NULL;
        return IPPROTO_DONE;
@@ -425,9 +429,12 @@ ip6_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet *ifp)
                        }
 
                        if (ours) {
-                               KERNEL_LOCK();
-                               nxt = ip6_deliver(mp, offp, nxt, AF_INET6);
-                               KERNEL_UNLOCK();
+                               if (af == AF_UNSPEC) {
+                                       KERNEL_LOCK();
+                                       nxt = ip_deliver(mp, offp, nxt,
+                                           AF_INET6);
+                                       KERNEL_UNLOCK();
+                               }
                                goto out;
                        }
                        goto bad;
@@ -502,9 +509,11 @@ ip6_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet *ifp)
                goto out;
 
        if (ours) {
-               KERNEL_LOCK();
-               nxt = ip6_deliver(mp, offp, nxt, AF_INET6);
-               KERNEL_UNLOCK();
+               if (af == AF_UNSPEC) {
+                       KERNEL_LOCK();
+                       nxt = ip_deliver(mp, offp, nxt, AF_INET6);
+                       KERNEL_UNLOCK();
+               }
                goto out;
        }
 
@@ -542,66 +551,10 @@ ip6_local(struct mbuf **mp, int *offp, int nxt, int af)
        if (ip6_hbhchcheck(*mp, offp, &nxt, NULL))
                return IPPROTO_DONE;
 
-       return ip6_deliver(mp, offp, nxt, AF_INET6);
-}
-
-int
-ip6_deliver(struct mbuf **mp, int *offp, int nxt, int af)
-{
-       int nest = 0;
-
-       KERNEL_ASSERT_LOCKED();
-
-       /* pf might have changed things */
-       in6_proto_cksum_out(*mp, NULL);
-
-       /*
-        * Tell launch routine the next header
-        */
-       ip6stat_inc(ip6s_delivered);
-
-       while (nxt != IPPROTO_DONE) {
-               if (ip6_hdrnestlimit && (++nest > ip6_hdrnestlimit)) {
-                       ip6stat_inc(ip6s_toomanyhdr);
-                       goto bad;
-               }
-
-               /*
-                * protection against faulty packet - there should be
-                * more sanity checks in header chain processing.
-                */
-               if ((*mp)->m_pkthdr.len < *offp) {
-                       ip6stat_inc(ip6s_tooshort);
-                       goto bad;
-               }
-
-               /* draft-itojun-ipv6-tcp-to-anycast */
-               if (ISSET((*mp)->m_flags, M_ACAST) && (nxt == IPPROTO_TCP)) {
-                       if ((*mp)->m_len >= sizeof(struct ip6_hdr)) {
-                               icmp6_error(*mp, ICMP6_DST_UNREACH,
-                                       ICMP6_DST_UNREACH_ADDR,
-                                       offsetof(struct ip6_hdr, ip6_dst));
-                               *mp = NULL;
-                       }
-                       goto bad;
-               }
-
-#ifdef IPSEC
-               if (ipsec_in_use) {
-                       if (ipsec_local_check(*mp, *offp, nxt, af) != 0) {
-                               ip6stat_inc(ip6s_cantforward);
-                               goto bad;
-                       }
-               }
-               /* Otherwise, just fall through and deliver the packet */
-#endif /* IPSEC */
-
-               nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(mp, offp, nxt, af);
-       }
+       /* Check wheter we are already in a IPv4/IPv6 local deliver loop. */
+       if (af == AF_UNSPEC)
+               nxt = ip_deliver(mp, offp, nxt, AF_INET6);
        return nxt;
- bad:
-       m_freemp(mp);
-       return IPPROTO_DONE;
 }
 
 int
index d031bda..9b58d9e 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ip6_var.h,v 1.76 2017/06/27 13:28:02 bluhm Exp $      */
+/*     $OpenBSD: ip6_var.h,v 1.77 2017/07/05 11:34:10 bluhm Exp $      */
 /*     $KAME: ip6_var.h,v 1.33 2000/06/11 14:59:20 jinmei Exp $        */
 
 /*
@@ -304,7 +304,6 @@ int icmp6_ctloutput(int, struct socket *, int, int, struct mbuf *);
 void   ip6_init(void);
 void   ip6intr(void);
 int    ip6_input_if(struct mbuf **, int *, int, int, struct ifnet *);
-int    ip6_deliver(struct mbuf **, int *, int, int);
 void   ip6_freepcbopts(struct ip6_pktopts *);
 void   ip6_freemoptions(struct ip6_moptions *);
 int    ip6_unknown_opt(u_int8_t *, struct mbuf *, int);