Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
T
tsn-measures
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
tsn-measures
Commits
2ba307c4
Commit
2ba307c4
authored
Sep 24, 2020
by
Joanne Hugé
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Remove poll wake-up for signal emission and XPD
parent
3f5754b5
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
316 additions
and
407 deletions
+316
-407
packet-exchange/src/recv_packet.c
packet-exchange/src/recv_packet.c
+298
-351
packet-exchange/src/recv_packet.h
packet-exchange/src/recv_packet.h
+0
-1
packet-exchange/src/server.c
packet-exchange/src/server.c
+10
-36
scripts/run-server
scripts/run-server
+4
-11
scripts/test-board-synchro
scripts/test-board-synchro
+4
-8
No files found.
packet-exchange/src/recv_packet.c
View file @
2ba307c4
...
...
@@ -63,156 +63,141 @@ static char ts_tracemark_buf[64];
// Sets the interface
static
int
set_if
(
void
)
{
struct
ifreq
ifreq
;
struct
ifreq
ifreq
;
memset
(
&
ifreq
,
0
,
sizeof
(
ifreq
));
strncpy
(
ifreq
.
ifr_name
,
params
->
network_if
,
sizeof
(
ifreq
.
ifr_name
)
-
1
);
memset
(
&
ifreq
,
0
,
sizeof
(
ifreq
));
strncpy
(
ifreq
.
ifr_name
,
params
->
network_if
,
sizeof
(
ifreq
.
ifr_name
)
-
1
);
if
(
ioctl
(
sock_fd
,
SIOCGIFINDEX
,
&
ifreq
))
error
(
EXIT_FAILURE
,
errno
,
"ioctl SIOCGIFINDEX failed
\n
"
);
if
(
ioctl
(
sock_fd
,
SIOCGIFINDEX
,
&
ifreq
))
error
(
EXIT_FAILURE
,
errno
,
"ioctl SIOCGIFINDEX failed
\n
"
);
return
ifreq
.
ifr_ifindex
;
return
ifreq
.
ifr_ifindex
;
}
void
init_udp_recv
(
ingress_param_t
*
_params
,
ingress_stat_t
*
_stats
,
int
_use_histogram
,
uint64_t
*
_kernel_latency_hist
)
{
int
getaddrinfo_err
;
int
set_if_err
;
struct
addrinfo
hints
,
*
servinfo
,
*
servinfo_it
;
params
=
_params
;
stats
=
_stats
;
use_histogram
=
_use_histogram
;
kernel_latency_hist
=
_kernel_latency_hist
;
memset
(
&
hints
,
0
,
sizeof
hints
);
hints
.
ai_family
=
AF_UNSPEC
;
hints
.
ai_socktype
=
SOCK_DGRAM
;
hints
.
ai_flags
=
AI_PASSIVE
;
getaddrinfo_err
=
getaddrinfo
(
NULL
,
SERVER_PORT
,
&
hints
,
&
servinfo
);
if
(
getaddrinfo_err
!=
0
)
{
fprintf
(
stderr
,
"getaddrinfo: %s
\n
"
,
gai_strerror
(
getaddrinfo_err
));
exit
(
EXIT_FAILURE
);
}
for
(
servinfo_it
=
servinfo
;
servinfo_it
;
servinfo_it
=
servinfo_it
->
ai_next
)
{
sock_fd
=
socket
(
servinfo
->
ai_family
,
servinfo
->
ai_socktype
,
servinfo
->
ai_protocol
);
if
(
bind
(
sock_fd
,
servinfo_it
->
ai_addr
,
servinfo_it
->
ai_addrlen
)
==
-
1
)
{
close
(
sock_fd
);
continue
;
}
break
;
}
freeaddrinfo
(
servinfo
);
if
(
sock_fd
==
-
1
)
error
(
EXIT_FAILURE
,
errno
,
"Couldn't create receive socket"
);
set_if_err
=
set_if
();
if
(
set_if_err
<
0
)
error
(
EXIT_FAILURE
,
errno
,
"Couldn't set interface
\n
"
);
if
(
setsockopt
(
sock_fd
,
SOL_SOCKET
,
SO_BINDTODEVICE
,
params
->
network_if
,
strlen
(
params
->
network_if
)))
error
(
EXIT_FAILURE
,
errno
,
"setsockopt SO_BINDTODEVICE failed
\n
"
);
if
(
params
->
use_timestamps
)
{
if
(
setsockopt
(
sock_fd
,
SOL_SOCKET
,
SO_TIMESTAMPING
,
&
so_timestamping_flags
,
sizeof
(
so_timestamping_flags
)))
error
(
EXIT_FAILURE
,
errno
,
"setsockopt SO_TIMESTAMPING failed
\n
"
);
}
int
_use_histogram
,
uint64_t
*
_kernel_latency_hist
)
{
int
getaddrinfo_err
;
int
set_if_err
;
struct
addrinfo
hints
,
*
servinfo
,
*
servinfo_it
;
params
=
_params
;
stats
=
_stats
;
use_histogram
=
_use_histogram
;
kernel_latency_hist
=
_kernel_latency_hist
;
memset
(
&
hints
,
0
,
sizeof
hints
);
hints
.
ai_family
=
AF_UNSPEC
;
hints
.
ai_socktype
=
SOCK_DGRAM
;
hints
.
ai_flags
=
AI_PASSIVE
;
getaddrinfo_err
=
getaddrinfo
(
NULL
,
SERVER_PORT
,
&
hints
,
&
servinfo
);
if
(
getaddrinfo_err
!=
0
)
{
fprintf
(
stderr
,
"getaddrinfo: %s
\n
"
,
gai_strerror
(
getaddrinfo_err
));
exit
(
EXIT_FAILURE
);
}
for
(
servinfo_it
=
servinfo
;
servinfo_it
;
servinfo_it
=
servinfo_it
->
ai_next
)
{
sock_fd
=
socket
(
servinfo
->
ai_family
,
servinfo
->
ai_socktype
,
servinfo
->
ai_protocol
);
if
(
bind
(
sock_fd
,
servinfo_it
->
ai_addr
,
servinfo_it
->
ai_addrlen
)
==
-
1
)
{
close
(
sock_fd
);
continue
;
}
break
;
}
freeaddrinfo
(
servinfo
);
if
(
sock_fd
==
-
1
)
error
(
EXIT_FAILURE
,
errno
,
"Couldn't create receive socket"
);
set_if_err
=
set_if
();
if
(
set_if_err
<
0
)
error
(
EXIT_FAILURE
,
errno
,
"Couldn't set interface
\n
"
);
if
(
setsockopt
(
sock_fd
,
SOL_SOCKET
,
SO_BINDTODEVICE
,
params
->
network_if
,
strlen
(
params
->
network_if
)))
error
(
EXIT_FAILURE
,
errno
,
"setsockopt SO_BINDTODEVICE failed
\n
"
);
if
(
params
->
use_timestamps
)
{
if
(
setsockopt
(
sock_fd
,
SOL_SOCKET
,
SO_TIMESTAMPING
,
&
so_timestamping_flags
,
sizeof
(
so_timestamping_flags
)))
error
(
EXIT_FAILURE
,
errno
,
"setsockopt SO_TIMESTAMPING failed
\n
"
);
}
}
/*
* Receive UDP packet
*/
void
recv_udp_packet
()
{
struct
cmsghdr
*
cmsg
;
struct
msghdr
msg
;
// Message hardware, sent to the socket
struct
iovec
iov
;
// The iovec structures stores the RX buffer
struct
sockaddr_in
sin
;
struct
{
struct
cmsghdr
cm
;
char
control
[
512
];
}
control
;
int
recvmsgerr
;
struct
timespec
ts
;
iov
.
iov_base
=
&
rx_buffer
;
iov
.
iov_len
=
MAX_BUFFER_SIZE
-
1
;
memset
(
&
msg
,
0
,
sizeof
(
msg
));
msg
.
msg_name
=
&
sin
;
msg
.
msg_namelen
=
sizeof
(
sin
);
msg
.
msg_iov
=
&
iov
;
msg
.
msg_iovlen
=
1
;
msg
.
msg_control
=
&
control
;
msg
.
msg_controllen
=
sizeof
(
control
);
recvmsgerr
=
recvmsg
(
sock_fd
,
&
msg
,
0
);
if
(
recvmsgerr
<
0
)
error
(
EXIT_FAILURE
,
errno
,
"recvmsg failed, ret value: %d
\n
"
,
recvmsgerr
);
if
(
params
->
use_timestamps
)
{
clock_gettime
(
CLOCK_REALTIME
,
&
ts
);
post_kernel_timestamp
=
ts_to_uint
(
ts
);
}
if
(
params
->
use_timestamps
)
{
for
(
cmsg
=
CMSG_FIRSTHDR
(
&
msg
);
cmsg
;
cmsg
=
CMSG_NXTHDR
(
&
msg
,
cmsg
))
{
if
(
cmsg
->
cmsg_level
==
SOL_SOCKET
&&
cmsg
->
cmsg_type
==
SO_TIMESTAMPING
)
{
struct
timespec
*
stamp
=
(
struct
timespec
*
)
CMSG_DATA
(
cmsg
);
if
(
params
->
enable_ts_tracemark
)
{
sprintf
(
ts_tracemark_buf
,
"%"
PRIu64
,
ts_to_uint
(
*
stamp
));
tracemark
(
ts_tracemark_buf
);
}
else
{
uint64_t
kernel_latency
=
post_kernel_timestamp
-
ts_to_uint
(
*
stamp
);
kernel_latency
/=
1000u
;
stats
->
min_kernel_latency
=
_min_
(
kernel_latency
,
stats
->
min_kernel_latency
);
stats
->
max_kernel_latency
=
_max_
(
kernel_latency
,
stats
->
max_kernel_latency
);
stats
->
avg_kernel_latency
=
(
stats
->
max_kernel_latency
*
(
stats
->
packets_received
)
+
kernel_latency
)
/
(
stats
->
packets_received
+
1
);
if
(
use_histogram
)
{
if
(
kernel_latency
>
MAX_KERNEL_LATENCY
)
stats
->
high_kernel_latency
++
;
else
kernel_latency_hist
[
kernel_latency
]
++
;
}
}
}
}
}
for
(
int
i
=
0
;
i
<
MAX_BUFFER_SIZE
;
i
++
)
stats
->
data
[
i
]
=
rx_buffer
[
i
];
struct
cmsghdr
*
cmsg
;
struct
msghdr
msg
;
// Message hardware, sent to the socket
struct
iovec
iov
;
// The iovec structures stores the RX buffer
struct
sockaddr_in
sin
;
struct
{
struct
cmsghdr
cm
;
char
control
[
512
];
}
control
;
int
recvmsgerr
;
struct
timespec
ts
;
iov
.
iov_base
=
&
rx_buffer
;
iov
.
iov_len
=
MAX_BUFFER_SIZE
-
1
;
memset
(
&
msg
,
0
,
sizeof
(
msg
));
msg
.
msg_name
=
&
sin
;
msg
.
msg_namelen
=
sizeof
(
sin
);
msg
.
msg_iov
=
&
iov
;
msg
.
msg_iovlen
=
1
;
msg
.
msg_control
=
&
control
;
msg
.
msg_controllen
=
sizeof
(
control
);
recvmsgerr
=
recvmsg
(
sock_fd
,
&
msg
,
0
);
if
(
recvmsgerr
<
0
)
error
(
EXIT_FAILURE
,
errno
,
"recvmsg failed, ret value: %d
\n
"
,
recvmsgerr
);
if
(
params
->
use_timestamps
)
{
clock_gettime
(
CLOCK_REALTIME
,
&
ts
);
post_kernel_timestamp
=
ts_to_uint
(
ts
);
}
if
(
params
->
use_timestamps
)
{
for
(
cmsg
=
CMSG_FIRSTHDR
(
&
msg
);
cmsg
;
cmsg
=
CMSG_NXTHDR
(
&
msg
,
cmsg
))
{
if
(
cmsg
->
cmsg_level
==
SOL_SOCKET
&&
cmsg
->
cmsg_type
==
SO_TIMESTAMPING
)
{
struct
timespec
*
stamp
=
(
struct
timespec
*
)
CMSG_DATA
(
cmsg
);
if
(
params
->
enable_ts_tracemark
)
{
sprintf
(
ts_tracemark_buf
,
"%"
PRIu64
,
ts_to_uint
(
*
stamp
));
tracemark
(
ts_tracemark_buf
);
}
else
{
uint64_t
kernel_latency
=
post_kernel_timestamp
-
ts_to_uint
(
*
stamp
);
kernel_latency
/=
1000u
;
stats
->
min_kernel_latency
=
_min_
(
kernel_latency
,
stats
->
min_kernel_latency
);
stats
->
max_kernel_latency
=
_max_
(
kernel_latency
,
stats
->
max_kernel_latency
);
stats
->
avg_kernel_latency
=
(
stats
->
max_kernel_latency
*
(
stats
->
packets_received
)
+
kernel_latency
)
/
(
stats
->
packets_received
+
1
);
if
(
use_histogram
)
{
if
(
kernel_latency
>
MAX_KERNEL_LATENCY
)
stats
->
high_kernel_latency
++
;
else
kernel_latency_hist
[
kernel_latency
]
++
;
}
}
}
}
}
for
(
int
i
=
0
;
i
<
MAX_BUFFER_SIZE
;
i
++
)
stats
->
data
[
i
]
=
rx_buffer
[
i
];
}
#ifdef WITH_XDP
...
...
@@ -222,215 +207,180 @@ static unsigned int ifindex;
static
struct
xdpsock
xdp_socket
;
static
void
open_xdp_socket
(
char
*
network_if
)
{
struct
xsk_socket_config
xsk_cfg
;
uint32_t
idx
;
int
ret
,
i
;
/* Create XDP socket */
xsk_cfg
.
rx_size
=
XSK_RING_CONS__DEFAULT_NUM_DESCS
;
xsk_cfg
.
tx_size
=
XSK_RING_PROD__DEFAULT_NUM_DESCS
;
xsk_cfg
.
libbpf_flags
=
0
;
xsk_cfg
.
xdp_flags
=
xdp_flags
;
xsk_cfg
.
bind_flags
=
0
;
ret
=
xsk_socket__create
(
&
xdp_socket
.
xsk
,
network_if
,
0
,
xdp_socket
.
umem
.
umem
,
&
xdp_socket
.
rx
,
&
xdp_socket
.
tx
,
&
xsk_cfg
);
if
(
ret
)
err
(
"xsk_socket__create() failed"
);
/* Add some buffers */
ret
=
xsk_ring_prod__reserve
(
&
xdp_socket
.
umem
.
fq
,
XSK_RING_PROD__DEFAULT_NUM_DESCS
,
&
idx
);
if
(
ret
!=
XSK_RING_PROD__DEFAULT_NUM_DESCS
)
err
(
"xsk_ring_prod__reserve() failed"
);
for
(
i
=
0
;
i
<
XSK_RING_PROD__DEFAULT_NUM_DESCS
;
i
++
)
*
xsk_ring_prod__fill_addr
(
&
xdp_socket
.
umem
.
fq
,
idx
++
)
=
i
*
FRAME_SIZE
;
xsk_ring_prod__submit
(
&
xdp_socket
.
umem
.
fq
,
XSK_RING_PROD__DEFAULT_NUM_DESCS
);
struct
xsk_socket_config
xsk_cfg
;
uint32_t
idx
;
int
ret
,
i
;
/* Create XDP socket */
xsk_cfg
.
rx_size
=
XSK_RING_CONS__DEFAULT_NUM_DESCS
;
xsk_cfg
.
tx_size
=
XSK_RING_PROD__DEFAULT_NUM_DESCS
;
xsk_cfg
.
libbpf_flags
=
0
;
xsk_cfg
.
xdp_flags
=
xdp_flags
;
xsk_cfg
.
bind_flags
=
0
;
ret
=
xsk_socket__create
(
&
xdp_socket
.
xsk
,
network_if
,
0
,
xdp_socket
.
umem
.
umem
,
&
xdp_socket
.
rx
,
&
xdp_socket
.
tx
,
&
xsk_cfg
);
if
(
ret
)
err
(
"xsk_socket__create() failed"
);
/* Add some buffers */
ret
=
xsk_ring_prod__reserve
(
&
xdp_socket
.
umem
.
fq
,
XSK_RING_PROD__DEFAULT_NUM_DESCS
,
&
idx
);
if
(
ret
!=
XSK_RING_PROD__DEFAULT_NUM_DESCS
)
err
(
"xsk_ring_prod__reserve() failed"
);
for
(
i
=
0
;
i
<
XSK_RING_PROD__DEFAULT_NUM_DESCS
;
i
++
)
*
xsk_ring_prod__fill_addr
(
&
xdp_socket
.
umem
.
fq
,
idx
++
)
=
i
*
FRAME_SIZE
;
xsk_ring_prod__submit
(
&
xdp_socket
.
umem
.
fq
,
XSK_RING_PROD__DEFAULT_NUM_DESCS
);
}
/*
* Init XDP socket
*/
void
init_xdp_recv
(
ingress_param_t
*
_params
,
ingress_stat_t
*
_stats
)
{
int
ret
,
prog_fd
,
xsks_map
=
0
;
struct
bpf_prog_load_attr
prog_load_attr
=
{
.
prog_type
=
BPF_PROG_TYPE_XDP
,
.
file
=
"/home/oli/tsn-measures/packet-exchange/build/xdp_kern.o"
,
};
struct
xsk_umem_config
cfg
=
{
.
fill_size
=
XSK_RING_PROD__DEFAULT_NUM_DESCS
,
.
comp_size
=
XSK_RING_CONS__DEFAULT_NUM_DESCS
,
.
frame_size
=
FRAME_SIZE
,
.
frame_headroom
=
XSK_UMEM__DEFAULT_FRAME_HEADROOM
,
.
flags
=
0
,
};
struct
bpf_object
*
obj
;
struct
bpf_map
*
map
;
void
*
buffer
=
NULL
;
params
=
_params
;
stats
=
_stats
;
ret
=
bpf_prog_load_xattr
(
&
prog_load_attr
,
&
obj
,
&
prog_fd
);
if
(
ret
||
prog_fd
<
0
)
err
(
"bpf_prog_load_xattr() failed"
);
map
=
bpf_object__find_map_by_name
(
obj
,
"xsks_map"
);
xsks_map
=
bpf_map__fd
(
map
);
if
(
xsks_map
<
0
)
err
(
"No xsks_map found!"
);
ifindex
=
if_nametoindex
(
params
->
network_if
);
if
(
!
ifindex
)
err_errno
(
"if_nametoindex() failed"
);
/* Use XDP _only_ in conjuction with driver assisted mode */
ret
=
bpf_set_link_xdp_fd
(
ifindex
,
prog_fd
,
xdp_flags
);
if
(
ret
)
err
(
"bpf_set_link_xdp_fd() failed"
);
/* Allocate user space memory for xdp frames */
ret
=
posix_memalign
(
&
buffer
,
sysconf
(
_SC_PAGE_SIZE
),
NUM_FRAMES
*
FRAME_SIZE
);
if
(
ret
)
err_errno
(
"posix_memalign() failed"
);
ret
=
xsk_umem__create
(
&
xdp_socket
.
umem
.
umem
,
buffer
,
NUM_FRAMES
*
FRAME_SIZE
,
&
xdp_socket
.
umem
.
fq
,
&
xdp_socket
.
umem
.
cq
,
&
cfg
);
if
(
ret
)
err
(
"xsk_umem__create() failed"
);
xdp_socket
.
umem
.
buffer
=
buffer
;
/* Open and bind socket */
open_xdp_socket
(
params
->
network_if
);
void
init_xdp_recv
(
ingress_param_t
*
_params
,
ingress_stat_t
*
_stats
)
{
int
ret
,
prog_fd
,
xsks_map
=
0
;
struct
bpf_prog_load_attr
prog_load_attr
=
{
.
prog_type
=
BPF_PROG_TYPE_XDP
,
.
file
=
"/home/oli/tsn-measures/packet-exchange/build/xdp_kern.o"
,
};
struct
xsk_umem_config
cfg
=
{
.
fill_size
=
XSK_RING_PROD__DEFAULT_NUM_DESCS
,
.
comp_size
=
XSK_RING_CONS__DEFAULT_NUM_DESCS
,
.
frame_size
=
FRAME_SIZE
,
.
frame_headroom
=
XSK_UMEM__DEFAULT_FRAME_HEADROOM
,
.
flags
=
0
,
};
struct
bpf_object
*
obj
;
struct
bpf_map
*
map
;
void
*
buffer
=
NULL
;
params
=
_params
;
stats
=
_stats
;
ret
=
bpf_prog_load_xattr
(
&
prog_load_attr
,
&
obj
,
&
prog_fd
);
if
(
ret
||
prog_fd
<
0
)
err
(
"bpf_prog_load_xattr() failed"
);
map
=
bpf_object__find_map_by_name
(
obj
,
"xsks_map"
);
xsks_map
=
bpf_map__fd
(
map
);
if
(
xsks_map
<
0
)
err
(
"No xsks_map found!"
);
ifindex
=
if_nametoindex
(
params
->
network_if
);
if
(
!
ifindex
)
err_errno
(
"if_nametoindex() failed"
);
/* Use XDP _only_ in conjuction with driver assisted mode */
ret
=
bpf_set_link_xdp_fd
(
ifindex
,
prog_fd
,
xdp_flags
);
if
(
ret
)
err
(
"bpf_set_link_xdp_fd() failed"
);
/* Allocate user space memory for xdp frames */
ret
=
posix_memalign
(
&
buffer
,
sysconf
(
_SC_PAGE_SIZE
),
NUM_FRAMES
*
FRAME_SIZE
);
if
(
ret
)
err_errno
(
"posix_memalign() failed"
);
ret
=
xsk_umem__create
(
&
xdp_socket
.
umem
.
umem
,
buffer
,
NUM_FRAMES
*
FRAME_SIZE
,
&
xdp_socket
.
umem
.
fq
,
&
xdp_socket
.
umem
.
cq
,
&
cfg
);
if
(
ret
)
err
(
"xsk_umem__create() failed"
);
xdp_socket
.
umem
.
buffer
=
buffer
;
/* Open and bind socket */
open_xdp_socket
(
params
->
network_if
);
}
void
setup_poll_fd
(
void
)
{
fds
[
0
].
fd
=
xsk_socket__fd
(
xdp_socket
.
xsk
);
fds
[
0
].
events
=
POLLIN
;
fds
[
0
].
fd
=
xsk_socket__fd
(
xdp_socket
.
xsk
);
fds
[
0
].
events
=
POLLIN
;
}
static
int
received
;
static
uint32_t
idx_rx
=
0
,
idx
;
static
void
p
oll_wakeup
(
struct
timespec
ts
,
int
margi
n
)
{
int
r
et
;
struct
timespec
ts_prev
,
current
;
ts_prev
=
ts
;
s
ubstract_ns
(
&
ts_prev
,
margin
*
1000
);
static
void
p
arse_raw_packet
(
uint64_t
addr
,
size_t
le
n
)
{
char
*
pack
et
;
struct
ethhdr
*
eth
;
struct
iphdr
*
ip
;
struct
udphdr
*
udp
;
s
ize_t
min_len
=
sizeof
(
*
eth
)
+
sizeof
(
*
ip
)
+
sizeof
(
*
udp
);
ret
=
clock_nanosleep
(
CLOCK_REALTIME
,
TIMER_ABSTIME
,
&
ts_prev
,
NULL
);
if
(
ret
)
{
fprintf
(
stderr
,
"clock_nanosleep returned error: %d, aborting...
\n
"
,
ret
);
exit
(
EXIT_FAILURE
);
if
(
len
<=
min_len
)
{
stats
->
xdp_data
=
NULL
;
return
;
}
do
{
clock_gettime
(
CLOCK_REALTIME
,
&
current
);
}
while
(
calcdiff_ns_signed
(
ts
,
current
)
>
1000
);
}
static
void
parse_raw_packet
(
uint64_t
addr
,
size_t
len
)
{
char
*
packet
;
struct
ethhdr
*
eth
;
struct
iphdr
*
ip
;
struct
udphdr
*
udp
;
size_t
min_len
=
sizeof
(
*
eth
)
+
sizeof
(
*
ip
)
+
sizeof
(
*
udp
);
if
(
len
<=
min_len
)
{
stats
->
xdp_data
=
NULL
;
return
;
}
packet
=
xsk_umem__get_data
(
xdp_socket
.
umem
.
buffer
,
addr
);
packet
=
xsk_umem__get_data
(
xdp_socket
.
umem
.
buffer
,
addr
);
eth
=
(
struct
ethhdr
*
)
packet
;
ip
=
(
struct
iphdr
*
)(
packet
+
sizeof
(
*
eth
));
udp
=
(
struct
udphdr
*
)(
packet
+
sizeof
(
*
eth
)
+
sizeof
(
*
ip
));
eth
=
(
struct
ethhdr
*
)
packet
;
ip
=
(
struct
iphdr
*
)(
packet
+
sizeof
(
*
eth
));
udp
=
(
struct
udphdr
*
)(
packet
+
sizeof
(
*
eth
)
+
sizeof
(
*
ip
));
stats
->
xdp_data
=
packet
+
sizeof
(
*
eth
)
+
sizeof
(
*
ip
)
+
sizeof
(
*
udp
);
stats
->
xdp_data
=
packet
+
sizeof
(
*
eth
)
+
sizeof
(
*
ip
)
+
sizeof
(
*
udp
);
}
/*
* Receive XDP socket
*/
int
recv_xdp_packet
(
struct
timespec
next
)
{
int
ret
;
uint64_t
addr
;
uint32_t
len
;
struct
timespec
next_pre
,
current
;
int
k
=
0
;
if
(
params
->
xdp_polling_mode
==
0
)
{
ret
=
poll
(
fds
,
1
,
-
1
);
if
(
ret
==
0
)
{
return
-
1
;
}
else
if
(
ret
<
0
)
error
(
EXIT_FAILURE
,
errno
,
"poll failed"
);
received
=
xsk_ring_cons__peek
(
&
xdp_socket
.
rx
,
1
,
&
idx_rx
);
}
else
{
next_pre
=
next
;
substract_ns
(
&
next_pre
,
120
*
1000
);
ret
=
clock_nanosleep
(
CLOCK_REALTIME
,
TIMER_ABSTIME
,
&
next_pre
,
NULL
);
if
(
ret
)
{
fprintf
(
stderr
,
"clock_nanosleep returned error: %d, aborting...
\n
"
,
ret
);
exit
(
EXIT_FAILURE
);
}
int
ret
;
uint64_t
addr
;
uint32_t
len
;
struct
timespec
next_pre
,
current
;
int
k
=
0
;
ret
=
poll
(
fds
,
1
,
-
1
);
if
(
ret
!=
1
)
error
(
EXIT_FAILURE
,
errno
,
"poll failed"
);
do
{
received
=
xsk_ring_cons__peek
(
&
xdp_socket
.
rx
,
1
,
&
idx_rx
);
}
while
(
!
received
);
}
received
=
xsk_ring_cons__peek
(
&
xdp_socket
.
rx
,
1
,
&
idx_rx
);
if
(
received
!=
1
)
error
(
EXIT_FAILURE
,
errno
,
"Received %d packets"
,
received
);
if
(
received
!=
1
)
error
(
EXIT_FAILURE
,
errno
,
"Received %d packets"
,
received
);
/* Get the packet */
addr
=
xsk_ring_cons__rx_desc
(
&
xdp_socket
.
rx
,
idx_rx
)
->
addr
;
len
=
xsk_ring_cons__rx_desc
(
&
xdp_socket
.
rx
,
idx_rx
)
->
len
;
/* Get the packet */
addr
=
xsk_ring_cons__rx_desc
(
&
xdp_socket
.
rx
,
idx_rx
)
->
addr
;
len
=
xsk_ring_cons__rx_desc
(
&
xdp_socket
.
rx
,
idx_rx
)
->
len
;
/* Parse it */
parse_raw_packet
(
xsk_umem__add_offset_to_addr
(
addr
),
len
);
/* Parse it */
parse_raw_packet
(
xsk_umem__add_offset_to_addr
(
addr
),
len
);
return
0
;
return
0
;
}
void
recv_xdp_cleanup
(
void
)
{
uint64_t
addr
;
int
ret
;
uint64_t
addr
;
int
ret
;
/* Cleanup */
xsk_ring_cons__release
(
&
xdp_socket
.
rx
,
received
);
/* Cleanup */
xsk_ring_cons__release
(
&
xdp_socket
.
rx
,
received
);
/* Add that particular buffer back to the fill queue */
if
(
xsk_prod_nb_free
(
&
xdp_socket
.
umem
.
fq
,
received
))
{
ret
=
xsk_ring_prod__reserve
(
&
xdp_socket
.
umem
.
fq
,
received
,
&
idx
);
/* Add that particular buffer back to the fill queue */
if
(
xsk_prod_nb_free
(
&
xdp_socket
.
umem
.
fq
,
received
))
{
ret
=
xsk_ring_prod__reserve
(
&
xdp_socket
.
umem
.
fq
,
received
,
&
idx
);
if
(
ret
!=
received
)
err
(
"xsk_ring_prod__reserve() failed"
);
if
(
ret
!=
received
)
err
(
"xsk_ring_prod__reserve() failed"
);
*
xsk_ring_prod__fill_addr
(
&
xdp_socket
.
umem
.
fq
,
idx
)
=
xsk_umem__extract_addr
(
addr
);
*
xsk_ring_prod__fill_addr
(
&
xdp_socket
.
umem
.
fq
,
idx
)
=
xsk_umem__extract_addr
(
addr
);
xsk_ring_prod__submit
(
&
xdp_socket
.
umem
.
fq
,
received
);
}
xsk_ring_prod__submit
(
&
xdp_socket
.
umem
.
fq
,
received
);
}
}
void
close_xdp_socket
(
void
)
{
xsk_socket__delete
(
xdp_socket
.
xsk
);
xsk_umem__delete
(
xdp_socket
.
umem
.
umem
);
bpf_set_link_xdp_fd
(
ifindex
,
-
1
,
xdp_flags
);
xsk_socket__delete
(
xdp_socket
.
xsk
);
xsk_umem__delete
(
xdp_socket
.
umem
.
umem
);
bpf_set_link_xdp_fd
(
ifindex
,
-
1
,
xdp_flags
);
}
#else
void
init_xdp_recv
(
ingress_param_t
*
_params
,
ingress_stat_t
*
_stats
)
{
(
void
)
_params
;
(
void
)
_stats
;
}
void
init_xdp_recv
(
ingress_param_t
*
_params
,
ingress_stat_t
*
_stats
)
{
(
void
)
_params
;
(
void
)
_stats
;
}
void
setup_poll_fd
(
void
)
{}
void
close_xdp_socket
(
void
)
{}
int
recv_xdp_packet
(
struct
timespec
next
)
{
(
void
)
next
;
return
0
;
}
int
recv_xdp_packet
(
struct
timespec
next
)
{
(
void
)
next
;
return
0
;
}
void
recv_xdp_cleanup
(
void
)
{}
#endif
...
...
@@ -440,53 +390,50 @@ void recv_xdp_cleanup(void) {}
* Code from scheduled_tx_tools
*/
static
int
process_socket_error_queue
(
void
)
{
uint8_t
msg_control
[
CMSG_SPACE
(
sizeof
(
struct
sock_extended_err
))];
unsigned
char
err_buffer
[
256
];
struct
sock_extended_err
*
serr
;
struct
cmsghdr
*
cmsg
;
__u64
tstamp
=
0
;
struct
iovec
iov
=
{.
iov_base
=
err_buffer
,
.
iov_len
=
sizeof
(
err_buffer
)};
struct
msghdr
msg
=
{.
msg_iov
=
&
iov
,
.
msg_iovlen
=
1
,
.
msg_control
=
msg_control
,
.
msg_controllen
=
sizeof
(
msg_control
)};
if
(
recvmsg
(
sock_fd
,
&
msg
,
MSG_ERRQUEUE
)
==
-
1
)
{
fprintf
(
stderr
,
"recvmsg failed"
);
return
-
1
;
}
cmsg
=
CMSG_FIRSTHDR
(
&
msg
);
while
(
cmsg
!=
NULL
)
{
serr
=
(
void
*
)
CMSG_DATA
(
cmsg
);
if
(
serr
->
ee_origin
==
SO_EE_ORIGIN_TXTIME
)
{
tstamp
=
((
__u64
)
serr
->
ee_data
<<
32
)
+
serr
->
ee_info
;
switch
(
serr
->
ee_code
)
{
case
SO_EE_CODE_TXTIME_INVALID_PARAM
:
fprintf
(
stderr
,
"packet with tstamp %llu dropped "
"due to invalid params
\n
"
,
tstamp
);
return
0
;
case
SO_EE_CODE_TXTIME_MISSED
:
fprintf
(
stderr
,
"packet with tstamp %llu dropped "
"due to missed deadline
\n
"
,
tstamp
);
return
0
;
default:
return
-
1
;
}
}
cmsg
=
CMSG_NXTHDR
(
&
msg
,
cmsg
);
}
return
0
;
uint8_t
msg_control
[
CMSG_SPACE
(
sizeof
(
struct
sock_extended_err
))];
unsigned
char
err_buffer
[
256
];
struct
sock_extended_err
*
serr
;
struct
cmsghdr
*
cmsg
;
__u64
tstamp
=
0
;
struct
iovec
iov
=
{.
iov_base
=
err_buffer
,
.
iov_len
=
sizeof
(
err_buffer
)};
struct
msghdr
msg
=
{.
msg_iov
=
&
iov
,
.
msg_iovlen
=
1
,
.
msg_control
=
msg_control
,
.
msg_controllen
=
sizeof
(
msg_control
)};
if
(
recvmsg
(
sock_fd
,
&
msg
,
MSG_ERRQUEUE
)
==
-
1
)
{
fprintf
(
stderr
,
"recvmsg failed"
);
return
-
1
;
}
cmsg
=
CMSG_FIRSTHDR
(
&
msg
);
while
(
cmsg
!=
NULL
)
{
serr
=
(
void
*
)
CMSG_DATA
(
cmsg
);
if
(
serr
->
ee_origin
==
SO_EE_ORIGIN_TXTIME
)
{
tstamp
=
((
__u64
)
serr
->
ee_data
<<
32
)
+
serr
->
ee_info
;
switch
(
serr
->
ee_code
)
{
case
SO_EE_CODE_TXTIME_INVALID_PARAM
:
fprintf
(
stderr
,
"packet with tstamp %llu dropped "
"due to invalid params
\n
"
,
tstamp
);
return
0
;
case
SO_EE_CODE_TXTIME_MISSED
:
fprintf
(
stderr
,
"packet with tstamp %llu dropped "
"due to missed deadline
\n
"
,
tstamp
);
return
0
;
default:
return
-
1
;
}
}
cmsg
=
CMSG_NXTHDR
(
&
msg
,
cmsg
);
}
return
0
;
}
#endif
packet-exchange/src/recv_packet.h
View file @
2ba307c4
...
...
@@ -8,7 +8,6 @@ typedef struct ingress_param {
int
use_timestamps
;
int
enable_ts_tracemark
;
int
xdp_polling_mode
;
uint64_t
interval
;
size_t
tx_buffer_len
;
...
...
packet-exchange/src/server.c
View file @
2ba307c4
...
...
@@ -48,9 +48,6 @@ typedef struct thread_param {
uint64_t
start_ts
;
int
poll
;
int
poll_margin
;
}
thread_param_t
;
typedef
struct
main_params
{
...
...
@@ -93,7 +90,7 @@ static char ts_tracemark_buf[64];
static
void
help
(
char
*
argv
[])
{
printf
(
"Usage: %s [-f IF -a CPU -p PRIO -i USEC -r USEC] [-b CLIENT_IP] [-d "
"BUF_LEN -cgtv] [-T LATENCY_THRESHOLD -G] [-x
POLL_MODE -
X]
\n\n
"
"BUF_LEN -cgtv] [-T LATENCY_THRESHOLD -G] [-xX]
\n\n
"
" -h Show help
\n
"
" -f IF Set the network interface to be used
\n
"
" -a CPU Pin the real time thread to CPU
\n
"
...
...
@@ -103,13 +100,11 @@ static void help(char *argv[]) {
" -d BUF_LEN Set the length of tx buffer
\n
"
" -c Receive timestamp and emit signal
\n
"
" -s NS Common start time reference
\n
"
" -P USEC Do polling to wakeup signal thread with specified margin
\n
"
" -C Receive timestamp and print difference with current time
\n
"
" -b CLIENT_IP Server side RTT
\n
"
" -g Print histograms to sdtout on exit
\n
"
" -t Enable timestamps
\n
"
" -x POLL_MODE Use AF_XDP sockets
\n
"
" POLL_MODE: 0 for polling, 1 for combination of both
\n
"
" -x Use AF_XDP sockets
\n
"
" -X Trace during XDP packet reception
\n
"
" -T THRESHOLD Enable tracing until THRESHOLD is reached
\n
"
" -M Send tracemark when packet is received
\n
"
...
...
@@ -119,30 +114,13 @@ static void help(char *argv[]) {
argv
[
0
]);
}
static
void
poll_wakeup
(
struct
timespec
ts
,
int
margin
)
{
int
ret
;
struct
timespec
ts_prev
,
current
;
ts_prev
=
ts
;
substract_ns
(
&
ts_prev
,
margin
*
1000
);
ret
=
clock_nanosleep
(
CLOCK_REALTIME
,
TIMER_ABSTIME
,
&
ts_prev
,
NULL
);
if
(
ret
)
{
fprintf
(
stderr
,
"clock_nanosleep returned error: %d, aborting...
\n
"
,
ret
);
exit
(
EXIT_FAILURE
);
}
do
{
clock_gettime
(
CLOCK_REALTIME
,
&
current
);
}
while
(
calcdiff_ns_signed
(
ts
,
current
)
>
1000
);
}
static
void
*
emit_signal_thread
(
void
*
p
)
{
(
void
)
p
;
cpu_set_t
mask
;
struct
timespec
current
;
struct
timespec
previous_emit
,
previous_ts
;
int64_t
emit_diff
,
ts_diff
;
int
ret
;
// Set thread CPU affinity
if
(
thread_params
.
affinity_cpu
)
{
...
...
@@ -157,15 +135,18 @@ static void *emit_signal_thread(void *p) {
for
(
int
i
=
0
;;
i
++
)
{
pthread_cond_wait
(
&
emit_signal_ts_received
,
&
emit_signal_mutex
);
clock_gettime
(
CLOCK_REALTIME
,
&
current
);
poll_wakeup
(
emit_signal_next
,
thread_params
.
poll_margin
);
ret
=
clock_nanosleep
(
CLOCK_REALTIME
,
TIMER_ABSTIME
,
&
emit_signal_next
,
NULL
);
if
(
ret
)
{
fprintf
(
stderr
,
"clock_nanosleep returned error: %d, aborting...
\n
"
,
ret
);
exit
(
EXIT_FAILURE
);
}
toggle_gpio
();
clock_gettime
(
CLOCK_REALTIME
,
&
current
);
// Check if something went wrong
if
(
i
>
0
)
{
clock_gettime
(
CLOCK_REALTIME
,
&
current
);
emit_diff
=
calcdiff_ns_signed
(
current
,
previous_emit
);
ts_diff
=
calcdiff_ns_signed
(
emit_signal_next
,
previous_ts
);
if
((
emit_diff
<
((
int64_t
)
thread_params
.
interval
)
-
ERROR_MARGIN_NS
)
||
...
...
@@ -397,8 +378,6 @@ int main(int argc, char *argv[]) {
thread_params
.
affinity_cpu
=
0
;
thread_params
.
enable_diff_ts
=
0
;
thread_params
.
enable_receive_tracemark
=
0
;
thread_params
.
poll
=
0
;
thread_params
.
poll_margin
=
75
;
thread_params
.
start_ts
=
0
;
main_params
.
refresh_rate
=
50000
;
main_params
.
verbose
=
0
;
...
...
@@ -557,7 +536,7 @@ static void process_options(int argc, char *argv[]) {
int
network_if_specified
=
0
;
for
(;;)
{
int
c
=
getopt
(
argc
,
argv
,
"a:b:cCs:d:f:ghi:p:r:tvx
:XT:GMSP:
"
);
int
c
=
getopt
(
argc
,
argv
,
"a:b:cCs:d:f:ghi:p:r:tvx
XT:GMS
"
);
if
(
c
==
-
1
)
break
;
...
...
@@ -613,7 +592,6 @@ static void process_options(int argc, char *argv[]) {
break
;
case
'x'
:
tsn_task
=
XDP_TASK
;
ingress_params
.
xdp_polling_mode
=
atoi
(
optarg
);
break
;
case
'X'
:
main_params
.
enable_xdp_tracing
=
1
;
...
...
@@ -628,10 +606,6 @@ static void process_options(int argc, char *argv[]) {
case
'S'
:
ingress_params
.
enable_ts_tracemark
=
1
;
break
;
case
'P'
:
thread_params
.
poll
=
1
;
thread_params
.
poll_margin
=
atoi
(
optarg
);
break
;
}
}
...
...
scripts/run-server
View file @
2ba307c4
...
...
@@ -10,18 +10,14 @@ usage() {
cat
<<
ENDUSAGE
Usage:
$0
[-h] [-I if] [SERVER] | TCPDUMP [TRACE_OPTS]
-h Show help
SERVER: -bct
((-x | -X) POLL)
-g INTERVAL -a CPU
SERVER: -bct
X
-g INTERVAL -a CPU
Options passed to the C server program (everything here is optional)
-b Send back packets for round trip measurements
-c USEC Emit a signal on GPIO at the timestamp given in packet, specify interval
(to be used with -c option in client program)
-O USEC Do polling to wakeup signal thread with specified margin
-C USEC Measure difference between current time and timestamp sent in tx data
-t Use SO_TIMESTAMPS to see how much time packet spent in kernel
-x POLL Use XDP sockets, with a global libbpf installation
-X POLL Use XDP sockets, with libbpf located in
\$
HOME/libbpf folder
POLL: Polling mode used in server program, 0 to poll with poll function,
1 to do active polling
-X Use XDP sockets, with libbpf located in
\$
HOME/libbpf folder
-s NS Specify a CLOCK_REALTIME timestamp at which client should start
(to be used with PTP) (interval needs to be specified with -j)
-j USEC Specify interval (used with -s)
...
...
@@ -60,7 +56,7 @@ tracecmd_events="-e irq -e sched -e net -e napi"
tracecmd_opts
=
""
cpu
=
1
while
getopts
"j:a:b:c:C:htx:X
:s:d:i:g:I:T:E:P:B:MSQO:
"
opt
;
do
while
getopts
"j:a:b:c:C:htx:X
s:d:i:g:I:T:E:P:B:MSQ
"
opt
;
do
case
"
${
opt
}
"
in
h
)
usage
...
...
@@ -78,9 +74,6 @@ while getopts "j:a:b:c:C:htx:X:s:d:i:g:I:T:E:P:B:MSQO:" opt; do
c
)
server_options+
=
" -c -i
${
OPTARG
}
"
;;
O
)
server_options+
=
" -P
${
OPTARG
}
"
;;
C
)
server_options+
=
" -C -i
${
OPTARG
}
"
;;
...
...
@@ -107,7 +100,7 @@ while getopts "j:a:b:c:C:htx:X:s:d:i:g:I:T:E:P:B:MSQO:" opt; do
interface
=
"
${
OPTARG
}
"
;;
X
)
server_options+
=
" -x
${
OPTARG
}
"
server_options+
=
" -x "
make_opts
=
" -e WITH_GIT_XDP=1"
;;
s
)
...
...
scripts/test-board-synchro
View file @
2ba307c4
...
...
@@ -4,13 +4,12 @@ script_dir=$(dirname $(realpath $0))
usage
()
{
cat
<<
ENDUSAGE
Usage:
$0
[-h] [-i USEC -c USEC -t MSEC] [-T] BOARD1_HOSTNAME BOARD2_HOSTNAME
Usage:
$0
[-h] [-i USEC -c USEC -t MSEC] [-T
X
] BOARD1_HOSTNAME BOARD2_HOSTNAME
-h Show help
-i USEC Specify which interval to use in client
-c USEC Specify which offset to use for the timestamp in the packet
-t MSEC Set the start timestamp offset
-P USEC Do polling to wakeup signal thread with specified margin
-X POLL_MODE Use XDP with specified poll mode
-X Use XDP
-T Enable tracing on the boards
BOARD_HOSTNAME Uses /etc/hosts to find the IP address associated to the hostname
ENDUSAGE
...
...
@@ -23,7 +22,7 @@ interval=1000
server_opts
=
""
ts_offset
=
2000
while
getopts
"hc:i:o:rt:T
P:X:
"
opt
;
do
while
getopts
"hc:i:o:rt:T
X
"
opt
;
do
case
"
${
opt
}
"
in
h
)
usage
...
...
@@ -40,11 +39,8 @@ while getopts "hc:i:o:rt:TP:X:" opt; do
T
)
enable_tracing
=
1
;;
P
)
server_opts+
=
" -P
${
OPTARG
}
"
;;
X
)
server_opts+
=
" -X
${
OPTARG
}
"
server_opts+
=
" -X "
;;
*
)
usage
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment