/* The meaning of SUPPORTED is "will redirect packet as expected".
*/ #define SUPPORTED _BITUL(0)
/* Note on sk_skb-to-ingress ->af_vsock: * * Peer socket may receive the packet some time after the return from sendmsg(). * In a typical usage scenario, recvmsg() will block until the redirected packet * appears in the destination queue, or timeout if the packet was dropped. By * that point, the verdict map has already been updated to reflect what has * happened. * * But sk_skb-to-ingress/af_vsock is an unsupported combination, so no recvmsg() * takes place. Which means we may race the execution of the verdict logic and * read map_verd before it has been updated, i.e. we might observe * map_verd[SK_DROP]=0 instead of map_verd[SK_DROP]=1. * * This confuses the selftest logic: if there was no packet dropped, where's the * packet? So here's a heuristic: on map_verd[SK_DROP]=map_verd[SK_PASS]=0 * (which implies the verdict program has not been ran) just re-read the verdict * map again.
*/ #define UNSUPPORTED_RACY_VERD _BITUL(1)
staticvoid handle_unsupported(int sd_send, int sd_peer, int sd_in, int sd_out, int sd_recv, int map_verd, int status)
{ unsignedint drop, pass; char recv_buf;
ssize_t n;
get_verdict: if (xbpf_map_lookup_elem(map_verd, &u32(SK_DROP), &drop) ||
xbpf_map_lookup_elem(map_verd, &u32(SK_PASS), &pass)) return;
if (pass == 0 && drop == 0 && (status & UNSUPPORTED_RACY_VERD)) {
sched_yield(); goto get_verdict;
}
if (pass != 0) {
FAIL("unsupported: wanted verdict pass 0, have %u", pass); return;
}
/* If nothing was dropped, packet should have reached the peer */ if (drop == 0) {
errno = 0;
n = recv_timeout(sd_peer, &recv_buf, 1, 0, IO_TIMEOUT_SEC); if (n != 1)
FAIL_ERRNO("unsupported: packet missing, retval=%zd", n);
}
/* Ensure queues are empty */
try_recv("bpf.recv(sd_send)", sd_send, MSG_DONTWAIT, false); if (sd_in != sd_send)
try_recv("bpf.recv(sd_in)", sd_in, MSG_DONTWAIT, false);
staticvoid test_send_redir_recv(int sd_send, int send_flags, int sd_peer, int sd_in, int sd_out, int sd_recv, struct maps *maps, int status)
{ unsignedint drop, pass; char *send_buf = "ab"; char recv_buf = '\0';
ssize_t n, len = 1;
/* Zero out the verdict map */ if (xbpf_map_update_elem(maps->verd, &u32(SK_DROP), &u32(0), BPF_ANY) ||
xbpf_map_update_elem(maps->verd, &u32(SK_PASS), &u32(0), BPF_ANY)) return;
if (xbpf_map_update_elem(maps->in, &u32(0), &u64(sd_in), BPF_NOEXIST)) return;
if (xbpf_map_update_elem(maps->out, &u32(0), &u64(sd_out), BPF_NOEXIST)) goto del_in;
/* Last byte is OOB data when send_flags has MSG_OOB bit set */ if (send_flags & MSG_OOB)
len++;
n = send(sd_send, send_buf, len, send_flags); if (n >= 0 && n < len)
FAIL("incomplete send"); if (n < 0) { /* sk_msg redirect combo not supported? */ if (status & SUPPORTED || errno != EACCES)
FAIL_ERRNO("send"); goto out;
}
errno = 0;
n = recv_timeout(sd_recv, &recv_buf, 1, 0, IO_TIMEOUT_SEC); if (n != 1) {
FAIL_ERRNO("recv_timeout()"); goto out;
}
/* Check verdict _after_ recv(); af_vsock may need time to catch up */ if (xbpf_map_lookup_elem(maps->verd, &u32(SK_DROP), &drop) ||
xbpf_map_lookup_elem(maps->verd, &u32(SK_PASS), &pass)) goto out;
if (drop != 0 || pass != 1)
FAIL("unexpected verdict drop/pass: wanted 0/1, have %u/%u",
drop, pass);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.