Run IPv6 hop-by-hop options processing in parallel. The ip6_hbhchcheck()
authorbluhm <bluhm@openbsd.org>
Mon, 15 Aug 2022 16:15:36 +0000 (16:15 +0000)
committerbluhm <bluhm@openbsd.org>
Mon, 15 Aug 2022 16:15:36 +0000 (16:15 +0000)
code is MP safe and moves from ip6_local() to ip6_ours().  If there
are any options, store the chain offset and next protocol in a mbuf
tag.  When dequeuing without tag, it is a regular IPv6 header.  As
mbuf tags degrade performance, use them only if a hop-by-hop header
is present.  Such packets are rare and pf drops them by default.
OK mvs@

sys/netinet/ip_input.c
sys/netinet6/ip6_input.c
sys/sys/mbuf.h

index 4ff6882..1a4e2d8 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ip_input.c,v 1.378 2022/08/12 14:49:15 bluhm Exp $    */
+/*     $OpenBSD: ip_input.c,v 1.379 2022/08/15 16:15:36 bluhm Exp $    */
 /*     $NetBSD: ip_input.c,v 1.30 1996/03/16 23:53:58 christos Exp $   */
 
 /*
@@ -560,11 +560,13 @@ ip_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet *ifp)
 int
 ip_local(struct mbuf **mp, int *offp, int nxt, int af)
 {
-       struct ip *ip;
+       if (*offp == 0) {
+               struct ip *ip;
 
-       ip = mtod(*mp, struct ip *);
-       *offp = ip->ip_hl << 2;
-       nxt = ip->ip_p;
+               ip = mtod(*mp, struct ip *);
+               *offp = ip->ip_hl << 2;
+               nxt = ip->ip_p;
+       }
 
        /* Check whether we are already in a IPv4/IPv6 local deliver loop. */
        if (af == AF_UNSPEC)
index 045fb00..6e70de6 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ip6_input.c,v 1.252 2022/08/12 14:49:15 bluhm Exp $   */
+/*     $OpenBSD: ip6_input.c,v 1.253 2022/08/15 16:15:37 bluhm Exp $   */
 /*     $KAME: ip6_input.c,v 1.188 2001/03/29 05:34:31 itojun Exp $     */
 
 /*
@@ -167,6 +167,11 @@ ip6_init(void)
 #endif
 }
 
+struct ip6_offnxt {
+       int     ion_off;
+       int     ion_nxt;
+};
+
 /*
  * Enqueue packet for local delivery.  Queuing is used as a boundary
  * between the network layer (input/forward path) running with
@@ -175,10 +180,37 @@ ip6_init(void)
 int
 ip6_ours(struct mbuf **mp, int *offp, int nxt, int af)
 {
+       /* ip6_hbhchcheck() may be run before, then off and nxt are set */
+       if (*offp == 0) {
+               nxt = ip6_hbhchcheck(mp, offp, NULL);
+               if (nxt == IPPROTO_DONE)
+                       return IPPROTO_DONE;
+       }
+
        /* We are already in a IPv4/IPv6 local deliver loop. */
        if (af != AF_UNSPEC)
                return ip6_local(mp, offp, nxt, af);
 
+       /* save values for later, use after dequeue */
+       if (*offp != sizeof(struct ip6_hdr)) {
+               struct m_tag *mtag;
+               struct ip6_offnxt *ion;
+
+               /* mbuf tags are expensive, but only used for header options */
+               mtag = m_tag_get(PACKET_TAG_IP6_OFFNXT, sizeof(*ion),
+                   M_NOWAIT);
+               if (mtag == NULL) {
+                       ip6stat_inc(ip6s_idropped);
+                       m_freemp(mp);
+                       return IPPROTO_DONE;
+               }
+               ion = (struct ip6_offnxt *)(mtag + 1);
+               ion->ion_off = *offp;
+               ion->ion_nxt = nxt;
+
+               m_tag_prepend(*mp, mtag);
+       }
+
        niq_enqueue(&ip6intrq, *mp);
        *mp = NULL;
        return IPPROTO_DONE;
@@ -584,9 +616,27 @@ ip6_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet *ifp)
 int
 ip6_local(struct mbuf **mp, int *offp, int nxt, int af)
 {
-       nxt = ip6_hbhchcheck(mp, offp, NULL);
-       if (nxt == IPPROTO_DONE)
-               return IPPROTO_DONE;
+       if (*offp == 0) {
+               struct m_tag *mtag;
+
+               mtag = m_tag_find(*mp, PACKET_TAG_IP6_OFFNXT, NULL);
+               if (mtag != NULL) {
+                       struct ip6_offnxt *ion;
+
+                       ion = (struct ip6_offnxt *)(mtag + 1);
+                       *offp = ion->ion_off;
+                       nxt = ion->ion_nxt;
+
+                       m_tag_delete(*mp, mtag);
+               } else {
+                       struct ip6_hdr *ip6;
+
+                       ip6 = mtod(*mp, struct ip6_hdr *);
+                       *offp = sizeof(struct ip6_hdr);
+                       nxt = ip6->ip6_nxt;
+                       
+               }
+       }
 
        /* Check whether we are already in a IPv4/IPv6 local deliver loop. */
        if (af == AF_UNSPEC)
index 7265562..f8eae7a 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: mbuf.h,v 1.254 2022/02/14 04:33:18 dlg Exp $  */
+/*     $OpenBSD: mbuf.h,v 1.255 2022/08/15 16:15:37 bluhm Exp $        */
 /*     $NetBSD: mbuf.h,v 1.19 1996/02/09 18:25:14 christos Exp $       */
 
 /*
@@ -479,6 +479,7 @@ struct m_tag *m_tag_next(struct mbuf *, struct m_tag *);
 #define PACKET_TAG_SRCROUTE            0x1000 /* IPv4 source routing options */
 #define PACKET_TAG_TUNNEL              0x2000  /* Tunnel endpoint address */
 #define PACKET_TAG_CARP_BAL_IP         0x4000  /* carp(4) ip balanced marker */
+#define PACKET_TAG_IP6_OFFNXT          0x8000  /* IPv6 offset and next proto */
 
 #define MTAG_BITS \
     ("\20\1IPSEC_IN_DONE\2IPSEC_OUT_DONE\3IPSEC_FLOWINFO" \