Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys Rework to make FAST_IPSEC PF_KEY dumps unicast and reli...



details:   https://anonhg.NetBSD.org/src/rev/0dd3c5aa3bad
branches:  trunk
changeset: 567011:0dd3c5aa3bad
user:      jonathan <jonathan%NetBSD.org@localhost>
date:      Thu May 27 19:19:00 2004 +0000

description:
Rework to make  FAST_IPSEC PF_KEY dumps unicast and reliable:

Introduce new socket-layer function sbappendaddrchain() to
sys/kern/uipc_socket2.c: like sbappendaddr(), only takes a chain of
records and appends the entire chain in one pass. sbappendaddrchain()
also takes an `sbprio' argument, which indicates the caller requires
special `reliable' handling of the socket-buffer.  `sbprio' is
described in sys/sys/socketvar.h, although (for now) the different
levels are not yet implemented.

Rework sys/netipsec/key.c PF_KEY DUMP responses to build a chain of
mbuf records, one record per dump response. Unicast the entire chain
to the requestor, with all-or-none semantics.

Changed files;
        sys/socketvar.h kern/uipc_socket2.c netipsec/key.c
Reviewed by:
        Jason Thorpe, Thor Lancelot Simon, post to tech-kern.

Todo: request pullup to 2.0 branch.  Post-2.0, rework sysctl() API for
dumps to use new record-chain constructors. Actually implement
the distinct service levels in sbappendaddrchain() so we can use them
to make PF_KEY ACQUIRE messages more reliable.

diffstat:

 sys/kern/uipc_socket2.c |  114 ++++++++++++++-
 sys/netipsec/key.c      |  355 +++++++++++++++++++++++++++++++++++------------
 sys/sys/socketvar.h     |   30 +++-
 3 files changed, 400 insertions(+), 99 deletions(-)

diffs (truncated from 631 to 300 lines):

diff -r fb003d5f9e20 -r 0dd3c5aa3bad sys/kern/uipc_socket2.c
--- a/sys/kern/uipc_socket2.c   Thu May 27 19:15:10 2004 +0000
+++ b/sys/kern/uipc_socket2.c   Thu May 27 19:19:00 2004 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: uipc_socket2.c,v 1.62 2004/04/19 03:44:46 christos Exp $       */
+/*     $NetBSD: uipc_socket2.c,v 1.63 2004/05/27 19:19:00 jonathan Exp $       */
 
 /*
  * Copyright (c) 1982, 1986, 1988, 1990, 1993
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uipc_socket2.c,v 1.62 2004/04/19 03:44:46 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uipc_socket2.c,v 1.63 2004/05/27 19:19:00 jonathan Exp $");
 
 #include "opt_mbuftrace.h"
 #include "opt_sb_max.h"
@@ -511,15 +511,22 @@
 }
 #endif /* SOCKBUF_DEBUG */
 
-#define        SBLINKRECORD(sb, m0)                                            \
+/*
+ * Link a chain of records onto a socket buffer
+ */
+#define        SBLINKRECORDCHAIN(sb, m0, mlast)                                \
 do {                                                                   \
        if ((sb)->sb_lastrecord != NULL)                                \
                (sb)->sb_lastrecord->m_nextpkt = (m0);                  \
        else                                                            \
                (sb)->sb_mb = (m0);                                     \
-       (sb)->sb_lastrecord = (m0);                                     \
+       (sb)->sb_lastrecord = (mlast);                                  \
 } while (/*CONSTCOND*/0)
 
+
+#define        SBLINKRECORD(sb, m0)                                            \
+    SBLINKRECORDCHAIN(sb, m0, m0)
+
 /*
  * Append mbuf chain m to the last record in the
  * socket buffer sb.  The additional space associated
@@ -764,6 +771,105 @@
        return (1);
 }
 
+/*
+ * Helper for sbappendchainaddr: prepend a struct sockaddr* to
+ * an mbuf chain.
+ */
+static __inline struct mbuf *
+m_prepend_sockaddr(struct mbuf *m0, const struct sockaddr *asa)
+{
+       struct mbuf *m;
+       const int mlen = asa->sa_len;
+
+       /* only the first in each chain need be a pkthdr */
+       MGETHDR(m, M_DONTWAIT, MT_SONAME);
+       if (m == 0)
+               return (0);
+       MCLAIM(m, sb->sb_mowner);
+       KASSERT(mlen <= MLEN);
+
+       m->m_len = mlen;
+       bcopy((caddr_t)asa, mtod(m, caddr_t), mlen);
+       m->m_next = m0;
+       m->m_pkthdr.len = mlen + m0->m_pkthdr.len;
+
+       return m;
+}
+
+int
+sbappendaddrchain(struct sockbuf *sb, const struct sockaddr *asa,
+                 struct mbuf *m0, int sbprio)
+{
+       int space;
+       struct mbuf *m, *n, *n0, *nlast;
+       int error;
+
+       /*
+        * XXX sbprio reserved for encoding priority of this* request:
+        *  SB_PRIO_NONE --> honour normal sb limits
+        *  SB_PRIO_ONESHOT_OVERFLOW --> if socket has any space,
+        *      take whole chain. Intended for large requests
+        *      that should be delivered atomically (all, or none).
+        * SB_PRIO_OVERDRAFT -- allow a small (2*MLEN) overflow
+        *       over normal socket limits, for messages indicating
+        *       buffer overflow in earlier normal/lower-priority messages
+        * SB_PRIO_BESTEFFORT -->  ignore limits entirely.
+        *       Intended for  kernel-generated messages only.
+        *        Up to generator to avoid total mbuf resource exhaustion.
+        */
+       (void)sbprio;
+
+       if (m0 && (m0->m_flags & M_PKTHDR) == 0)
+               panic("sbappendaddrchain");
+
+       space = sbspace(sb);
+       
+#ifdef notyet
+       /* 
+        * Enforce SB_PRIO_* limits as described above.
+        */
+#endif
+
+       n0 = NULL;
+       nlast = NULL;
+       for (m = m0; m; m = m->m_nextpkt) {
+               struct mbuf *np;
+
+               /* Prepend sockaddr to this record (m) of input chain m0 */
+               n = m_prepend_sockaddr(m, asa);
+               if (n == NULL) {
+                       error = ENOBUFS;
+                       goto bad;
+               }
+
+               /* Append record (asa+m) to end of new chain n0 */
+               if (n0 == NULL) {
+                       n0 = n;
+               } else {
+                       nlast->m_nextpkt = n;
+               }
+               /* Keep track of last record on new chain */
+               nlast = n;
+
+               for (np = n; np; np = np->m_next)
+                       sballoc(sb, np);
+       }
+
+       /* Drop the entire chain of (asa+m) records onto the socket */
+       SBLINKRECORDCHAIN(sb, n0, nlast);
+       for (m = nlast; m->m_next; m = m->m_next)
+               ;
+       sb->sb_mbtail = m;
+       
+       return (1);
+
+bad:
+       if (n)
+               m_freem(n);
+       return 0;       
+}
+
+
 int
 sbappendcontrol(struct sockbuf *sb, struct mbuf *m0, struct mbuf *control)
 {
diff -r fb003d5f9e20 -r 0dd3c5aa3bad sys/netipsec/key.c
--- a/sys/netipsec/key.c        Thu May 27 19:15:10 2004 +0000
+++ b/sys/netipsec/key.c        Thu May 27 19:19:00 2004 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: key.c,v 1.18 2004/05/26 23:16:25 jonathan Exp $        */
+/*     $NetBSD: key.c,v 1.19 2004/05/27 19:19:00 jonathan Exp $        */
 /*     $FreeBSD: src/sys/netipsec/key.c,v 1.3.2.3 2004/02/14 22:23:23 bms Exp $        */
 /*     $KAME: key.c,v 1.191 2001/06/27 10:46:49 sakane Exp $   */
 
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: key.c,v 1.18 2004/05/26 23:16:25 jonathan Exp $");
+__KERNEL_RCSID(0, "$NetBSD: key.c,v 1.19 2004/05/27 19:19:00 jonathan Exp $");
 
 /*
  * This code is referd to RFC 2367
@@ -385,6 +385,8 @@
        const struct sadb_msghdr *));
 static int key_spddump __P((struct socket *, struct mbuf *,
        const struct sadb_msghdr *));
+static struct mbuf * key_setspddump __P((int *errorp));
+static struct mbuf * key_setspddump_chain __P((int *errorp, int *lenp));
 static struct mbuf *key_setdumpsp __P((struct secpolicy *,
        u_int8_t, u_int32_t, u_int32_t));
 static u_int key_getspreqmsglen __P((struct secpolicy *));
@@ -477,6 +479,8 @@
 static int key_expire __P((struct secasvar *));
 static int key_flush __P((struct socket *, struct mbuf *,
        const struct sadb_msghdr *));
+static struct mbuf *key_setdump_chain __P((u_int8_t req_satype, int *errorp,
+       int *lenp));
 static int key_dump __P((struct socket *, struct mbuf *,
        const struct sadb_msghdr *));
 static int key_promisc __P((struct socket *, struct mbuf *,
@@ -2390,6 +2394,61 @@
        return key_sendup_mbuf(so, m, KEY_SENDUP_ALL);
 }
 
+static struct sockaddr key_src = { 2, PF_KEY, };
+
+static struct mbuf *
+key_setspddump_chain(int *errorp, int *lenp)
+{
+       struct secpolicy *sp;
+       int cnt;
+       u_int dir;
+       struct mbuf *m, *n, *prev;
+       int totlen;
+
+       *lenp = 0;
+
+       /* search SPD entry and get buffer size. */
+       cnt = 0;
+       for (dir = 0; dir < IPSEC_DIR_MAX; dir++) {
+               LIST_FOREACH(sp, &sptree[dir], chain) {
+                       cnt++;
+               }
+       }
+
+       if (cnt == 0) {
+               *errorp = ENOENT;
+               return (NULL);
+       }
+
+       m = NULL;
+       prev = m;
+       totlen = 0;
+       for (dir = 0; dir < IPSEC_DIR_MAX; dir++) {
+               LIST_FOREACH(sp, &sptree[dir], chain) {
+                       --cnt;
+                       n = key_setdumpsp(sp, SADB_X_SPDDUMP, cnt, 0);
+
+                       if (!n) {
+                               *errorp = ENOBUFS;
+                               if (m) m_freem(m);
+                               return (NULL);
+                       }
+
+                       totlen += n->m_pkthdr.len;
+                       if (!m) {
+                               m = n;
+                       } else {
+                               prev->m_nextpkt = n;
+                       }
+                       prev = n;
+               }
+       }
+
+       *lenp = totlen;
+       *errorp = 0;
+       return (m);
+}
+
 /*
  * SADB_SPDDUMP processing
  * receive
@@ -2402,44 +2461,65 @@
  * m will always be freed.
  */
 static int
-key_spddump(so, m, mhp)
+key_spddump(so, m0, mhp)
        struct socket *so;
-       struct mbuf *m;
+       struct mbuf *m0;
        const struct sadb_msghdr *mhp;
 {
-       struct secpolicy *sp;
-       int cnt;
-       u_int dir;
        struct mbuf *n;
+       int error, len;
+       int ok, s;
 
        /* sanity check */
-       if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
+       if (so == NULL || m0 == NULL || mhp == NULL || mhp->msg == NULL)
                panic("key_spddump: NULL pointer is passed.\n");
 
-       /* search SPD entry and get buffer size. */
-       cnt = 0;
-       for (dir = 0; dir < IPSEC_DIR_MAX; dir++) {
-               LIST_FOREACH(sp, &sptree[dir], chain) {
-                       cnt++;
-               }
-       }
-
-       if (cnt == 0)
-               return key_senderror(so, m, ENOENT);
-
-       for (dir = 0; dir < IPSEC_DIR_MAX; dir++) {
-               LIST_FOREACH(sp, &sptree[dir], chain) {
-                       --cnt;
-                       n = key_setdumpsp(sp, SADB_X_SPDDUMP, cnt,
-                           mhp->msg->sadb_msg_pid);
-
-                       if (n)
-                               key_sendup_mbuf(so, n, KEY_SENDUP_ONE);
-               }
-       }
-
-       m_freem(m);
-       return 0;
+
+       /*
+        * If the requestor has insufficient socket-buffer space
+        * for the entire chain, nobody gets any response to the DUMP.
+        * XXX For now, only the requestor ever gets anything.
+        * Moreover, if the requestor has any space at all, they receive



Home | Main Index | Thread Index | Old Index