diff options
| author | Greg Troxel <gdt@ir.bbn.com> | 2014-12-02 14:51:49 -0500 |
|---|---|---|
| committer | Daniel Walton <dwalton@cumulusnetworks.com> | 2016-05-26 15:24:50 +0000 |
| commit | cfa0ed0949284a978e6d1710de66cf40474594c9 (patch) | |
| tree | 19eb8921ec31abbde5728aeb8e34749451b68c85 /zebra/kernel_socket.c | |
| parent | 9b97a19b10268c8a4b533e72640d53b504e90193 (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.c | 50 |
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. |
