DF-3484 / ngrace.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | /* ngrace.c -- DF-3484 hammer: multi-CPU producers into the single global * v1 netgraph queue (ngqbase/ngqlast under crit_enter only). * Each instance: ctrl socket (own node) + data socket, mkpeer echo via * generic NGM_MKPEER, then N writes to the data socket addressed to hook * "e0" (each write -> ngd_send -> ng_queue_data; echo reply -> another). * Run 2+ instances concurrently on different CPUs; watch netstat -m drift. * usage: ngrace <iters> */ #include <sys/types.h> #include <sys/socket.h> #include <netgraph/ng_message.h> #include <netgraph/socket/ng_socket.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <stddef.h> #include <errno.h> #include <err.h> static int cs, ds; static void mkpeer_ctrl(const char *type, const char *ourhook, const char *peerhook) { static char mbuf[512]; struct ng_mesg *msg = (struct ng_mesg *)mbuf; struct sockaddr_ng dst; struct iovec iov[2]; struct msghdr mhdr; struct ngm_mkpeer mk; int t; memset(&mk, 0, sizeof(mk)); strcpy(mk.type, type); strcpy(mk.ourhook, ourhook); strcpy(mk.peerhook, peerhook); memset(msg, 0, sizeof(*msg) + sizeof(mk)); msg->header.version = NG_VERSION; msg->header.typecookie = 851672668; msg->header.cmd = 2; msg->header.arglen = sizeof(mk); memcpy(msg->data, &mk, sizeof(mk)); memset(&dst, 0, sizeof(dst)); dst.sg_len = offsetof(struct sockaddr_ng, sg_data) + 1; dst.sg_family = AF_NETGRAPH; dst.sg_data[0] = 0; iov[0].iov_base = (caddr_t)&msg->header; iov[0].iov_len = sizeof(struct ng_msghdr); iov[1].iov_base = (caddr_t)msg->data; iov[1].iov_len = sizeof(mk); memset(&mhdr, 0, sizeof(mhdr)); mhdr.msg_name = (caddr_t)&dst; mhdr.msg_namelen = dst.sg_len; mhdr.msg_iov = iov; mhdr.msg_iovlen = 2; if (sendmsg(cs, &mhdr, 0) < 0) err(1, "mkpeer"); { struct timeval tv = {0, 200000}; setsockopt(cs, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); read(cs, mbuf, sizeof(mbuf)); } (void)t; } int main(int argc, char **argv) { long i, n = argc > 1 ? atol(argv[1]) : 100000; char buf[256]; struct sockaddr_ng dst; ssize_t r; static const char *myname; cs = socket(AF_NETGRAPH, SOCK_DGRAM, NG_CONTROL); if (cs < 0) err(1, "socket ctrl"); { struct timeval tvz = {0, 300000}; setsockopt(cs, SOL_SOCKET, SO_RCVTIMEO, &tvz, sizeof(tvz)); } ds = socket(AF_NETGRAPH, SOCK_DGRAM, NG_DATA); if (ds < 0) err(1, "socket data"); { struct timeval tvz = {0, 500000}; setsockopt(ds, SOL_SOCKET, SO_SNDTIMEO, &tvz, sizeof(tvz)); } /* name our own node first (path "" = self) */ { static char nb[512]; struct ng_mesg *msg = (struct ng_mesg *)nb; struct ngm_name nm; struct sockaddr_ng d2; struct iovec iov[2]; struct msghdr mh; char nmbuf[32]; snprintf(nmbuf, sizeof(nmbuf), "ng%d", (int)getpid()); myname = strdup(nmbuf); memset(&nm, 0, sizeof(nm)); strlcpy(nm.name, nmbuf, sizeof(nm.name)); memset(msg, 0, sizeof(*msg) + sizeof(nm)); msg->header.version = NG_VERSION; msg->header.typecookie = 851672668; msg->header.cmd = 4; msg->header.arglen = sizeof(nm); memcpy(msg->data, &nm, sizeof(nm)); memset(&d2, 0, sizeof(d2)); d2.sg_len = offsetof(struct sockaddr_ng, sg_data) + 1; d2.sg_family = AF_NETGRAPH; d2.sg_data[0] = 0; iov[0].iov_base = (caddr_t)&msg->header; iov[0].iov_len = sizeof(struct ng_msghdr); iov[1].iov_base = (caddr_t)msg->data; iov[1].iov_len = sizeof(nm); memset(&mh, 0, sizeof(mh)); mh.msg_name = (caddr_t)&d2; mh.msg_namelen = d2.sg_len; mh.msg_iov = iov; mh.msg_iovlen = 2; if (sendmsg(cs, &mh, 0) < 0) err(1, "self-name sendmsg"); read(cs, nb, sizeof(nb)); } mkpeer_ctrl("echo", "e0", "e0"); /* drain data socket */ memset(&dst, 0, sizeof(dst)); dst.sg_len = offsetof(struct sockaddr_ng, sg_data) + strlen(myname) + 1; dst.sg_family = AF_NETGRAPH; strcpy(dst.sg_data, myname); if (connect(ds, (struct sockaddr *)&dst, dst.sg_len) < 0) err(1, "connect data"); /* per-send hook address */ memset(&dst, 0, sizeof(dst)); dst.sg_len = offsetof(struct sockaddr_ng, sg_data) + strlen("e0") + 1; dst.sg_family = AF_NETGRAPH; strcpy(dst.sg_data, "e0"); for (i = 0; i < n; i++) { if (send(ds, buf, sizeof(buf), 0) < 0) { if (errno == ENOBUFS || errno == ENOMEM) continue; err(1, "sendto"); } /* drain the echo replies so rcvbuf does not fill */ r = recv(ds, buf, sizeof(buf), MSG_DONTWAIT); (void)r; } printf("NGRACE-DONE %ld sends\n", n); return (0); } |