Whamcloud - gitweb
* fix for 5890: different compilers produce different wire struct offsets
authoreeb <eeb>
Thu, 17 Mar 2005 19:16:17 +0000 (19:16 +0000)
committereeb <eeb>
Thu, 17 Mar 2005 19:16:17 +0000 (19:16 +0000)
    This gives vibnal its own wirecheck utility and adds compile-time
    assertions to vibnal to ensure all platforms agree.

lnet/klnds/viblnd/.cvsignore
lnet/klnds/viblnd/viblnd.c
lnet/klnds/viblnd/viblnd.h
lnet/klnds/viblnd/viblnd_wire.h [new file with mode: 0644]
lnet/klnds/viblnd/wirecheck.c [new file with mode: 0644]

index 5ed596b..2e9b6f4 100644 (file)
@@ -8,3 +8,4 @@ autoMakefile
 .*.flags
 .tmp_versions
 .depend
+wirecheck
index d54d4c8..73542fa 100644 (file)
@@ -47,6 +47,131 @@ static ctl_table kibnal_top_ctl_table[] = {
 };
 #endif
 
+void vibnal_assert_wire_constants (void)
+{
+        /* Wire protocol assertions generated by 'wirecheck'
+         * running on Linux robert.bartonsoftware.com 2.6.5-1.358 #1 Sat May 8 09:04:50 EDT 2004 i686
+         * with gcc version 3.3.3 20040412 (Red Hat Linux 3.3.3-7) */
+
+
+        /* Constants... */
+        CLASSERT (IBNAL_MSG_MAGIC == 0x0be91b91);
+        CLASSERT (IBNAL_MSG_VERSION == 5);
+        CLASSERT (IBNAL_MSG_CONNREQ == 0xc0);
+        CLASSERT (IBNAL_MSG_CONNACK == 0xc1);
+        CLASSERT (IBNAL_MSG_NOOP == 0xd0);
+        CLASSERT (IBNAL_MSG_IMMEDIATE == 0xd1);
+        CLASSERT (IBNAL_MSG_PUT_REQ == 0xd2);
+        CLASSERT (IBNAL_MSG_PUT_NAK == 0xd3);
+        CLASSERT (IBNAL_MSG_PUT_ACK == 0xd4);
+        CLASSERT (IBNAL_MSG_PUT_DONE == 0xd5);
+        CLASSERT (IBNAL_MSG_GET_REQ == 0xd6);
+        CLASSERT (IBNAL_MSG_GET_DONE == 0xd7);
+
+        /* Checks for struct kib_connparams_t */
+        CLASSERT ((int)sizeof(kib_connparams_t) == 12);
+        CLASSERT ((int)offsetof(kib_connparams_t, ibcp_queue_depth) == 0);
+        CLASSERT ((int)sizeof(((kib_connparams_t *)0)->ibcp_queue_depth) == 4);
+        CLASSERT ((int)offsetof(kib_connparams_t, ibcp_max_msg_size) == 4);
+        CLASSERT ((int)sizeof(((kib_connparams_t *)0)->ibcp_max_msg_size) == 4);
+        CLASSERT ((int)offsetof(kib_connparams_t, ibcp_max_frags) == 8);
+        CLASSERT ((int)sizeof(((kib_connparams_t *)0)->ibcp_max_frags) == 4);
+
+        /* Checks for struct kib_immediate_msg_t */
+        CLASSERT ((int)sizeof(kib_immediate_msg_t) == 72);
+        CLASSERT ((int)offsetof(kib_immediate_msg_t, ibim_hdr) == 0);
+        CLASSERT ((int)sizeof(((kib_immediate_msg_t *)0)->ibim_hdr) == 72);
+        CLASSERT ((int)offsetof(kib_immediate_msg_t, ibim_payload[13]) == 85);
+        CLASSERT ((int)sizeof(((kib_immediate_msg_t *)0)->ibim_payload[13]) == 1);
+
+        /* Checks for struct kib_rdma_frag_t */
+        CLASSERT ((int)sizeof(kib_rdma_frag_t) == 12);
+        CLASSERT ((int)offsetof(kib_rdma_frag_t, rf_nob) == 0);
+        CLASSERT ((int)sizeof(((kib_rdma_frag_t *)0)->rf_nob) == 4);
+        CLASSERT ((int)offsetof(kib_rdma_frag_t, rf_addr_lo) == 4);
+        CLASSERT ((int)sizeof(((kib_rdma_frag_t *)0)->rf_addr_lo) == 4);
+        CLASSERT ((int)offsetof(kib_rdma_frag_t, rf_addr_hi) == 8);
+        CLASSERT ((int)sizeof(((kib_rdma_frag_t *)0)->rf_addr_hi) == 4);
+
+        /* Checks for struct kib_rdma_desc_t */
+        CLASSERT ((int)sizeof(kib_rdma_desc_t) == 8);
+        CLASSERT ((int)offsetof(kib_rdma_desc_t, rd_key) == 0);
+        CLASSERT ((int)sizeof(((kib_rdma_desc_t *)0)->rd_key) == 4);
+        CLASSERT ((int)offsetof(kib_rdma_desc_t, rd_nfrag) == 4);
+        CLASSERT ((int)sizeof(((kib_rdma_desc_t *)0)->rd_nfrag) == 4);
+        CLASSERT ((int)offsetof(kib_rdma_desc_t, rd_frags[13]) == 164);
+        CLASSERT ((int)sizeof(((kib_rdma_desc_t *)0)->rd_frags[13]) == 12);
+
+        /* Checks for struct kib_putreq_msg_t */
+        CLASSERT ((int)sizeof(kib_putreq_msg_t) == 80);
+        CLASSERT ((int)offsetof(kib_putreq_msg_t, ibprm_hdr) == 0);
+        CLASSERT ((int)sizeof(((kib_putreq_msg_t *)0)->ibprm_hdr) == 72);
+        CLASSERT ((int)offsetof(kib_putreq_msg_t, ibprm_cookie) == 72);
+        CLASSERT ((int)sizeof(((kib_putreq_msg_t *)0)->ibprm_cookie) == 8);
+
+        /* Checks for struct kib_putack_msg_t */
+        CLASSERT ((int)sizeof(kib_putack_msg_t) == 24);
+        CLASSERT ((int)offsetof(kib_putack_msg_t, ibpam_src_cookie) == 0);
+        CLASSERT ((int)sizeof(((kib_putack_msg_t *)0)->ibpam_src_cookie) == 8);
+        CLASSERT ((int)offsetof(kib_putack_msg_t, ibpam_dst_cookie) == 8);
+        CLASSERT ((int)sizeof(((kib_putack_msg_t *)0)->ibpam_dst_cookie) == 8);
+        CLASSERT ((int)offsetof(kib_putack_msg_t, ibpam_rd) == 16);
+        CLASSERT ((int)sizeof(((kib_putack_msg_t *)0)->ibpam_rd) == 8);
+
+        /* Checks for struct kib_get_msg_t */
+        CLASSERT ((int)sizeof(kib_get_msg_t) == 88);
+        CLASSERT ((int)offsetof(kib_get_msg_t, ibgm_hdr) == 0);
+        CLASSERT ((int)sizeof(((kib_get_msg_t *)0)->ibgm_hdr) == 72);
+        CLASSERT ((int)offsetof(kib_get_msg_t, ibgm_cookie) == 72);
+        CLASSERT ((int)sizeof(((kib_get_msg_t *)0)->ibgm_cookie) == 8);
+        CLASSERT ((int)offsetof(kib_get_msg_t, ibgm_rd) == 80);
+        CLASSERT ((int)sizeof(((kib_get_msg_t *)0)->ibgm_rd) == 8);
+
+        /* Checks for struct kib_completion_msg_t */
+        CLASSERT ((int)sizeof(kib_completion_msg_t) == 16);
+        CLASSERT ((int)offsetof(kib_completion_msg_t, ibcm_cookie) == 0);
+        CLASSERT ((int)sizeof(((kib_completion_msg_t *)0)->ibcm_cookie) == 8);
+        CLASSERT ((int)offsetof(kib_completion_msg_t, ibcm_status) == 8);
+        CLASSERT ((int)sizeof(((kib_completion_msg_t *)0)->ibcm_status) == 4);
+
+        /* Checks for struct kib_msg_t */
+        CLASSERT ((int)sizeof(kib_msg_t) == 144);
+        CLASSERT ((int)offsetof(kib_msg_t, ibm_magic) == 0);
+        CLASSERT ((int)sizeof(((kib_msg_t *)0)->ibm_magic) == 4);
+        CLASSERT ((int)offsetof(kib_msg_t, ibm_version) == 4);
+        CLASSERT ((int)sizeof(((kib_msg_t *)0)->ibm_version) == 2);
+        CLASSERT ((int)offsetof(kib_msg_t, ibm_type) == 6);
+        CLASSERT ((int)sizeof(((kib_msg_t *)0)->ibm_type) == 1);
+        CLASSERT ((int)offsetof(kib_msg_t, ibm_credits) == 7);
+        CLASSERT ((int)sizeof(((kib_msg_t *)0)->ibm_credits) == 1);
+        CLASSERT ((int)offsetof(kib_msg_t, ibm_nob) == 8);
+        CLASSERT ((int)sizeof(((kib_msg_t *)0)->ibm_nob) == 4);
+        CLASSERT ((int)offsetof(kib_msg_t, ibm_cksum) == 12);
+        CLASSERT ((int)sizeof(((kib_msg_t *)0)->ibm_cksum) == 4);
+        CLASSERT ((int)offsetof(kib_msg_t, ibm_srcnid) == 16);
+        CLASSERT ((int)sizeof(((kib_msg_t *)0)->ibm_srcnid) == 8);
+        CLASSERT ((int)offsetof(kib_msg_t, ibm_srcstamp) == 24);
+        CLASSERT ((int)sizeof(((kib_msg_t *)0)->ibm_srcstamp) == 8);
+        CLASSERT ((int)offsetof(kib_msg_t, ibm_dstnid) == 32);
+        CLASSERT ((int)sizeof(((kib_msg_t *)0)->ibm_dstnid) == 8);
+        CLASSERT ((int)offsetof(kib_msg_t, ibm_dststamp) == 40);
+        CLASSERT ((int)sizeof(((kib_msg_t *)0)->ibm_dststamp) == 8);
+        CLASSERT ((int)offsetof(kib_msg_t, ibm_seq) == 48);
+        CLASSERT ((int)sizeof(((kib_msg_t *)0)->ibm_seq) == 8);
+        CLASSERT ((int)offsetof(kib_msg_t, ibm_u.connparams) == 56);
+        CLASSERT ((int)sizeof(((kib_msg_t *)0)->ibm_u.connparams) == 12);
+        CLASSERT ((int)offsetof(kib_msg_t, ibm_u.immediate) == 56);
+        CLASSERT ((int)sizeof(((kib_msg_t *)0)->ibm_u.immediate) == 72);
+        CLASSERT ((int)offsetof(kib_msg_t, ibm_u.putreq) == 56);
+        CLASSERT ((int)sizeof(((kib_msg_t *)0)->ibm_u.putreq) == 80);
+        CLASSERT ((int)offsetof(kib_msg_t, ibm_u.putack) == 56);
+        CLASSERT ((int)sizeof(((kib_msg_t *)0)->ibm_u.putack) == 24);
+        CLASSERT ((int)offsetof(kib_msg_t, ibm_u.get) == 56);
+        CLASSERT ((int)sizeof(((kib_msg_t *)0)->ibm_u.get) == 88);
+        CLASSERT ((int)offsetof(kib_msg_t, ibm_u.completion) == 56);
+        CLASSERT ((int)sizeof(((kib_msg_t *)0)->ibm_u.completion) == 16);
+}
+
 void
 kibnal_pause(int ticks)
 {
@@ -185,10 +310,7 @@ kibnal_unpack_msg(kib_msg_t *msg, int nob)
                 break;
 
         case IBNAL_MSG_PUT_REQ:
-                /* CAVEAT EMPTOR!  We don't actually put ibprm_rd on the wire;
-                 * it's just there to remember the source buffers while we wait
-                 * for the PUT_ACK */
-                if (msg_nob < offsetof(kib_msg_t, ibm_u.putreq.ibprm_rd)) {
+                if (msg_nob < sizeof(msg->ibm_u.putreq)) {
                         CERROR("Short PUT_REQ: %d(%d)\n", msg_nob,
                                (int)(hdr_size + sizeof(msg->ibm_u.putreq)));
                         return -EPROTO;
@@ -1778,6 +1900,8 @@ kibnal_module_init (void)
 {
         int    rc;
 
+        vibnal_assert_wire_constants();
+
         CLASSERT (offsetof(kib_msg_t, ibm_u) + sizeof(kib_connparams_t) 
                   <= cm_REQ_priv_data_len);
         CLASSERT (offsetof(kib_msg_t, ibm_u) + sizeof(kib_connparams_t) 
index c19a903..46d3be6 100644 (file)
@@ -260,110 +260,7 @@ typedef struct
 #define IBNAL_INIT_CQ              7
 #define IBNAL_INIT_ALL             8
 
-/************************************************************************
- * IB Wire message format.
- * These are sent in sender's byte order (i.e. receiver flips).
- */
-
-typedef struct kib_connparams
-{
-        __u32             ibcp_queue_depth;
-        __u32             ibcp_max_msg_size;
-        __u32             ibcp_max_frags;
-} kib_connparams_t __attribute__((packed));
-
-typedef struct
-{
-        ptl_hdr_t         ibim_hdr;             /* portals header */
-        char              ibim_payload[0];      /* piggy-backed payload */
-} kib_immediate_msg_t __attribute__((packed));
-
-/* YEUCH! the __u64 address is split into 2 __u32 fields to ensure proper
- * packing.  Otherwise we can't fit enough frags into an IBNAL message (<=
- * smallest page size on any arch). */
-typedef struct
-{
-        __u32             rf_nob;               /* # of bytes */
-        __u32             rf_addr_lo;           /* lo 4 bytes of vaddr */
-        __u32             rf_addr_hi;           /* hi 4 bytes of vaddr */
-} kib_rdma_frag_t __attribute__((packed));
-
-typedef struct
-{
-        __u32             rd_key;               /* local/remote key */
-        __u32             rd_nfrag;             /* # fragments */
-        kib_rdma_frag_t   rd_frags[0];          /* buffer frags */
-} kib_rdma_desc_t __attribute__((packed));
-
-/* CAVEAT EMPTOR!  We don't actually put ibprm_rd on the wire; it's just there
- * to remember the source buffers while we wait for the PUT_ACK */
-
-typedef struct
-{
-        ptl_hdr_t         ibprm_hdr;            /* portals header */
-        __u64             ibprm_cookie;         /* opaque completion cookie */
-        kib_rdma_frag_t   ibprm_rd;             /* source buffer */
-} kib_putreq_msg_t __attribute__((packed));
-
-typedef struct
-{
-        __u64             ibpam_src_cookie;     /* reflected completion cookie */
-        __u64             ibpam_dst_cookie;     /* opaque completion cookie */
-        kib_rdma_desc_t   ibpam_rd;             /* sender's sink buffer */
-} kib_putack_msg_t __attribute__((packed));
-
-typedef struct
-{
-        ptl_hdr_t         ibgm_hdr;             /* portals header */
-        __u64             ibgm_cookie;          /* opaque completion cookie */
-        kib_rdma_desc_t   ibgm_rd;              /* rdma descriptor */
-} kib_get_msg_t __attribute__((packed));
-
-typedef struct
-{
-        __u64             ibcm_cookie;          /* opaque completion cookie */
-        __s32             ibcm_status;          /* < 0 failure: >= 0 length */
-} kib_completion_msg_t __attribute__((packed));
-
-typedef struct
-{
-        /* First 2 fields fixed FOR ALL TIME */
-        __u32             ibm_magic;            /* I'm an openibnal message */
-        __u16             ibm_version;          /* this is my version number */
-
-        __u8              ibm_type;             /* msg type */
-        __u8              ibm_credits;          /* returned credits */
-        __u32             ibm_nob;              /* # bytes in whole message */
-        __u32             ibm_cksum;            /* checksum (0 == no checksum) */
-        __u64             ibm_srcnid;           /* sender's NID */
-        __u64             ibm_srcstamp;         /* sender's incarnation */
-        __u64             ibm_dstnid;           /* destination's NID */
-        __u64             ibm_dststamp;         /* destination's incarnation */
-        __u64             ibm_seq;              /* sequence number */
-
-        union {
-                kib_connparams_t      connparams;
-                kib_immediate_msg_t   immediate;
-                kib_putreq_msg_t      putreq;
-                kib_putack_msg_t      putack;
-                kib_get_msg_t         get;
-                kib_completion_msg_t  completion;
-        } ibm_u __attribute__((packed));
-} kib_msg_t __attribute__((packed));
-
-#define IBNAL_MSG_MAGIC       0x0be91b91        /* unique magic */
-#define IBNAL_MSG_VERSION              4        /* current protocol version */
-
-#define IBNAL_MSG_CONNREQ           0xc0        /* connection request */
-#define IBNAL_MSG_CONNACK           0xc1        /* connection acknowledge */
-#define IBNAL_MSG_NOOP              0xd0        /* nothing (just credits) */
-#define IBNAL_MSG_IMMEDIATE         0xd1        /* immediate */
-#define IBNAL_MSG_PUT_REQ           0xd2        /* putreq (src->sink) */
-#define IBNAL_MSG_PUT_NAK           0xd3        /* completion (sink->src) */
-#define IBNAL_MSG_PUT_ACK           0xd4        /* putack (sink->src) */
-#define IBNAL_MSG_PUT_DONE          0xd5        /* completion (src->sink) */
-#define IBNAL_MSG_GET_REQ           0xd6        /* getreq (sink->src) */
-#define IBNAL_MSG_GET_DONE          0xd7        /* completion (src->sink: all OK) */
+#include "vibnal_wire.h"
 
 /***********************************************************************/
 
diff --git a/lnet/klnds/viblnd/viblnd_wire.h b/lnet/klnds/viblnd/viblnd_wire.h
new file mode 100644 (file)
index 0000000..cd1ba5f
--- /dev/null
@@ -0,0 +1,104 @@
+/************************************************************************
+ * IB Wire message format.
+ * These are sent in sender's byte order (i.e. receiver flips).
+ */
+
+typedef struct kib_connparams
+{
+        __u32             ibcp_queue_depth;
+        __u32             ibcp_max_msg_size;
+        __u32             ibcp_max_frags;
+} kib_connparams_t __attribute__((packed));
+
+typedef struct
+{
+        ptl_hdr_t         ibim_hdr;             /* portals header */
+        char              ibim_payload[0];      /* piggy-backed payload */
+} kib_immediate_msg_t __attribute__((packed));
+
+/* YEUCH! the __u64 address is split into 2 __u32 fields to ensure proper
+ * packing.  Otherwise we can't fit enough frags into an IBNAL message (<=
+ * smallest page size on any arch). */
+typedef struct
+{
+        __u32             rf_nob;               /* # of bytes */
+        __u32             rf_addr_lo;           /* lo 4 bytes of vaddr */
+        __u32             rf_addr_hi;           /* hi 4 bytes of vaddr */
+} kib_rdma_frag_t __attribute__((packed));
+
+typedef struct
+{
+        __u32             rd_key;               /* local/remote key */
+        __u32             rd_nfrag;             /* # fragments */
+        kib_rdma_frag_t   rd_frags[0];          /* buffer frags */
+} kib_rdma_desc_t __attribute__((packed));
+
+/* CAVEAT EMPTOR!  We don't actually put ibprm_rd on the wire; it's just there
+ * to remember the source buffers while we wait for the PUT_ACK */
+
+typedef struct
+{
+        ptl_hdr_t         ibprm_hdr;            /* portals header */
+        __u64             ibprm_cookie;         /* opaque completion cookie */
+} kib_putreq_msg_t __attribute__((packed));
+
+typedef struct
+{
+        __u64             ibpam_src_cookie;     /* reflected completion cookie */
+        __u64             ibpam_dst_cookie;     /* opaque completion cookie */
+        kib_rdma_desc_t   ibpam_rd;             /* sender's sink buffer */
+} kib_putack_msg_t __attribute__((packed));
+
+typedef struct
+{
+        ptl_hdr_t         ibgm_hdr;             /* portals header */
+        __u64             ibgm_cookie;          /* opaque completion cookie */
+        kib_rdma_desc_t   ibgm_rd;              /* rdma descriptor */
+} kib_get_msg_t __attribute__((packed));
+
+typedef struct
+{
+        __u64             ibcm_cookie;          /* opaque completion cookie */
+        __s32             ibcm_status;          /* < 0 failure: >= 0 length */
+       __u32             ibcm_pad;             /* pad to 8 byte boundary */
+} kib_completion_msg_t __attribute__((packed));
+
+typedef struct
+{
+        /* First 2 fields fixed FOR ALL TIME */
+        __u32             ibm_magic;            /* I'm an openibnal message */
+        __u16             ibm_version;          /* this is my version number */
+
+        __u8              ibm_type;             /* msg type */
+        __u8              ibm_credits;          /* returned credits */
+        __u32             ibm_nob;              /* # bytes in whole message */
+        __u32             ibm_cksum;            /* checksum (0 == no checksum) */
+        __u64             ibm_srcnid;           /* sender's NID */
+        __u64             ibm_srcstamp;         /* sender's incarnation */
+        __u64             ibm_dstnid;           /* destination's NID */
+        __u64             ibm_dststamp;         /* destination's incarnation */
+        __u64             ibm_seq;              /* sequence number */
+
+        union {
+                kib_connparams_t      connparams;
+                kib_immediate_msg_t   immediate;
+                kib_putreq_msg_t      putreq;
+                kib_putack_msg_t      putack;
+                kib_get_msg_t         get;
+                kib_completion_msg_t  completion;
+        } ibm_u __attribute__((packed));
+} kib_msg_t __attribute__((packed));
+
+#define IBNAL_MSG_MAGIC       0x0be91b91        /* unique magic */
+#define IBNAL_MSG_VERSION              5        /* current protocol version */
+
+#define IBNAL_MSG_CONNREQ           0xc0        /* connection request */
+#define IBNAL_MSG_CONNACK           0xc1        /* connection acknowledge */
+#define IBNAL_MSG_NOOP              0xd0        /* nothing (just credits) */
+#define IBNAL_MSG_IMMEDIATE         0xd1        /* immediate */
+#define IBNAL_MSG_PUT_REQ           0xd2        /* putreq (src->sink) */
+#define IBNAL_MSG_PUT_NAK           0xd3        /* completion (sink->src) */
+#define IBNAL_MSG_PUT_ACK           0xd4        /* putack (sink->src) */
+#define IBNAL_MSG_PUT_DONE          0xd5        /* completion (src->sink) */
+#define IBNAL_MSG_GET_REQ           0xd6        /* getreq (sink->src) */
+#define IBNAL_MSG_GET_DONE          0xd7        /* completion (src->sink: all OK) */
diff --git a/lnet/klnds/viblnd/wirecheck.c b/lnet/klnds/viblnd/wirecheck.c
new file mode 100644 (file)
index 0000000..7e2a6c3
--- /dev/null
@@ -0,0 +1,207 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ */
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <portals/api-support.h>
+#include <portals/lib-types.h>
+
+#include "vibnal_wire.h"
+
+#ifndef HAVE_STRNLEN
+#define strnlen(s, i) strlen(s)
+#endif
+
+#define BLANK_LINE()                            \
+do {                                            \
+        printf ("\n");                          \
+} while (0)
+
+#define COMMENT(c)                              \
+do {                                            \
+        printf ("        /* "c" */\n");         \
+} while (0)
+
+#undef STRINGIFY
+#define STRINGIFY(a) #a
+
+#define CHECK_DEFINE(a)                                         \
+do {                                                            \
+        printf ("        CLASSERT ("#a" == "STRINGIFY(a)");\n"); \
+} while (0)
+
+#define CHECK_VALUE(a)                                  \
+do {                                                    \
+        printf ("        CLASSERT ("#a" == %d);\n", a);  \
+} while (0)
+
+#define CHECK_MEMBER_OFFSET(s,m)                \
+do {                                            \
+        CHECK_VALUE((int)offsetof(s, m));       \
+} while (0)
+
+#define CHECK_MEMBER_SIZEOF(s,m)                \
+do {                                            \
+        CHECK_VALUE((int)sizeof(((s *)0)->m));  \
+} while (0)
+
+#define CHECK_MEMBER(s,m)                       \
+do {                                            \
+        CHECK_MEMBER_OFFSET(s, m);              \
+        CHECK_MEMBER_SIZEOF(s, m);              \
+} while (0)
+
+#define CHECK_STRUCT(s)                         \
+do {                                            \
+        BLANK_LINE ();                          \
+        COMMENT ("Checks for struct "#s);       \
+        CHECK_VALUE((int)sizeof(s));            \
+} while (0)
+
+void
+system_string (char *cmdline, char *str, int len)
+{
+        int   fds[2];
+        int   rc;
+        pid_t pid;
+
+        rc = pipe (fds);
+        if (rc != 0)
+                abort ();
+
+        pid = fork ();
+        if (pid == 0) {
+                /* child */
+                int   fd = fileno(stdout);
+
+                rc = dup2(fds[1], fd);
+                if (rc != fd)
+                        abort();
+
+                exit(system(cmdline));
+                /* notreached */
+        } else if ((int)pid < 0) {
+                abort();
+        } else {
+                FILE *f = fdopen (fds[0], "r");
+
+                if (f == NULL)
+                        abort();
+
+                close(fds[1]);
+
+                if (fgets(str, len, f) == NULL)
+                        abort();
+
+                if (waitpid(pid, &rc, 0) != pid)
+                        abort();
+
+                if (!WIFEXITED(rc) ||
+                    WEXITSTATUS(rc) != 0)
+                        abort();
+
+                if (strnlen(str, len) == len)
+                        str[len - 1] = 0;
+
+                if (str[strlen(str) - 1] == '\n')
+                        str[strlen(str) - 1] = 0;
+
+                fclose(f);
+        }
+}
+
+int
+main (int argc, char **argv)
+{
+        char unameinfo[80];
+        char gccinfo[80];
+
+        system_string("uname -a", unameinfo, sizeof(unameinfo));
+        system_string("gcc -v 2>&1 | tail -1", gccinfo, sizeof(gccinfo));
+
+        printf ("void vibnal_assert_wire_constants (void)\n"
+                "{\n"
+                "        /* Wire protocol assertions generated by 'wirecheck'\n"
+                "         * running on %s\n"
+                "         * with %s */\n"
+                "\n", unameinfo, gccinfo);
+
+        BLANK_LINE ();
+        
+        COMMENT ("Constants...");
+        CHECK_DEFINE (IBNAL_MSG_MAGIC);
+        CHECK_DEFINE (IBNAL_MSG_VERSION);
+
+        CHECK_DEFINE (IBNAL_MSG_CONNREQ);
+        CHECK_DEFINE (IBNAL_MSG_CONNACK);
+        CHECK_DEFINE (IBNAL_MSG_NOOP);
+        CHECK_DEFINE (IBNAL_MSG_IMMEDIATE);
+        CHECK_DEFINE (IBNAL_MSG_PUT_REQ);
+        CHECK_DEFINE (IBNAL_MSG_PUT_NAK);
+        CHECK_DEFINE (IBNAL_MSG_PUT_ACK);
+        CHECK_DEFINE (IBNAL_MSG_PUT_DONE);
+        CHECK_DEFINE (IBNAL_MSG_GET_REQ);
+        CHECK_DEFINE (IBNAL_MSG_GET_DONE);
+
+        CHECK_STRUCT (kib_connparams_t);
+        CHECK_MEMBER (kib_connparams_t, ibcp_queue_depth);
+        CHECK_MEMBER (kib_connparams_t, ibcp_max_msg_size);
+        CHECK_MEMBER (kib_connparams_t, ibcp_max_frags);
+
+        CHECK_STRUCT (kib_immediate_msg_t);
+        CHECK_MEMBER (kib_immediate_msg_t, ibim_hdr);
+        CHECK_MEMBER (kib_immediate_msg_t, ibim_payload[13]);
+
+        CHECK_STRUCT (kib_rdma_frag_t);
+        CHECK_MEMBER (kib_rdma_frag_t, rf_nob);
+        CHECK_MEMBER (kib_rdma_frag_t, rf_addr_lo);
+        CHECK_MEMBER (kib_rdma_frag_t, rf_addr_hi);
+
+        CHECK_STRUCT (kib_rdma_desc_t);
+        CHECK_MEMBER (kib_rdma_desc_t, rd_key);
+        CHECK_MEMBER (kib_rdma_desc_t, rd_nfrag);
+        CHECK_MEMBER (kib_rdma_desc_t, rd_frags[13]);
+
+        CHECK_STRUCT (kib_putreq_msg_t);
+        CHECK_MEMBER (kib_putreq_msg_t, ibprm_hdr);
+        CHECK_MEMBER (kib_putreq_msg_t, ibprm_cookie);
+
+        CHECK_STRUCT (kib_putack_msg_t);
+        CHECK_MEMBER (kib_putack_msg_t, ibpam_src_cookie);
+        CHECK_MEMBER (kib_putack_msg_t, ibpam_dst_cookie);
+        CHECK_MEMBER (kib_putack_msg_t, ibpam_rd);
+
+        CHECK_STRUCT (kib_get_msg_t);
+        CHECK_MEMBER (kib_get_msg_t, ibgm_hdr);
+        CHECK_MEMBER (kib_get_msg_t, ibgm_cookie);
+        CHECK_MEMBER (kib_get_msg_t, ibgm_rd);
+
+        CHECK_STRUCT (kib_completion_msg_t);
+        CHECK_MEMBER (kib_completion_msg_t, ibcm_cookie);
+        CHECK_MEMBER (kib_completion_msg_t, ibcm_status);
+
+        CHECK_STRUCT (kib_msg_t);
+        CHECK_MEMBER (kib_msg_t, ibm_magic);
+        CHECK_MEMBER (kib_msg_t, ibm_version);
+        CHECK_MEMBER (kib_msg_t, ibm_type);
+        CHECK_MEMBER (kib_msg_t, ibm_credits);
+        CHECK_MEMBER (kib_msg_t, ibm_nob);
+        CHECK_MEMBER (kib_msg_t, ibm_cksum);
+        CHECK_MEMBER (kib_msg_t, ibm_srcnid);
+        CHECK_MEMBER (kib_msg_t, ibm_srcstamp);
+        CHECK_MEMBER (kib_msg_t, ibm_dstnid);
+        CHECK_MEMBER (kib_msg_t, ibm_dststamp);
+        CHECK_MEMBER (kib_msg_t, ibm_seq);
+        CHECK_MEMBER (kib_msg_t, ibm_u.connparams);
+        CHECK_MEMBER (kib_msg_t, ibm_u.immediate);
+        CHECK_MEMBER (kib_msg_t, ibm_u.putreq);
+        CHECK_MEMBER (kib_msg_t, ibm_u.putack);
+        CHECK_MEMBER (kib_msg_t, ibm_u.get);
+        CHECK_MEMBER (kib_msg_t, ibm_u.completion);
+
+        printf ("}\n\n");
+
+        return (0);
+}