socket: Provide socket owner cpuid hint
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Thu, 25 Sep 2014 13:51:14 +0000 (21:51 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Sun, 28 Sep 2014 12:49:12 +0000 (20:49 +0800)
If the cpuid hint could not be provided or the cpuid hint does not make
sense, -1 will be returned as cpuid hint, e.g. TCP listen sockets w/o
SO_REUSEPORT.

This helps avoiding unnecessary IPIs and contention on receiving sockbuf
token.

sys/kern/uipc_socket.c
sys/netinet/ip_output.c
sys/netinet/raw_ip.c
sys/netinet/tcp_usrreq.c
sys/sys/socket.h

index e2f8bf4..9e33a1a 100644 (file)
@@ -2439,10 +2439,16 @@ integer:
                        error = sooptcopyout(sopt, &optval_l, sizeof(optval_l));
                        break;
 
+               case SO_CPUHINT:
+                       optval = -1; /* no hint */
+                       goto integer;
+
                default:
                        error = ENOPROTOOPT;
                        break;
                }
+               if (error == 0 && so->so_proto && so->so_proto->pr_ctloutput)
+                       so_pr_ctloutput(so, sopt);
                return (error);
        }
 }
index 4a35ce2..cac869e 100644 (file)
@@ -1343,6 +1343,16 @@ ip_ctloutput(netmsg_t msg)
        int     error, optval;
 
        error = optval = 0;
+
+       /* Get socket's owner cpuid hint */
+       if (sopt->sopt_level == SOL_SOCKET &&
+           sopt->sopt_dir == SOPT_GET &&
+           sopt->sopt_name == SO_CPUHINT) {
+               optval = mycpuid;
+               soopt_from_kbuf(sopt, &optval, sizeof(optval));
+               goto done;
+       }
+
        if (sopt->sopt_level != IPPROTO_IP) {
                error = EINVAL;
                goto done;
index cdbab95..cc242a3 100644 (file)
@@ -352,13 +352,22 @@ rip_ctloutput(netmsg_t msg)
        KASSERT(&curthread->td_msgport == netisr_cpuport(0),
            ("not in netisr0"));
 
+       error = 0;
+
+       /* Get socket's owner cpuid hint */
+       if (sopt->sopt_level == SOL_SOCKET &&
+           sopt->sopt_dir == SOPT_GET &&
+           sopt->sopt_name == SO_CPUHINT) {
+               optval = mycpuid;
+               soopt_from_kbuf(sopt, &optval, sizeof(optval));
+               goto done;
+       }
+
        if (sopt->sopt_level != IPPROTO_IP) {
                error = EINVAL;
                goto done;
        }
 
-       error = 0;
-
        switch (sopt->sopt_dir) {
        case SOPT_GET:
                switch (sopt->sopt_name) {
index f792017..aa6dcfb 100644 (file)
@@ -1418,6 +1418,28 @@ tcp_ctloutput(netmsg_t msg)
                error = ECONNRESET;
                goto done;
        }
+       tp = intotcpcb(inp);
+
+       /* Get socket's owner cpuid hint */
+       if (sopt->sopt_level == SOL_SOCKET &&
+           sopt->sopt_dir == SOPT_GET &&
+           sopt->sopt_name == SO_CPUHINT) {
+               if (tp->t_flags & TF_LISTEN) {
+                       /*
+                        * Listen sockets owner cpuid is always 0,
+                        * which does not make sense if SO_REUSEPORT
+                        * is not set.
+                        */
+                       if (so->so_options & SO_REUSEPORT)
+                               optval = (inp->inp_lgrpindex & ncpus2_mask);
+                       else
+                               optval = -1; /* no hint */
+               } else {
+                       optval = mycpuid;
+               }
+               soopt_from_kbuf(sopt, &optval, sizeof(optval));
+               goto done;
+       }
 
        if (sopt->sopt_level != IPPROTO_TCP) {
                switch (sopt->sopt_name) {
@@ -1442,7 +1464,6 @@ tcp_ctloutput(netmsg_t msg)
                /* msg invalid now */
                return;
        }
-       tp = intotcpcb(inp);
 
        switch (sopt->sopt_dir) {
        case SOPT_SET:
index 9d65049..5426a13 100644 (file)
@@ -100,8 +100,10 @@ typedef __socklen_t        socklen_t;
 #define SO_RCVTIMEO    0x1006          /* receive timeout */
 #define        SO_ERROR        0x1007          /* get error status and clear */
 #define        SO_TYPE         0x1008          /* get socket type */
-/*efine        SO_PRIVSTATE    0x1009             get/deny privileged state */
+/* 0x1009 reserved for FreeBSD compat */
 #define        SO_SNDSPACE     0x100a          /* get appr. send buffer free space */
+/* 0x1010 ~ 0x102f reserved for FreeBSD compat */
+#define        SO_CPUHINT      0x1030          /* get socket's owner cpuid hint */
 
 /*
  * Structure used for manipulating linger option.