pru_send: Allow non-NULL address parameter to be passed
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Sun, 4 Dec 2011 13:21:51 +0000 (21:21 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Sun, 4 Dec 2011 13:21:51 +0000 (21:21 +0800)
Currently the passed in address is copied into a newly allocated
memory (grr, additional blocking kmalloc), and the PRUS_FREEADDR
will be set so that protocol thread could know when to free the
address.

Before this change netperf UDP_STREAM (unconnected socket) could
only do ~200Kpps (w/ -m 18), now it could do ~990Kpps (w/ -m 18).
This gives ~500% performance improvement for tiny UDP packet TX.
The improvement is not as good as the connected socket, which is
~600%, mainly because of the additional memory allocation for
the address.  We _may_ further optimize out the address allocation.

sys/kern/uipc_msg.c
sys/kern/uipc_socket.c
sys/net/netmsg.h
sys/netinet/tcp_usrreq.c
sys/netinet/udp_usrreq.c

index 4f99828..cb7965d 100644 (file)
@@ -349,17 +349,25 @@ so_pru_sync(struct socket *so)
 
 void
 so_pru_send_async(struct socket *so, int flags, struct mbuf *m,
-           struct sockaddr *addr, struct mbuf *control, struct thread *td)
+           struct sockaddr *addr0, struct mbuf *control, struct thread *td)
 {
        struct netmsg_pru_send *msg;
+       struct sockaddr *addr = NULL;
 
        KASSERT(so->so_proto->pr_flags & PR_ASYNC_SEND,
            ("async pru_send is not supported\n"));
 
+       flags |= PRUS_NOREPLY;
+       if (addr0 != NULL) {
+               addr = kmalloc(addr0->sa_len, M_SONAME, M_WAITOK);
+               memcpy(addr, addr0, addr0->sa_len);
+               flags |= PRUS_FREEADDR;
+       }
+
        msg = &m->m_hdr.mh_sndmsg;
        netmsg_init(&msg->base, so, &netisr_apanic_rport,
                    0, so->so_proto->pr_usrreqs->pru_send);
-       msg->nm_flags = flags | PRUS_NOREPLY;
+       msg->nm_flags = flags;
        msg->nm_m = m;
        msg->nm_addr = addr;
        msg->nm_control = control;
index fb9b5eb..83e43e9 100644 (file)
@@ -940,12 +940,7 @@ restart:
        if (flags & MSG_DONTROUTE)
                pru_flags |= PRUS_DONTROUTE;
 
-       /*
-        * XXX
-        * 'addr' could be free by the caller, so if it is ever supplied
-        * we can't do asynchronized pru_send
-        */
-       if (addr == NULL && udp_sosnd_async && (flags & MSG_SYNC) == 0) {
+       if (udp_sosnd_async && (flags & MSG_SYNC) == 0) {
                so_pru_send_async(so, pru_flags, top, addr, NULL, td);
                error = 0;
        } else {
index a07c730..82c4d48 100644 (file)
@@ -193,6 +193,7 @@ struct netmsg_pru_send {
 #define PRUS_NAMALLOC          0x8
 #define PRUS_NOREPLY           0x10
 #define PRUS_DONTROUTE         0x20
+#define PRUS_FREEADDR          0x40
 
 struct netmsg_pru_sense {
        struct netmsg_base      base;
index e7c3330..31b5ac5 100644 (file)
@@ -731,13 +731,14 @@ tcp_usr_send(netmsg_t msg)
        struct socket *so = msg->send.base.nm_so;
        int flags = msg->send.nm_flags;
        struct mbuf *m = msg->send.nm_m;
-       struct mbuf *control __debugvar = msg->send.nm_control;
        int error = 0;
        struct inpcb *inp;
        struct tcpcb *tp;
        TCPDEBUG0;
 
-       KKASSERT(control == NULL);
+       KKASSERT(msg->send.nm_control == NULL);
+       KKASSERT(msg->send.nm_addr == NULL);
+       KKASSERT((flags & PRUS_FREEADDR) == 0);
 
        inp = so->so_pcb;
 
index 892adeb..24edc09 100644 (file)
@@ -1243,6 +1243,7 @@ udp_send(netmsg_t msg)
 {
        struct socket *so = msg->send.base.nm_so;
        struct mbuf *m = msg->send.nm_m;
+       struct sockaddr *addr = msg->send.nm_addr;
        int pru_flags = msg->send.nm_flags;
        struct inpcb *inp;
        int error;
@@ -1252,7 +1253,6 @@ udp_send(netmsg_t msg)
 
        inp = so->so_pcb;
        if (inp) {
-               struct sockaddr *addr = msg->send.nm_addr;
                struct thread *td = msg->send.nm_td;
                int flags = 0;
 
@@ -1264,6 +1264,9 @@ udp_send(netmsg_t msg)
                error = EINVAL;
        }
 
+       if (pru_flags & PRUS_FREEADDR)
+               kfree(addr, M_SONAME);
+
        if ((pru_flags & PRUS_NOREPLY) == 0)
                lwkt_replymsg(&msg->send.base.lmsg, error);
 }