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)
This commit is contained in:
Greg Troxel 2014-12-02 14:51:49 -05:00 committed by Daniel Walton
parent 9b97a19b10
commit cfa0ed0949

View File

@ -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.