Skip to content

Commit

Permalink
Add support for the link_ntop() subroutine
Browse files Browse the repository at this point in the history
Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
Reviewed-by: Kris Van Hees <kris.van.hees@oracle.com>
  • Loading branch information
euloh authored and kvanhees committed Dec 21, 2023
1 parent e24fe20 commit 371ecc1
Show file tree
Hide file tree
Showing 8 changed files with 250 additions and 2 deletions.
1 change: 1 addition & 0 deletions bpf/Build
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ bpf_dlib_SOURCES = \
index.S \
inet_ntoa.S \
inet_ntoa6.S \
link_ntop.S \
lltostr.S \
mutex_owned.S \
mutex_owner.S \
Expand Down
127 changes: 127 additions & 0 deletions bpf/link_ntop.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
*/

#define BPF_FUNC_probe_read 4

#define ARPHRD_ETHER 1 /* ARP protocol hw identifier <linux/if_arp.h> */
#define ARPHRD_INFINIBAND 32 /* ARP protocol hw identifier <linux/if_arp.h> */

#define ETH_ALEN 6 /* Octets in ethernet addr <linux/if_ether.h> */
#define INFINIBAND_ALEN 20 /* Octets in IPoIB HW addr <linux/if_infiniband.h> */

#define MAX_ALEN 20

#define LENGTH 72

.text

/*
* uint64_t write_byte2hex(const uint8_t src, char *dst)
*/
.align 4
.global write_byte2hex
.type write_byte2hex, @function
write_byte2hex:
/*
* Branch-free implementation of byte-to-hex function.
*
* Process 4 bits (one hex digit) at a time.
*
* Given: r3 in [0, 15].
* Then, ((-(r3 - 9)) >> 63) is 1 if r3 in [10, 15], and 0 otherwise.
* Therefore, the hex digit (character) representing r3 is:
* r3 + '0' + ((-(r3 - 9)) >> 63) * ('a' - '0' - 10)
*/

.macro WRITE_DIGIT n
/* Put digit n from %r1 into %r3. */
mov %r3, %r1
rsh %r3, 4 * (1 - \n)
and %r3, 0xf

/* Store the converted value into %r2. */
mov %r4, %r3
sub %r4, 9
neg %r4
rsh %r4, 63
mul %r4, 'a' - '0' - 10
add %r4, '0'
add %r4, %r3
stxb [%r2 + \n], %r4
.endm

WRITE_DIGIT 0
WRITE_DIGIT 1

exit
.size write_byte2hex, .-write_byte2hex

/*
* void link_ntop(const dt_dctx_t *dctx, const uint8_t *src, char *dst, uint32 type)
*/
.align 4
.global dt_link_ntop
.type dt_link_ntop, @function
dt_link_ntop:
/*
* %r9 dst pointer
* %r8 src copy
* %r7 len left
*
* We copy the src string so that we can safely dereference individual
* bytes. The src string is at most MAX_ALEN bytes. The dst string is
* three times the src length. The dst space is a tstring, which is
* known to be at least 72 bytes. This is long enough for both src copy
* and dst string since, as we write the dst string, src bytes are
* being used up. So the dst string will start at byte 0 while src
* will be copied to offset LENGTH-MAX_ALEN.
*/

/* Write pointer to dst. */
mov %r9, %r3

/* Copy of src data. */
mov %r8, %r3
add %r8, LENGTH - MAX_ALEN

/* Store len in %r7 based on arg4. */
mov %r7, ETH_ALEN
jeq %r4, ARPHRD_INFINIBAND, .Lib
jne %r4, ARPHRD_ETHER, .Lerror
ja .Lcomp
.Lib:
mov %r7, INFINIBAND_ALEN
.Lcomp:

/* Copy src data. */
mov %r3, %r2
mov %r2, %r7
mov %r1, %r8
call BPF_FUNC_probe_read
jne %r0, 0, .Lerror

/* Loop over bytes. Each byte is appended with a ':'. */
.Lloop:
jle %r7, 0, .Ldone
ldxb %r1, [%r8 + 0]
mov %r2, %r9
call write_byte2hex
stb [%r9 + 2], ':'
add %r9, 3
add %r8, 1
sub %r7, 1
ja .Lloop
.Ldone:
stb [%r9 + -1], 0
mov %r0, 0
exit

.Lerror:
/* Output the terminating NUL byte and return. */
stb [%r9 + 0], 0
mov %r0, 0
exit

.size dt_link_ntop, .-dt_link_ntop
24 changes: 23 additions & 1 deletion libdtrace/dt_cg.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
#include <assert.h>
#include <errno.h>

#include <sys/socket.h> /* needed for if_arp.h on OL7/x86 */
#include <linux/if_arp.h> /* ARPHRD_ETHER ARPHRD_INFINIBAND */

#include <dt_impl.h>
#include <dt_dis.h>
#include <dt_dctx.h>
Expand Down Expand Up @@ -6239,6 +6242,25 @@ dt_cg_subr_inet_ntop(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
tnp->dn_tstring = NULL;
}

static void
dt_cg_subr_link_ntop(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
{
dt_node_t *type = dnp->dn_args;
uint_t Lokay = dt_irlist_label(dlp);

/* Determine type and check it is okay. */
dt_cg_node(type, dlp, drp);
emit(dlp, BPF_BRANCH_IMM(BPF_JEQ, type->dn_reg, ARPHRD_INFINIBAND, Lokay));
emit(dlp, BPF_BRANCH_IMM(BPF_JEQ, type->dn_reg, ARPHRD_ETHER, Lokay));
dt_cg_probe_error(yypcb, DTRACEFLT_ILLOP, DT_ISREG, type->dn_reg);
emitl(dlp, Lokay,
BPF_NOP());

dt_cg_subr_arg_to_tstring(dnp, dlp, drp, "dt_link_ntop", 1,
DT_ISREG, type->dn_reg, DT_IGNOR, 0);
dt_regset_free(drp, type->dn_reg);
}

typedef void dt_cg_subr_f(dt_node_t *, dt_irlist_t *, dt_regset_t *);

static dt_cg_subr_f *_dt_cg_subr[DIF_SUBR_MAX + 1] = {
Expand Down Expand Up @@ -6287,7 +6309,7 @@ static dt_cg_subr_f *_dt_cg_subr[DIF_SUBR_MAX + 1] = {
[DIF_SUBR_INET_NTOA] = &dt_cg_subr_inet_ntoa,
[DIF_SUBR_INET_NTOA6] = &dt_cg_subr_inet_ntoa6,
[DIF_SUBR_D_PATH] = NULL,
[DIF_SUBR_LINK_NTOP] = NULL,
[DIF_SUBR_LINK_NTOP] = &dt_cg_subr_link_ntop,
};

static void
Expand Down
3 changes: 3 additions & 0 deletions test/unittest/funcs/err.link_ntopbadaddr.r
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
-- @@stderr --
dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN

3 changes: 3 additions & 0 deletions test/unittest/funcs/err.link_ntopbadarg.r
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
-- @@stderr --
dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): illegal operation in action #1 at BPF pc NNN

1 change: 0 additions & 1 deletion test/unittest/funcs/tst.link_ntop.d
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
/* @@xfail: dtv2 */

#pragma D option quiet

Expand Down
85 changes: 85 additions & 0 deletions test/unittest/funcs/tst.link_ntop_runtime_type.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Oracle Linux DTrace.
* Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/

#pragma D option quiet

uint8_t ibaddr[20];

BEGIN
{
mytype = ARPHRD_ETHER;

this->buf_eth = (uint64_t *)alloca(sizeof(uint64_t));

/* Ethernet MAC address 00:01:02:03:04:05 */
*(this->buf_eth) = htonll(0x000102030405 << 16);
printf("%s\n", link_ntop(mytype, this->buf_eth));

/* Ethernet MAC address ff:ff:ff:ff:ff:ff */
*(this->buf_eth) = htonll(0xffffffffffff << 16);
printf("%s\n", link_ntop(mytype, this->buf_eth));

/* Ethernet MAC address 01:33:0a:00:00:01 */
*(this->buf_eth) = htonll(0x01330a000001 << 16);
printf("%s\n", link_ntop(mytype, this->buf_eth));

/* Ethernet MAC address 00:10:e0:8a:71:5e */
*(this->buf_eth) = htonll(0x0010e08a715e << 16);
printf("%s\n", link_ntop(mytype, this->buf_eth));

/* Ethernet MAC address 2:8:20:ac:4:e */
*(this->buf_eth) = htonll(0x020820ac040e << 16);
printf("%s\n", link_ntop(mytype, this->buf_eth));

mytype = ARPHRD_INFINIBAND;

ibaddr[0] = 0x10;
ibaddr[1] = 0x80;
ibaddr[2] = 0x08;
ibaddr[3] = 0x08;
ibaddr[4] = 0x20;
ibaddr[5] = 0x0c;
ibaddr[6] = 0x41;
ibaddr[7] = 0x7a;
ibaddr[8] = 0x01;
ibaddr[9] = 0x7f;
ibaddr[10] = 0x01;
ibaddr[11] = 0xff;
ibaddr[12] = 0xff;
ibaddr[13] = 0x7f;
ibaddr[14] = 0x01;
ibaddr[15] = 0xff;
ibaddr[16] = 0xfe;
ibaddr[17] = 0x7f;
ibaddr[18] = 0x01;
ibaddr[19] = 0xff;
printf("%s\n", link_ntop(mytype, ibaddr));

ibaddr[0] = 0x80;
ibaddr[1] = 0x00;
ibaddr[2] = 0x04;
ibaddr[3] = 0x04;
ibaddr[4] = 0xFE;
ibaddr[5] = 0x8C;
ibaddr[6] = 0x41;
ibaddr[7] = 0x7A;
ibaddr[8] = 0x00;
ibaddr[9] = 0x00;
ibaddr[10] = 0x00;
ibaddr[11] = 0x00;
ibaddr[12] = 0x00;
ibaddr[13] = 0x02;
ibaddr[14] = 0xC9;
ibaddr[15] = 0x02;
ibaddr[16] = 0x00;
ibaddr[17] = 0x29;
ibaddr[18] = 0x31;
ibaddr[19] = 0xCD;
printf("%s\n", link_ntop(mytype, ibaddr));

exit(0);
}
8 changes: 8 additions & 0 deletions test/unittest/funcs/tst.link_ntop_runtime_type.r
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
00:01:02:03:04:05
ff:ff:ff:ff:ff:ff
01:33:0a:00:00:01
00:10:e0:8a:71:5e
02:08:20:ac:04:0e
10:80:08:08:20:0c:41:7a:01:7f:01:ff:ff:7f:01:ff:fe:7f:01:ff
80:00:04:04:fe:8c:41:7a:00:00:00:00:00:02:c9:02:00:29:31:cd

0 comments on commit 371ecc1

Please sign in to comment.