From: Masatake YAMATO Date: Fri, 5 Aug 2022 21:49:27 +0000 (+0900) Subject: test: (lsfd) add a case for displaying PROTONAME column of mmap'ed AF_PACKET socket X-Git-Tag: v2.39-rc1~561^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bce240a74538a886291104184fa200635399ea63;p=thirdparty%2Futil-linux.git test: (lsfd) add a case for displaying PROTONAME column of mmap'ed AF_PACKET socket Tools like tcpdump do mmap sockets! This test case proves lsfd can extract information such a exotic source of mmap. Signed-off-by: Masatake YAMATO --- diff --git a/tests/expected/lsfd/mkfds-mapped-packet-socket b/tests/expected/lsfd/mkfds-mapped-packet-socket new file mode 100644 index 0000000000..43c99015ce --- /dev/null +++ b/tests/expected/lsfd/mkfds-mapped-packet-socket @@ -0,0 +1,2 @@ + PACKET +PROTONAME: 0 diff --git a/tests/helpers/test_mkfds.c b/tests/helpers/test_mkfds.c index f2f569a406..e0a7ea8677 100644 --- a/tests/helpers/test_mkfds.c +++ b/tests/helpers/test_mkfds.c @@ -17,19 +17,26 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include #include #include #include #include #include +#include +#include +#include #include #include #include #include +#include +#include #include #include #include #include +#include #include #include "c.h" @@ -535,6 +542,130 @@ static void open_ro_blkdev(const struct factory *factory, struct fdesc fdescs[], }; } +static int make_packet_socket(int socktype, const char *interface) +{ + int sd; + struct sockaddr_ll addr; + + sd = socket(AF_PACKET, socktype, htons(ETH_P_ALL)); + if (sd < 0) + err(EXIT_FAILURE, "failed to make a socket with AF_PACKET"); + + if (interface == NULL) + return sd; /* Just making a socket */ + + memset(&addr, 0, sizeof(struct sockaddr_ll)); + addr.sll_family = AF_PACKET; + addr.sll_protocol = ETH_P_ALL; + addr.sll_ifindex = if_nametoindex(interface); + if (addr.sll_ifindex == 0) { + int e = errno; + close(sd); + errno = e; + err(EXIT_FAILURE, + "failed to get the interface index for %s", interface); + } + if (bind(sd, (struct sockaddr *)&addr, sizeof(struct sockaddr_ll)) < 0) { + int e = errno; + close(sd); + errno = e; + err(EXIT_FAILURE, + "failed to get the interface index for %s", interface); + } + + return sd; +} + +struct munmap_data { + void *ptr; + size_t len; +}; + +static void close_fdesc_after_munmap(int fd, void *data) +{ + struct munmap_data *munmap_data = data; + munmap(munmap_data->ptr, munmap_data->len); + free(data); + close(fd); +} + +static void make_mmapped_packet_socket(const struct factory *factory, struct fdesc fdescs[], pid_t * child _U_, + int argc, char ** argv) +{ + int sd; + struct arg socktype = decode_arg("socktype", factory->params, argc, argv); + struct arg interface = decode_arg("interface", factory->params, argc, argv); + + int isocktype; + const char *sinterface; + struct tpacket_req req; + struct munmap_data *munmap_data; + + if (strcmp(ARG_STRING(socktype), "DGRAM") == 0) + isocktype = SOCK_DGRAM; + else if (strcmp(ARG_STRING(socktype), "RAW") == 0) + isocktype = SOCK_RAW; + else + errx(EXIT_FAILURE, + "unknown socket type for socket(AF_PACKET,...): %s", + ARG_STRING(socktype)); + free_arg(&socktype); + + sinterface = ARG_STRING(interface); + sd = make_packet_socket(isocktype, sinterface); + free_arg(&interface); + + /* Specify the spec of ring buffers. + * + * ref. + * - linux/Documentation/networking/packet_mmap.rst + * - https://sites.google.com/site/packetmmap/home + */ + req.tp_block_size = PAGE_SIZE; + req.tp_frame_size = PAGE_SIZE; + req.tp_block_nr = 1; + req.tp_frame_nr = 1; + if (setsockopt(sd, SOL_PACKET, PACKET_TX_RING, (char *)&req, sizeof(req)) < 0) { + int e = errno; + close(sd); + errno = e; + err(EXIT_FAILURE, "failed to specify a buffer spec to a packet socket"); + } + + munmap_data = malloc(sizeof (*munmap_data)); + if (munmap_data == NULL) { + close(sd); + errx(EXIT_FAILURE, "memory exhausted"); + } + munmap_data->len = req.tp_block_size * req.tp_block_nr; + munmap_data->ptr = mmap(NULL, munmap_data->len, PROT_WRITE, MAP_SHARED, sd, 0); + if (munmap_data->ptr == MAP_FAILED) { + int e = errno; + close(sd); + free(munmap_data); + errno = e; + err(EXIT_FAILURE, "failed to do mmap a packet socket"); + } + + if (sd != fdescs[0].fd) { + if (dup2(sd, fdescs[0].fd) < 0) { + int e = errno; + close(sd); + munmap(munmap_data->ptr, munmap_data->len); + free(munmap_data); + errno = e; + err(EXIT_FAILURE, "failed to dup %d -> %d", sd, fdescs[0].fd); + } + close(sd); + } + + fdescs[0] = (struct fdesc){ + .fd = fdescs[0].fd, + .close = close_fdesc_after_munmap, + .data = munmap_data, + }; +} + #define PARAM_END { .name = NULL, } static const struct factory factories[] = { { @@ -687,6 +818,30 @@ static const struct factory factories[] = { PARAM_END }, }, + { + .name = "mapped-packet-socket", + .desc = "mmap'ed AF_PACKET socket", + .priv = true, + .N = 1, + .EX_N = 0, + .fork = false, + .make = make_mmapped_packet_socket, + .params = (struct parameter []) { + { + .name = "socktype", + .type = PTYPE_STRING, + .desc = "DGRAM or RAW", + .defv.string = "RAW", + }, + { + .name = "interface", + .type = PTYPE_STRING, + .desc = "a name of network interface like eth0 or lo", + .defv.string = "lo", + }, + PARAM_END + }, + }, }; static int count_parameters(const struct factory *factory) diff --git a/tests/ts/lsfd/mkfds-mapped-packet-socket b/tests/ts/lsfd/mkfds-mapped-packet-socket new file mode 100755 index 0000000000..e7818e9286 --- /dev/null +++ b/tests/ts/lsfd/mkfds-mapped-packet-socket @@ -0,0 +1,49 @@ +#!/bin/bash +# +# Copyright (C) 2022 Masatake YAMATO +# +# This file is part of util-linux. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +TS_TOPDIR="${0%/*}/../.." +TS_DESC="mmap'ed AF_PACKET socket" + +. $TS_TOPDIR/functions.sh +ts_init "$*" +ts_skip_nonroot + +. $TS_SELF/lsfd-functions.bash + +ts_check_test_command "$TS_CMD_LSFD" + +ts_check_test_command "$TS_HELPER_MKFDS" + +ts_cd "$TS_OUTDIR" + +PID= +FD=3 +EXPR= +INTERFACE=lo + +{ + coproc MKFDS { "$TS_HELPER_MKFDS" mapped-packet-socket $FD interface=${INTERFACE}; } + if read -u ${MKFDS[0]} PID; then + EXPR='(ASSOC == "shm") and (TYPE == "SOCK") and (MODE == "-w-")' + ${TS_CMD_LSFD} -p "$PID" -n -o PROTONAME -Q "${EXPR}" + echo 'PROTONAME': $? + fi + + kill -CONT ${PID} + wait ${MKFDS_PID} +} > $TS_OUTPUT 2>&1 + +ts_finalize