summaryrefslogtreecommitdiff
path: root/zebra/kernel_socket.c
diff options
context:
space:
mode:
authorGreg Troxel <gdt@ir.bbn.com>2014-12-02 14:51:49 -0500
committerDaniel Walton <dwalton@cumulusnetworks.com>2016-05-26 15:24:50 +0000
commitcfa0ed0949284a978e6d1710de66cf40474594c9 (patch)
tree19eb8921ec31abbde5728aeb8e34749451b68c85 /zebra/kernel_socket.c
parent9b97a19b10268c8a4b533e72640d53b504e90193 (diff)
zebra/kernel_socket.c: Use platform alignment
Use the platform-provided RT_ROUNDUP macro to align sockaddrs on the routing socket, rather than using hard-coded assumptions about alignment. Emit a warning if the OS doesn't define alignment macros. Resolves failure of ripngd on NetBSD 6 i386, which changed alignment to uint64_t from long. (cherry picked from commit 273b1bd341afff86ba571e0be296d88dba627136)
Diffstat (limited to 'zebra/kernel_socket.c')
-rw-r--r--zebra/kernel_socket.c50
1 files changed, 40 insertions, 10 deletions
diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c
index a8ce4d07df..5d5206a2f9 100644
--- a/zebra/kernel_socket.c
+++ b/zebra/kernel_socket.c
@@ -43,22 +43,52 @@
extern struct zebra_privs_t zserv_privs;
/*
- * Given a sockaddr length, round it up to include pad bytes following
- * it. Assumes the kernel pads to sizeof(long).
+ * Historically, the BSD routing socket has aligned data following a
+ * struct sockaddr to sizeof(long), which was 4 bytes on some
+ * platforms, and 8 bytes on others. NetBSD 6 changed the routing
+ * socket to align to sizeof(uint64_t), which is 8 bytes. OS X
+ * appears to align to sizeof(int), which is 4 bytes.
*
- * XXX: why is ROUNDUP(0) sizeof(long)? 0 is an illegal sockaddr
- * length anyway (< sizeof (struct sockaddr)), so this shouldn't
- * matter.
- * On OS X, both 32, 64bit syatems align on 4 byte boundary
+ * Alignment of zero-sized sockaddrs is nonsensical, but historically
+ * BSD defines RT_ROUNDUP(0) to be the alignment interval (rather than
+ * 0). We follow this practice without questioning it, but it is a
+ * bug if quagga calls ROUNDUP with 0.
*/
+
+/*
+ * Because of these varying conventions, the only sane approach is for
+ * the <net/route.h> header to define some flavor of ROUNDUP macro.
+ */
+#if defined(RT_ROUNDUP)
+#define ROUNDUP(a) RT_ROUNDUP(a)
+#endif /* defined(RT_ROUNDUP) */
+
+/*
+ * If ROUNDUP has not yet been defined in terms of platform-provided
+ * defines, attempt to cope with heuristics.
+ */
+#if !defined(ROUNDUP)
+
+/*
+ * It's a bug for a platform not to define rounding/alignment for
+ * sockaddrs on the routing socket. This warning really is
+ * intentional, to provoke filing bug reports with operating systems
+ * that don't define RT_ROUNDUP or equivalent.
+ */
+#warning "net/route.h does not define RT_ROUNDUP; making unwarranted assumptions!"
+
+/* OS X (Xcode as of 2014-12) is known not to define RT_ROUNDUP */
#ifdef __APPLE__
-#define ROUNDUP(a) \
- ((a) > 0 ? (1 + (((a) - 1) | (sizeof(int) - 1))) : sizeof(int))
+#define ROUNDUP_TYPE long
#else
-#define ROUNDUP(a) \
- ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+#define ROUNDUP_TYPE int
#endif
+#define ROUNDUP(a) \
+ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(ROUNDUP_TYPE) - 1))) : sizeof(ROUNDUP_TYPE))
+
+#endif /* defined(ROUNDUP) */
+
/*
* Given a pointer (sockaddr or void *), return the number of bytes
* taken up by the sockaddr and any padding needed for alignment.