-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for inet_ntoa6() subroutine
Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com>
- Loading branch information
Showing
4 changed files
with
298 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,246 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
/* | ||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. | ||
*/ | ||
|
||
#define BPF_FUNC_probe_read 4 | ||
|
||
#define DCTX_RODATA 56 | ||
|
||
.text | ||
|
||
/* | ||
* void write_hex16(const uint16_t src, char *dst) | ||
*/ | ||
.align 4 | ||
.global write_hex16 | ||
.type write_hex16, @function | ||
write_hex16: | ||
mov %r0, 0 | ||
|
||
/* | ||
* Branch-free implementation of num-to-hex print function. Given a | ||
* number from 0 to 15, this will output a hex digit (0-9a-f) in the | ||
* output buffer. It also supports suppression of leading 0s if it is | ||
* used to output a sequence of digits. | ||
* | ||
* Given: c in [0, 15] | ||
* Then, (c - 9) will be greater than 0 for c in [10, 15]. | ||
* Therefore, (-(c - 9)) will have its highest bit set if c in [10, 15]. | ||
* Thus, ((-(c - 9)) >> 63) will be 1 if c in [10, 15], and otherwise 0. | ||
* Therefore, the hex digit (character) representing c can be computed | ||
* as: | ||
* c + '0' + ((-(c - 9)) >> 63) * ('a' - '0' - 10) | ||
* | ||
* Let s be a global suppression flag across the digits (initially 0). | ||
* Let d be (c + s), and therefore ((-d) >> 63) will be 0 iff c and s | ||
* are both 0, and otherwise 1. This is used to determine whether the | ||
* output pointer should be advanced, and also to update the global | ||
& suppression flag (s += ((-d) >> 63)). | ||
*/ | ||
.macro WRITE_DIGIT n | ||
mov %r3, %r1 | ||
rsh %r3, 4 * (3 - \n) | ||
and %r3, 0xf | ||
mov %r4, %r3 | ||
mov %r5, %r3 | ||
sub %r4, 9 | ||
neg %r4 | ||
rsh %r4, 63 | ||
mul %r4, 0x27 | ||
add %r4, 0x30 | ||
add %r3, %r4 | ||
stxb [%r2 + 0], %r3 | ||
add %r5, %r0 | ||
neg %r5 | ||
rsh %r5, 63 /* 0 if '0', 1 otherwise */ | ||
add %r2, %r5 | ||
add %r0, %r5 | ||
.endm | ||
|
||
WRITE_DIGIT 0 | ||
WRITE_DIGIT 1 | ||
WRITE_DIGIT 2 | ||
WRITE_DIGIT 3 | ||
|
||
/* | ||
* It is possible that all digits are 0, in which case the output | ||
* pointer did not advance from its initial value. We do want a single | ||
* 0 digit as output though. | ||
* | ||
* Since in this case, %r5 will be zero if all digits are zero, and 1 | ||
* otherwise, we can simply use %r0 + (%r5 ^ 1) to ensure that when all | ||
* digits are 0, we retain the last one. | ||
*/ | ||
xor %r5, 1 | ||
add %r0, %r5 | ||
exit | ||
.size write_hex16, .-write_hex16 | ||
|
||
/* | ||
* void inet_ntoa6(const dt_dctx_t *dctx, const uint8_t *src, char *dst, | ||
* uint32 tbloff) | ||
*/ | ||
.align 4 | ||
.global dt_inet_ntoa6 | ||
.type dt_inet_ntoa6, @function | ||
dt_inet_ntoa6: | ||
/* %r9 = dst, %r6 = dctx, %r8 = dctx->rodata + tbloff */ | ||
mov %r9, %r3 /* %r9 = dst */ | ||
mov %r6, %r1 /* %r6 = dctx */ | ||
mov %r8, %r1 /* %r8 = dctx->rodata + tbloff */ | ||
ldxdw %r8, [%r8 + DCTX_RODATA] | ||
jge %r4, RODATA_SIZE, .Ldone | ||
add %r8, %r4 | ||
|
||
mov %r3, %r2 | ||
mov %r2, 16 | ||
mov %r1, %fp | ||
add %r1, -16 | ||
call BPF_FUNC_probe_read /* rc = probe_read(&fp[-16], 16, src) */ | ||
jne %r0, 0, .Ldone | ||
|
||
/* | ||
* Read the 8 words (16-bit values), and build a bitmap in %r7 | ||
* indicating which words are non-zero. | ||
* | ||
* We use an implementation that does not involve branches to reduce | ||
* complexity for the BPF verifier. | ||
* | ||
* The IPv6 address has words in network byte order which may differ | ||
* from the host byte order. We store a 2nd copy od the words, with | ||
* the byte order reversed (if needed). We shouldn't need the 2nd copy | ||
* if the byte order is the same but since the BPF verifier chokes on | ||
* the output code below due to lack of tracking of relations between | ||
* register values, the 2nd copy is needed anyway. | ||
*/ | ||
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ | ||
# define NTOH(reg) | ||
#else | ||
# define NTOH(reg) endbe reg, 16 | ||
#endif | ||
.macro GETWORD n | ||
ldxh %r0, [%fp + (-16 + \n * 2)] | ||
NTOH(%r0) | ||
stxh [%fp + (-32 + \n * 2)], %r0 | ||
neg %r0 | ||
rsh %r0, 63 | ||
lsh %r0, 7 - \n | ||
or %r7, %r0 | ||
.endm | ||
|
||
mov %r7, 0 | ||
GETWORD 0 | ||
GETWORD 1 | ||
GETWORD 2 | ||
GETWORD 3 | ||
GETWORD 4 | ||
GETWORD 5 | ||
GETWORD 6 | ||
GETWORD 7 | ||
|
||
/* Set the upper bound for %r7. */ | ||
and %r7, 0xff | ||
|
||
/* Handle mapped and embedded IPv4 addresses. */ | ||
mov %r0, %r7 | ||
and %r0, 0xfe | ||
jeq %r0, 2, .Lipv4 | ||
jne %r0, 6, .Lnotipv4 | ||
ldxh %r0, [%fp + -22] | ||
jeq %r0, 0xffff, .Lipv4 | ||
.Lnotipv4: | ||
|
||
/* | ||
* Perform a table lookup to determine the location and length of the | ||
* longest run of 0-words (if any). | ||
*/ | ||
mov %r0, %r8 | ||
add %r0, %r7 | ||
ldxb %r7, [%r0 + 0] | ||
|
||
/* | ||
* Determine the number of words to output at the start of the address. | ||
* It is found in the upper 4 bits in %r7 (result of the table lookup | ||
* above). We place an upper bound to make the BPF verifier happy. | ||
*/ | ||
mov %r6, %r7 | ||
rsh %r6, 4 | ||
jgt %r6, 7, .Ldone | ||
mov %r8, %fp | ||
add %r8, -32 | ||
|
||
/* Write out the %r6 words at the beginning of the address. */ | ||
.Lpref_loop: | ||
jle %r6, 0, .Lpref_done | ||
ldxh %r1, [%r8 + 0] | ||
mov %r2, %r9 | ||
call write_hex16 | ||
add %r9, %r0 | ||
stb [%r9 + 0], 0x3a | ||
add %r9, 1 | ||
add %r8, 2 | ||
sub %r6, 1 | ||
ja .Lpref_loop | ||
|
||
.Lpref_done: | ||
stb [%r9 + 0], 0x3a | ||
|
||
/* | ||
* Determine the number of zero-words that can be collapsed. It is | ||
* found in the lower 4 bits of %r7 (result of the table lookup above). | ||
* (Note: it is either 0 or >1.) | ||
*/ | ||
mov %r1, %r7 | ||
rsh %r1, 4 /* #(leading words) */ | ||
mov %r0, %r1 | ||
neg %r0 | ||
rsh %r0, 63 | ||
xor %r0, 1 | ||
add %r9, %r0 | ||
mov %r2, %r7 | ||
and %r2, 0xf /* #(zero words to collapse) */ | ||
add %r1, %r2 /* #(words used) */ | ||
jgt %r1, 8, .Ldone | ||
|
||
mov %r8, %fp | ||
add %r8, -32 | ||
mov %r0, %r1 | ||
mul %r0, 2 | ||
add %r8, %r0 | ||
mov %r6, 8 | ||
sub %r6, %r1 /* #(words left) */ | ||
|
||
stb [%r9 + 0], 0x3a | ||
mov %r0, %r6 | ||
neg %r0 | ||
rsh %r0, 63 | ||
xor %r0, 1 | ||
add %r9, %r0 | ||
|
||
.Lpost_loop: | ||
jle %r6, 0, .Ldone | ||
stb [%r9 + 0], 0x3a | ||
add %r9, 1 | ||
ldxh %r1, [%r8 + 0] | ||
mov %r2, %r9 | ||
call write_hex16 | ||
add %r9, %r0 | ||
add %r8, 2 | ||
sub %r6, 1 | ||
ja .Lpost_loop | ||
|
||
.Ldone: | ||
stb [%r9 + 0], 0 | ||
mov %r0, 0 | ||
exit | ||
|
||
.Lipv4: | ||
mov %r1, %r6 | ||
mov %r2, %fp | ||
add %r2, -4 | ||
mov %r3, %r9 | ||
call dt_inet_ntoa | ||
add %r9, %r0 | ||
ja .Ldone | ||
.size dt_inet_ntoa6, .-dt_inet_ntoa6 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters