tech-net archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: routing socket rouding?



On Feb 18, 2012, at 12:35 AM, Mouse wrote:
>>> There is a macro, historically ROUNDUP defined in various .c files,
>>> RT_ROUNDUP in <net/route.h> in 5.1 and presumably later, [...]
>>> 
>>> So, I'm curious: does anyone know what this macro turned into on a
>>> system with sizeof(long) not a power of two but with anything like
>>> the BSD routing socket, if such a system exists?
>> 
>> ROUNDUP (or ROUND_UP) macro was replaced by ALIGN on some platforms,
>> ie:
>> 
>>  http://lkml.org/lkml/2007/4/1/50
> 
> (a) That appears to be dealing with PCI support, not routing socket
> support.  It's the routing socket macro I'm curious about.  (The
> ROUND_UP macro being replaced does appear to assume the grain size
> being rounded up to is a pwoer of two, so it's related, but since it
> doesn't show the definition of the ALIGN it's being replaced with, the
> message is pretty much content-free for my purposes.)

If you search for both macro names, you'll discover that this Milind Choudhary 
made a sweep through the Linux kernel, including PCI support, network drivers, 
and so forth.  If the "not invented here" syndrome or whatever other reason 
means that you don't want to consider a change made in Linux, you'll even 
discover that it's used in APR-- see APR_ALIGN in include/apr_general.h:

#define APR_ALIGN(size, boundary) (((size) + ((boundary) - 1)) & ~((boundary) - 
1))

> (b) The ROUND_UP macro affected by that patch is not the one used by
> the routing socket code; it returns zero when passed zero, whereas the
> routing socket's ROUNDUP / RT_ROUNDUP returns sizeof(long) when passed
> zero.

I have reason to believe the NetBSD macro resembles:

#define RT_ROUNDUP2(a, n)       ((a) > 0 ? (1 + (((a) - 1) | ((n) - 1))) : (n))
#define RT_ROUNDUP(a)           RT_ROUNDUP2((a), sizeof(uint64_t))

Passing a=0 to RT_ROUNDUP2 is already aligned, but the ternary ?: causes it to 
return the "n" or alignment boundary, you get sizeof(uint64_t) back.  Whether 
that's the same as sizeof(long) depends on whether you are running an (I)LP64 
platform or not, because RT_ROUNDUP always passes n=8 to RT_ROUNDUP2:

% cat m.c
#define APR_ALIGN(size, boundary) (((size) + ((boundary) - 1)) & ~((boundary) - 
1))

#define RT_ROUNDUP2(a, n)       ((a) > 0 ? (1 + (((a) - 1) | ((n) - 1))) : (n))
#define RT_ROUNDUP(a)           RT_ROUNDUP2((a), sizeof(uint64_t))

#include <stdio.h>

int main() {
    printf("align 0, sizeof(int):  %ld\n", APR_ALIGN(0, sizeof(int)));
    printf("align 0, sizeof(long): %ld\n", APR_ALIGN(0, sizeof(long)));
    
    printf("align 2, sizeof(int):  %ld\n", APR_ALIGN(2, sizeof(int)));
    printf("align 2, sizeof(long): %ld\n", APR_ALIGN(2, sizeof(long)));

    printf("align 4, sizeof(int):  %ld\n", APR_ALIGN(4, sizeof(int)));
    printf("align 4, sizeof(long): %ld\n", APR_ALIGN(4, sizeof(long)));

    printf("align 8, sizeof(int):  %ld\n", APR_ALIGN(8, sizeof(int)));
    printf("align 8, sizeof(long): %ld\n", APR_ALIGN(8, sizeof(long)));

    printf("rt_roundup2 0, sizeof(int):  %ld\n", RT_ROUNDUP2(0, sizeof(int)));
    printf("rt_roundup2 0, sizeof(long): %ld\n", RT_ROUNDUP2(0, sizeof(long)));
    
    printf("rt_roundup2 2, sizeof(int):  %ld\n", RT_ROUNDUP2(2, sizeof(int)));
    printf("rt_roundup2 2, sizeof(long): %ld\n", RT_ROUNDUP2(2, sizeof(long)));

    printf("rt_roundup2 4, sizeof(int):  %ld\n", RT_ROUNDUP2(4, sizeof(int)));
    printf("rt_roundup2 4, sizeof(long): %ld\n", RT_ROUNDUP2(4, sizeof(long)));

    printf("rt_roundup2 8, sizeof(int):  %ld\n", RT_ROUNDUP2(8, sizeof(int)));
    printf("rt_roundup2 8, sizeof(long): %ld\n", RT_ROUNDUP2(8, sizeof(long)));
}

% cc -o m m.c && ./m
align 0, sizeof(int):  0
align 0, sizeof(long): 0
align 2, sizeof(int):  4
align 2, sizeof(long): 8
align 4, sizeof(int):  4
align 4, sizeof(long): 8
align 8, sizeof(int):  8
align 8, sizeof(long): 8
rt_roundup2 0, sizeof(int):  4
rt_roundup2 0, sizeof(long): 8
rt_roundup2 2, sizeof(int):  4
rt_roundup2 2, sizeof(long): 8
rt_roundup2 4, sizeof(int):  4
rt_roundup2 4, sizeof(long): 8
rt_roundup2 8, sizeof(int):  8
rt_roundup2 8, sizeof(long): 8

% cc -m32 -o m m.c && ./m
align 0, sizeof(int):  0
align 0, sizeof(long): 0
align 2, sizeof(int):  4
align 2, sizeof(long): 4
align 4, sizeof(int):  4
align 4, sizeof(long): 4
align 8, sizeof(int):  8
align 8, sizeof(long): 8
rt_roundup2 0, sizeof(int):  4
rt_roundup2 0, sizeof(long): 4
rt_roundup2 2, sizeof(int):  4
rt_roundup2 2, sizeof(long): 4
rt_roundup2 4, sizeof(int):  4
rt_roundup2 4, sizeof(long): 4
rt_roundup2 8, sizeof(int):  8
rt_roundup2 8, sizeof(long): 8

> (c) Your citing this in response to my question implies that Linux runs
> on something with sizeof(long) not a power of two.  Now I'm also
> curious what CPU (and/or machine) that is.

A DEC PDP-7 had an 18-bit word size, and the PDP-10 had a 36-bit word size; I'm 
not sure you'll find anything much newer than that.

However, my reason for citing the above is that many variants of ROUNDUP / 
ROUND_UP are buggy, and reasoning about an address or size that might be 
rounded up or not, depending on whether it is already aligned (or not), or 
zero, etc leads to problems.  (You also get problems when code using it moves 
from ILP32 to LP64, which is why I'm familiar with this macro and variants.)

>> and it appears to assume 2's compliment arithmetic....
> 
> Well, two's complement (not "compliment") versus alternatives is
> relevant only when dealing with negative values.

True, and "routing socket rouding?" should be "routing socket rounding?"

Many folks are more apt to fault others than they are to fault themselves for 
the same error.

Regards,
-- 
-Chuck



Home | Main Index | Thread Index | Old Index