[DTrace-devel] [PATCH 7/7] Add support for inet_ntoa6() subroutine

Eugene Loh eugene.loh at oracle.com
Tue Aug 1 23:22:01 UTC 2023


On 8/1/23 16:57, Kris Van Hees wrote:

> On Tue, Aug 01, 2023 at 01:40:40AM -0400, Eugene Loh via DTrace-devel wrote:
>
>> Also, it'd be great if the code had some high-level roadmap of where this
>> very difficult minimal-branching implementation is going.  Hopefully, it's
>> 100% correct and no one will ever have to look at this code again.
>> Otherwise, it's a nightmare.  Maybe there could be some C code in the
>> comments that illustrates what's going on in the BPF where each C statement
>> maps to a set of BPF instructions, even if the branch-free BPF instructions
>> take some head-scratching to figure out.  E.g., "d = (c || s) ? 1 : 0" maps
>> to "add %r5, %r0; neg %r5; rsh %r5, 63".
> The problem with C code is that it is about as obscure as this assembly code
> unless you write it as a higher level implementation, which then again will
> show branches and therefore become less useful.

Actually "show branches" is kind of what I meant.  Show the higher-level 
implementation.  People can then separate "is that doing what inet_ntoa6 
should do?" from "how do the BPF instructions accomplish that?"  Anyhow, 
just a suggestion.  Ultimately, the bottom line here is that this stuff 
is just plain tricky

> I'll add a bit more commentary to explain the use of the bitmap of non-zero
> words and the lookup table.
>

Cool.

>> Maybe it should also acknowledge that there are subtle ways that the
>> implemented algorithm differs from legacy DTrace (dtrace_dif.c).  Namely:
>> *)  There seem to be differences in the ways the two implementations decide
>> between ipv4 and v6.  I don't understand this stuff well enough to judge if
>> there are any errors here.
> I do not see where there are differences between legacy and this version when
> it comes to IPv4 and IPv6 addresses.  As far as I can see, the behaviour for
> mapped and embedded IPv4 addresses is the sme.

I have no idea if these differences are important, but they're there.  
One can see that by examining the code, but that requires some poking 
around into ipv6_addr_type().  So another way is just to try some 
"random" inputs:

struct in6_addr *ip6;
BEGIN
{
     ip6 = alloca(sizeof (struct in6_addr));
     ip6->in6_u.u6_addr8[ 0] = 0x01; printf("%s\n", inet_ntoa6(ip6)); 
ip6->in6_u.u6_addr8[ 0] = 0;
     ip6->in6_u.u6_addr8[ 1] = 0x01; printf("%s\n", inet_ntoa6(ip6)); 
ip6->in6_u.u6_addr8[ 1] = 0;
     ip6->in6_u.u6_addr8[ 2] = 0x01; printf("%s\n", inet_ntoa6(ip6)); 
ip6->in6_u.u6_addr8[ 2] = 0;
     ip6->in6_u.u6_addr8[ 3] = 0x01; printf("%s\n", inet_ntoa6(ip6)); 
ip6->in6_u.u6_addr8[ 3] = 0;
     ip6->in6_u.u6_addr8[ 4] = 0x01; printf("%s\n", inet_ntoa6(ip6)); 
ip6->in6_u.u6_addr8[ 4] = 0;
     ip6->in6_u.u6_addr8[ 5] = 0x01; printf("%s\n", inet_ntoa6(ip6)); 
ip6->in6_u.u6_addr8[ 5] = 0;
     ip6->in6_u.u6_addr8[ 6] = 0x01; printf("%s\n", inet_ntoa6(ip6)); 
ip6->in6_u.u6_addr8[ 6] = 0;
     ip6->in6_u.u6_addr8[ 7] = 0x01; printf("%s\n", inet_ntoa6(ip6)); 
ip6->in6_u.u6_addr8[ 7] = 0;
     ip6->in6_u.u6_addr8[ 8] = 0x01; printf("%s\n", inet_ntoa6(ip6)); 
ip6->in6_u.u6_addr8[ 8] = 0;
     ip6->in6_u.u6_addr8[ 9] = 0x01; printf("%s\n", inet_ntoa6(ip6)); 
ip6->in6_u.u6_addr8[ 9] = 0;
     ip6->in6_u.u6_addr8[10] = 0x01; printf("%s\n", inet_ntoa6(ip6)); 
ip6->in6_u.u6_addr8[10] = 0;
     ip6->in6_u.u6_addr8[11] = 0x01; printf("%s\n", inet_ntoa6(ip6)); 
ip6->in6_u.u6_addr8[11] = 0;
     ip6->in6_u.u6_addr8[12] = 0x01; printf("%s\n", inet_ntoa6(ip6)); 
ip6->in6_u.u6_addr8[12] = 0;
     ip6->in6_u.u6_addr8[13] = 0x01; printf("%s\n", inet_ntoa6(ip6)); 
ip6->in6_u.u6_addr8[13] = 0;
     ip6->in6_u.u6_addr8[14] = 0x01; printf("%s\n", inet_ntoa6(ip6)); 
ip6->in6_u.u6_addr8[14] = 0;
     ip6->in6_u.u6_addr8[15] = 0x01; printf("%s\n", inet_ntoa6(ip6)); 
ip6->in6_u.u6_addr8[15] = 0;
     exit(0);
}

With DTv1, I get:

100::
1::
0:100::
0:1::
0:0:100::
0:0:1::
0:0:0:100::
0:0:0:1::
::100:0:0:0
::1:0:0:0
::100:0:0
::1:0:0
1.0.0.0
0.1.0.0
0.0.1.0
::1

With the proposed patch:

100::
1::
0:100::
0:1::
0:0:100::
0:0:1::
0:0:0:100::
0:0:0:1::
::100:0:0:0
::1:0:0:0
::100:0:0
::1:0:0
1.0.0.0
0.1.0.0
::100
::1

Lots of agreement, but the second-to-last result differs.  I'm not 
saying these are meaningful -- or even legal -- cases, but only that one 
can see that the selection is not the same between the two 
implementations.  There are other examples.

>> This patch uses bpf/inet_ntoa.S.  That file claims the function is void, but
>> inet_ntoa6() uses the return value.  So, that file should document the
>> function correctly.  Also, that file claims to fill with ":".  It actually
>> fills with ".".
> The code now no longer expects inet_ntoa() to return a value, so this no
> longer matters.  I dropped the patch adding a return value from the series.
>
> If bpf/inet_ntoa.S documents is behaviour wrong (i.e. you point out how your
> comment claim ':' as separator whereas the implementation correctly uses '.'),
> you should subnmit a patch to fix that.  Or I can do it - but outside this
> series because it is independent.

Yeah.  My fault in the first place.  I can submit a patch.

>> On 7/27/23 11:31, Kris Van Hees via DTrace-devel wrote:
>>> diff --git a/bpf/inet_ntoa6.S b/bpf/inet_ntoa6.S
>>> +#define DCTX_RODATA			56
>> 56 hardwired?
> The trouble is that assembler input files cannot contain struct declarations
> and use offsetof(), so the only way to avoid this is to add a utility that
> writes out a .h file at build time to provide constants like this.  Worth
> considering - though since this is the only occurence (for now) maybe a
> comment might suffice?

Sure.



More information about the DTrace-devel mailing list