Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package passt for openSUSE:Factory checked in at 2024-08-13 13:22:03 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/passt (Old) and /work/SRC/openSUSE:Factory/.passt.new.7232 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "passt" Tue Aug 13 13:22:03 2024 rev:12 rq:1193334 version:20240806.ee36266 Changes: -------- --- /work/SRC/openSUSE:Factory/passt/passt.changes 2024-08-07 06:10:31.394618438 +0200 +++ /work/SRC/openSUSE:Factory/.passt.new.7232/passt.changes 2024-08-13 13:22:08.707499255 +0200 @@ -1,0 +2,15 @@ +Tue Aug 06 16:58:22 UTC 2024 - dcer...@suse.com + +- Update to version 20240806.ee36266: + * log, passt: Keep printing to stderr when passt is running in foreground + * tcp_splice: Fix side in OUT_WAIT flag setting + * util: Use unsigned (size_t) value for iov length + * udp_flow: move all udp_flow functions to udp_flow.c + * udp_flow: Remove udp_meta_t from the parameters of udp_flow_from_sock() + * log: Make logfile_write() private + * pasta: Save errno on signal handler entry, restore on return when needed + * pasta: modify hostname when detaching new namespace + * Fix typo in README file + * fedora/rpkg: List myself as author for changelog entries + +------------------------------------------------------------------- Old: ---- passt-20240726.57a21d2.tar.zst New: ---- passt-20240806.ee36266.tar.zst ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ passt.spec ++++++ --- /var/tmp/diff_new_pack.0Cexw6/_old 2024-08-13 13:22:09.559534756 +0200 +++ /var/tmp/diff_new_pack.0Cexw6/_new 2024-08-13 13:22:09.563534923 +0200 @@ -44,7 +44,7 @@ %endif Name: passt -Version: 20240726.57a21d2 +Version: 20240806.ee36266 Release: 0 Summary: User-mode networking daemons for virtual machines and namespaces License: GPL-2.0-or-later AND BSD-3-Clause ++++++ _service ++++++ --- /var/tmp/diff_new_pack.0Cexw6/_old 2024-08-13 13:22:09.595536256 +0200 +++ /var/tmp/diff_new_pack.0Cexw6/_new 2024-08-13 13:22:09.599536423 +0200 @@ -4,7 +4,7 @@ <param name="scm">git</param> <param name="changesgenerate">enable</param> <param name="versionformat">%cs.%h</param> - <param name="revision">2024_07_26.57a21d2</param> + <param name="revision">2024_08_06.ee36266</param> </service> <service mode="manual" name="recompress"> <param name="file">*.tar</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.0Cexw6/_old 2024-08-13 13:22:09.623537423 +0200 +++ /var/tmp/diff_new_pack.0Cexw6/_new 2024-08-13 13:22:09.627537589 +0200 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://passt.top/passt</param> - <param name="changesrevision">57a21d2df1467302dee71ee9d5683a8b96e6ce7f</param></service></servicedata> + <param name="changesrevision">ee36266a55478672ad2c5f4efbd6ca0bef3d37cd</param></service></servicedata> (No newline at EOF) ++++++ passt-20240726.57a21d2.tar.zst -> passt-20240806.ee36266.tar.zst ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/passt-20240726.57a21d2/Makefile new/passt-20240806.ee36266/Makefile --- old/passt-20240726.57a21d2/Makefile 2024-07-26 14:07:42.000000000 +0200 +++ new/passt-20240806.ee36266/Makefile 2024-08-06 15:03:48.000000000 +0200 @@ -47,7 +47,7 @@ PASST_SRCS = arch.c arp.c checksum.c conf.c dhcp.c dhcpv6.c flow.c fwd.c \ icmp.c igmp.c inany.c iov.c ip.c isolation.c lineread.c log.c mld.c \ ndp.c netlink.c packet.c passt.c pasta.c pcap.c pif.c tap.c tcp.c \ - tcp_buf.c tcp_splice.c udp.c util.c + tcp_buf.c tcp_splice.c udp.c udp_flow.c util.c QRAP_SRCS = qrap.c SRCS = $(PASST_SRCS) $(QRAP_SRCS) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/passt-20240726.57a21d2/README.md new/passt-20240806.ee36266/README.md --- old/passt-20240726.57a21d2/README.md 2024-07-26 14:07:42.000000000 +0200 +++ new/passt-20240806.ee36266/README.md 2024-08-06 15:03:48.000000000 +0200 @@ -398,7 +398,7 @@ and nameserver using SLAAC * [DHCPv6 server](/passt/tree/dhcpv6.c): a simple implementation handing out one single IPv6 address to the guest or namespace, - namely, the the same address as the first one configured for the upstream host + namely, the same address as the first one configured for the upstream host interface, and passing the nameservers configured on the host ## Addresses diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/passt-20240726.57a21d2/contrib/fedora/rpkg.macros new/passt-20240806.ee36266/contrib/fedora/rpkg.macros --- old/passt-20240726.57a21d2/contrib/fedora/rpkg.macros 2024-07-26 14:07:42.000000000 +0200 +++ new/passt-20240806.ee36266/contrib/fedora/rpkg.macros 2024-08-06 15:03:48.000000000 +0200 @@ -29,7 +29,11 @@ [ -z "${__from}" ] && __from="$(git rev-list --max-parents=0 HEAD)" __date="$(git log --pretty="format:%cI" "${__to}" -1)" - __author="$(git log -1 --pretty="format:%an <%ae>" ${__to} -- contrib/fedora)" + __author="Stefano Brivio <sbri...@redhat.com>" + # Use: + # __author="$(git log -1 --pretty="format:%an <%ae>" ${__to} -- contrib/fedora)" + # if you want the author of changelog entries to match the latest + # author for contrib/fedora printf "* %s %s - %s\n" "$(date "+%a %b %e %Y" -d "${__date}")" "${__author}" "$(git_version "${__to}")-1" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/passt-20240726.57a21d2/log.c new/passt-20240806.ee36266/log.c --- old/passt-20240726.57a21d2/log.c 2024-07-26 14:07:42.000000000 +0200 +++ new/passt-20240806.ee36266/log.c 2024-08-06 15:03:48.000000000 +0200 @@ -44,7 +44,7 @@ int log_trace; /* --trace mode enabled */ bool log_conf_parsed; /* Logging options already parsed */ -bool log_runtime; /* Daemonised, or ready in foreground */ +bool log_stderr = true; /* Not daemonised, no shell spawned */ /** * logtime_fmt_and_arg() - Build format and arguments to print relative log time @@ -55,6 +55,177 @@ (timespec_diff_us((x), &log_start) / 1000000LL), \ (timespec_diff_us((x), &log_start) / 100LL) +/* Prefixes for log file messages, indexed by priority */ +const char *logfile_prefix[] = { + NULL, NULL, NULL, /* Unused: LOG_EMERG, LOG_ALERT, LOG_CRIT */ + "ERROR: ", + "WARNING: ", + NULL, /* Unused: LOG_NOTICE */ + "info: ", + " ", /* LOG_DEBUG */ +}; + +#ifdef FALLOC_FL_COLLAPSE_RANGE +/** + * logfile_rotate_fallocate() - Write header, set log_written after fallocate() + * @fd: Log file descriptor + * @now: Current timestamp + * + * #syscalls lseek ppc64le:_llseek ppc64:_llseek arm:_llseek + */ +static void logfile_rotate_fallocate(int fd, const struct timespec *now) +{ + char buf[BUFSIZ]; + const char *nl; + int n; + + if (lseek(fd, 0, SEEK_SET) == -1) + return; + if (read(fd, buf, BUFSIZ) == -1) + return; + + n = snprintf(buf, BUFSIZ, "%s - log truncated at ", log_header); + n += snprintf(buf + n, BUFSIZ - n, logtime_fmt_and_arg(now)); + + /* Avoid partial lines by padding the header with spaces */ + nl = memchr(buf + n + 1, '\n', BUFSIZ - n - 1); + if (nl) + memset(buf + n, ' ', nl - (buf + n)); + + if (lseek(fd, 0, SEEK_SET) == -1) + return; + if (write(fd, buf, BUFSIZ) == -1) + return; + + log_written -= log_cut_size; +} +#endif /* FALLOC_FL_COLLAPSE_RANGE */ + +/** + * logfile_rotate_move() - Fallback: move recent entries toward start, then cut + * @fd: Log file descriptor + * @now: Current timestamp + * + * #syscalls lseek ppc64le:_llseek ppc64:_llseek arm:_llseek + * #syscalls ftruncate + */ +static void logfile_rotate_move(int fd, const struct timespec *now) +{ + int header_len, write_offset, end, discard, n; + char buf[BUFSIZ]; + const char *nl; + + header_len = snprintf(buf, BUFSIZ, "%s - log truncated at ", + log_header); + header_len += snprintf(buf + header_len, BUFSIZ - header_len, + logtime_fmt_and_arg(now)); + + if (lseek(fd, 0, SEEK_SET) == -1) + return; + if (write(fd, buf, header_len) == -1) + return; + + end = write_offset = header_len; + discard = log_cut_size + header_len; + + /* Try to cut cleanly at newline */ + if (lseek(fd, discard, SEEK_SET) == -1) + goto out; + if ((n = read(fd, buf, BUFSIZ)) <= 0) + goto out; + if ((nl = memchr(buf, '\n', n))) + discard += (nl - buf) + 1; + + /* Go to first block to be moved */ + if (lseek(fd, discard, SEEK_SET) == -1) + goto out; + + while ((n = read(fd, buf, BUFSIZ)) > 0) { + end = header_len; + + if (lseek(fd, write_offset, SEEK_SET) == -1) + goto out; + if ((n = write(fd, buf, n)) == -1) + goto out; + write_offset += n; + + if ((n = lseek(fd, 0, SEEK_CUR)) == -1) + goto out; + + if (lseek(fd, discard - header_len, SEEK_CUR) == -1) + goto out; + + end = n; + } + +out: + if (ftruncate(fd, end)) + return; + + log_written = end; +} + +/** + * logfile_rotate() - "Rotate" log file once it's full + * @fd: Log file descriptor + * @now: Current timestamp + * + * Return: 0 on success, negative error code on failure + * + * #syscalls fcntl + * + * fallocate() passed as EXTRA_SYSCALL only if FALLOC_FL_COLLAPSE_RANGE is there + */ +static int logfile_rotate(int fd, const struct timespec *now) +{ + if (fcntl(fd, F_SETFL, O_RDWR /* Drop O_APPEND: explicit lseek() */)) + return -errno; + +#ifdef FALLOC_FL_COLLAPSE_RANGE + /* Only for Linux >= 3.15, extent-based ext4 or XFS, glibc >= 2.18 */ + if (!fallocate(fd, FALLOC_FL_COLLAPSE_RANGE, 0, log_cut_size)) + logfile_rotate_fallocate(fd, now); + else +#endif + logfile_rotate_move(fd, now); + + if (fcntl(fd, F_SETFL, O_RDWR | O_APPEND)) + return -errno; + + return 0; +} + +/** + * logfile_write() - Write entry to log file, trigger rotation if full + * @newline: Append newline at the end of the message, if missing + * @pri: Facility and level map, same as priority for vsyslog() + * @format: Same as vsyslog() format + * @ap: Same as vsyslog() ap + */ +static void logfile_write(bool newline, int pri, const char *format, va_list ap) +{ + struct timespec now; + char buf[BUFSIZ]; + int n; + + if (clock_gettime(CLOCK_MONOTONIC, &now)) + return; + + n = snprintf(buf, BUFSIZ, logtime_fmt_and_arg(&now)); + n += snprintf(buf + n, BUFSIZ - n, ": %s", logfile_prefix[pri]); + + n += vsnprintf(buf + n, BUFSIZ - n, format, ap); + + if (newline && format[strlen(format)] != '\n') + n += snprintf(buf + n, BUFSIZ - n, "\n"); + + if ((log_written + n >= log_size) && logfile_rotate(log_file, &now)) + return; + + if ((n = write(log_file, buf, n)) >= 0) + log_written += n; +} + /** * vlogmsg() - Print or send messages to log or output files as configured * @newline: Append newline at the end of the message, if missing @@ -86,7 +257,7 @@ } if (debug_print || !log_conf_parsed || - (!log_runtime && (log_mask & LOG_MASK(LOG_PRI(pri))))) { + (log_stderr && (log_mask & LOG_MASK(LOG_PRI(pri))))) { (void)vfprintf(stderr, format, ap); if (newline && format[strlen(format)] != '\n') fprintf(stderr, "\n"); @@ -125,16 +296,6 @@ logmsg(true, pri, ": %s", strerror(errno_copy)); } -/* Prefixes for log file messages, indexed by priority */ -const char *logfile_prefix[] = { - NULL, NULL, NULL, /* Unused: LOG_EMERG, LOG_ALERT, LOG_CRIT */ - "ERROR: ", - "WARNING: ", - NULL, /* Unused: LOG_NOTICE */ - "info: ", - " ", /* LOG_DEBUG */ -}; - /** * trace_init() - Set log_trace depending on trace (debug) mode * @enable: Tracing debug mode enabled if non-zero @@ -203,7 +364,7 @@ if (newline && format[strlen(format)] != '\n') n += snprintf(buf + n, BUFSIZ - n, "\n"); - if (log_sock >= 0 && send(log_sock, buf, n, 0) != n && !log_runtime) + if (log_sock >= 0 && send(log_sock, buf, n, 0) != n && log_stderr) fprintf(stderr, "Failed to send %i bytes to syslog\n", n); } @@ -239,163 +400,3 @@ log_cut_size = ROUND_UP(log_size * LOGFILE_CUT_RATIO / 100, PAGE_SIZE); } -#ifdef FALLOC_FL_COLLAPSE_RANGE -/** - * logfile_rotate_fallocate() - Write header, set log_written after fallocate() - * @fd: Log file descriptor - * @now: Current timestamp - * - * #syscalls lseek ppc64le:_llseek ppc64:_llseek arm:_llseek - */ -static void logfile_rotate_fallocate(int fd, const struct timespec *now) -{ - char buf[BUFSIZ]; - const char *nl; - int n; - - if (lseek(fd, 0, SEEK_SET) == -1) - return; - if (read(fd, buf, BUFSIZ) == -1) - return; - - n = snprintf(buf, BUFSIZ, "%s - log truncated at ", log_header); - n += snprintf(buf + n, BUFSIZ - n, logtime_fmt_and_arg(now)); - - /* Avoid partial lines by padding the header with spaces */ - nl = memchr(buf + n + 1, '\n', BUFSIZ - n - 1); - if (nl) - memset(buf + n, ' ', nl - (buf + n)); - - if (lseek(fd, 0, SEEK_SET) == -1) - return; - if (write(fd, buf, BUFSIZ) == -1) - return; - - log_written -= log_cut_size; -} -#endif /* FALLOC_FL_COLLAPSE_RANGE */ - -/** - * logfile_rotate_move() - Fallback: move recent entries toward start, then cut - * @fd: Log file descriptor - * @now: Current timestamp - * - * #syscalls lseek ppc64le:_llseek ppc64:_llseek arm:_llseek - * #syscalls ftruncate - */ -static void logfile_rotate_move(int fd, const struct timespec *now) -{ - int header_len, write_offset, end, discard, n; - char buf[BUFSIZ]; - const char *nl; - - header_len = snprintf(buf, BUFSIZ, "%s - log truncated at ", - log_header); - header_len += snprintf(buf + header_len, BUFSIZ - header_len, - logtime_fmt_and_arg(now)); - - if (lseek(fd, 0, SEEK_SET) == -1) - return; - if (write(fd, buf, header_len) == -1) - return; - - end = write_offset = header_len; - discard = log_cut_size + header_len; - - /* Try to cut cleanly at newline */ - if (lseek(fd, discard, SEEK_SET) == -1) - goto out; - if ((n = read(fd, buf, BUFSIZ)) <= 0) - goto out; - if ((nl = memchr(buf, '\n', n))) - discard += (nl - buf) + 1; - - /* Go to first block to be moved */ - if (lseek(fd, discard, SEEK_SET) == -1) - goto out; - - while ((n = read(fd, buf, BUFSIZ)) > 0) { - end = header_len; - - if (lseek(fd, write_offset, SEEK_SET) == -1) - goto out; - if ((n = write(fd, buf, n)) == -1) - goto out; - write_offset += n; - - if ((n = lseek(fd, 0, SEEK_CUR)) == -1) - goto out; - - if (lseek(fd, discard - header_len, SEEK_CUR) == -1) - goto out; - - end = n; - } - -out: - if (ftruncate(fd, end)) - return; - - log_written = end; -} - -/** - * logfile_rotate() - "Rotate" log file once it's full - * @fd: Log file descriptor - * @now: Current timestamp - * - * Return: 0 on success, negative error code on failure - * - * #syscalls fcntl - * - * fallocate() passed as EXTRA_SYSCALL only if FALLOC_FL_COLLAPSE_RANGE is there - */ -static int logfile_rotate(int fd, const struct timespec *now) -{ - if (fcntl(fd, F_SETFL, O_RDWR /* Drop O_APPEND: explicit lseek() */)) - return -errno; - -#ifdef FALLOC_FL_COLLAPSE_RANGE - /* Only for Linux >= 3.15, extent-based ext4 or XFS, glibc >= 2.18 */ - if (!fallocate(fd, FALLOC_FL_COLLAPSE_RANGE, 0, log_cut_size)) - logfile_rotate_fallocate(fd, now); - else -#endif - logfile_rotate_move(fd, now); - - if (fcntl(fd, F_SETFL, O_RDWR | O_APPEND)) - return -errno; - - return 0; -} - -/** - * logfile_write() - Write entry to log file, trigger rotation if full - * @newline: Append newline at the end of the message, if missing - * @pri: Facility and level map, same as priority for vsyslog() - * @format: Same as vsyslog() format - * @ap: Same as vsyslog() ap - */ -void logfile_write(bool newline, int pri, const char *format, va_list ap) -{ - struct timespec now; - char buf[BUFSIZ]; - int n; - - if (clock_gettime(CLOCK_MONOTONIC, &now)) - return; - - n = snprintf(buf, BUFSIZ, logtime_fmt_and_arg(&now)); - n += snprintf(buf + n, BUFSIZ - n, ": %s", logfile_prefix[pri]); - - n += vsnprintf(buf + n, BUFSIZ - n, format, ap); - - if (newline && format[strlen(format)] != '\n') - n += snprintf(buf + n, BUFSIZ - n, "\n"); - - if ((log_written + n >= log_size) && logfile_rotate(log_file, &now)) - return; - - if ((n = write(log_file, buf, n)) >= 0) - log_written += n; -} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/passt-20240726.57a21d2/log.h new/passt-20240806.ee36266/log.h --- old/passt-20240726.57a21d2/log.h 2024-07-26 14:07:42.000000000 +0200 +++ new/passt-20240806.ee36266/log.h 2024-08-06 15:03:48.000000000 +0200 @@ -43,7 +43,7 @@ extern int log_trace; extern bool log_conf_parsed; -extern bool log_runtime; +extern bool log_stderr; extern struct timespec log_start; void trace_init(int enable); @@ -56,7 +56,6 @@ void __openlog(const char *ident, int option, int facility); void logfile_init(const char *name, const char *path, size_t size); void passt_vsyslog(bool newline, int pri, const char *format, va_list ap); -void logfile_write(bool newline, int pri, const char *format, va_list ap); void __setlogmask(int mask); #endif /* LOG_H */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/passt-20240726.57a21d2/passt.c new/passt-20240806.ee36266/passt.c --- old/passt-20240726.57a21d2/passt.c 2024-07-26 14:07:42.000000000 +0200 +++ new/passt-20240806.ee36266/passt.c 2024-08-06 15:03:48.000000000 +0200 @@ -290,15 +290,17 @@ if (isolate_prefork(&c)) die("Failed to sandbox process, exiting"); - if (!c.foreground) + if (!c.foreground) { __daemon(c.pidfile_fd, devnull_fd); - else + log_stderr = false; + } else { pidfile_write(c.pidfile_fd, getpid()); + } - log_runtime = true; - - if (pasta_child_pid) + if (pasta_child_pid) { kill(pasta_child_pid, SIGUSR1); + log_stderr = false; + } isolate_postfork(&c); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/passt-20240726.57a21d2/pasta.c new/passt-20240806.ee36266/pasta.c --- old/passt-20240726.57a21d2/pasta.c 2024-07-26 14:07:42.000000000 +0200 +++ new/passt-20240806.ee36266/pasta.c 2024-08-06 15:03:48.000000000 +0200 @@ -50,6 +50,8 @@ #include "netlink.h" #include "log.h" +#define HOSTNAME_PREFIX "pasta-" + /* PID of child, in case we created a namespace */ int pasta_child_pid; @@ -59,6 +61,7 @@ */ void pasta_child_handler(int signal) { + int errno_save = errno; siginfo_t infop; (void)signal; @@ -83,6 +86,8 @@ waitid(P_ALL, 0, NULL, WEXITED | WNOHANG); waitid(P_ALL, 0, NULL, WEXITED | WNOHANG); + + errno = errno_save; } /** @@ -177,6 +182,7 @@ /* cppcheck-suppress [constParameterCallback, unmatchedSuppression] */ static int pasta_spawn_cmd(void *arg) { + char hostname[HOST_NAME_MAX + 1] = HOSTNAME_PREFIX; const struct pasta_spawn_cmd_arg *a; sigset_t set; @@ -187,6 +193,14 @@ if (write_file("/proc/sys/net/ipv4/ping_group_range", "0 0")) warn("Cannot set ping_group_range, ICMP requests might fail"); + if (!gethostname(hostname + sizeof(HOSTNAME_PREFIX) - 1, + HOST_NAME_MAX + 1 - sizeof(HOSTNAME_PREFIX)) || + errno == ENAMETOOLONG) { + hostname[HOST_NAME_MAX] = '\0'; + if (sethostname(hostname, strlen(hostname))) + warn("Unable to set pasta-prefixed hostname"); + } + /* Wait for the parent to be ready: see main() */ sigemptyset(&set); sigaddset(&set, SIGUSR1); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/passt-20240726.57a21d2/tcp_splice.c new/passt-20240806.ee36266/tcp_splice.c --- old/passt-20240726.57a21d2/tcp_splice.c 2024-07-26 14:07:42.000000000 +0200 +++ new/passt-20240806.ee36266/tcp_splice.c 2024-08-06 15:03:48.000000000 +0200 @@ -577,7 +577,7 @@ if (conn->read[fromsidei] == conn->written[fromsidei]) break; - conn_event(c, conn, OUT_WAIT(fromsidei)); + conn_event(c, conn, OUT_WAIT(!fromsidei)); break; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/passt-20240726.57a21d2/udp.c new/passt-20240806.ee36266/udp.c --- old/passt-20240726.57a21d2/udp.c 2024-07-26 14:07:42.000000000 +0200 +++ new/passt-20240806.ee36266/udp.c 2024-08-06 15:03:48.000000000 +0200 @@ -95,7 +95,6 @@ #include <sys/socket.h> #include <sys/uio.h> #include <time.h> -#include <fcntl.h> #include <arpa/inet.h> #include <linux/errqueue.h> @@ -111,7 +110,6 @@ #include "log.h" #include "flow_table.h" -#define UDP_CONN_TIMEOUT 180 /* s, timeout for ephemeral or local bind */ #define UDP_MAX_FRAMES 32 /* max # of frames to receive at once */ /* "Spliced" sockets indexed by bound port (host order) */ @@ -277,199 +275,6 @@ } /** - * udp_at_sidx() - Get UDP specific flow at given sidx - * @sidx: Flow and side to retrieve - * - * Return: UDP specific flow at @sidx, or NULL of @sidx is invalid. Asserts if - * the flow at @sidx is not FLOW_UDP. - */ -struct udp_flow *udp_at_sidx(flow_sidx_t sidx) -{ - union flow *flow = flow_at_sidx(sidx); - - if (!flow) - return NULL; - - ASSERT(flow->f.type == FLOW_UDP); - return &flow->udp; -} - -/* - * udp_flow_close() - Close and clean up UDP flow - * @c: Execution context - * @uflow: UDP flow - */ -static void udp_flow_close(const struct ctx *c, struct udp_flow *uflow) -{ - if (uflow->s[INISIDE] >= 0) { - /* The listening socket needs to stay in epoll */ - close(uflow->s[INISIDE]); - uflow->s[INISIDE] = -1; - } - - if (uflow->s[TGTSIDE] >= 0) { - /* But the flow specific one needs to be removed */ - epoll_ctl(c->epollfd, EPOLL_CTL_DEL, uflow->s[TGTSIDE], NULL); - close(uflow->s[TGTSIDE]); - uflow->s[TGTSIDE] = -1; - } - flow_hash_remove(c, FLOW_SIDX(uflow, INISIDE)); - if (!pif_is_socket(uflow->f.pif[TGTSIDE])) - flow_hash_remove(c, FLOW_SIDX(uflow, TGTSIDE)); -} - -/** - * udp_flow_new() - Common setup for a new UDP flow - * @c: Execution context - * @flow: Initiated flow - * @s_ini: Initiating socket (or -1) - * @now: Timestamp - * - * Return: UDP specific flow, if successful, NULL on failure - */ -static flow_sidx_t udp_flow_new(const struct ctx *c, union flow *flow, - int s_ini, const struct timespec *now) -{ - const struct flowside *ini = &flow->f.side[INISIDE]; - struct udp_flow *uflow = NULL; - const struct flowside *tgt; - uint8_t tgtpif; - - if (!inany_is_unicast(&ini->eaddr) || ini->eport == 0) { - flow_trace(flow, "Invalid endpoint to initiate UDP flow"); - goto cancel; - } - - if (!(tgt = flow_target(c, flow, IPPROTO_UDP))) - goto cancel; - tgtpif = flow->f.pif[TGTSIDE]; - - uflow = FLOW_SET_TYPE(flow, FLOW_UDP, udp); - uflow->ts = now->tv_sec; - uflow->s[INISIDE] = uflow->s[TGTSIDE] = -1; - - if (s_ini >= 0) { - /* When using auto port-scanning the listening port could go - * away, so we need to duplicate the socket - */ - uflow->s[INISIDE] = fcntl(s_ini, F_DUPFD_CLOEXEC, 0); - if (uflow->s[INISIDE] < 0) { - flow_err(uflow, - "Couldn't duplicate listening socket: %s", - strerror(errno)); - goto cancel; - } - } - - if (pif_is_socket(tgtpif)) { - struct mmsghdr discard[UIO_MAXIOV] = { 0 }; - union { - flow_sidx_t sidx; - uint32_t data; - } fref = { - .sidx = FLOW_SIDX(flow, TGTSIDE), - }; - int rc; - - uflow->s[TGTSIDE] = flowside_sock_l4(c, EPOLL_TYPE_UDP_REPLY, - tgtpif, tgt, fref.data); - if (uflow->s[TGTSIDE] < 0) { - flow_dbg(uflow, - "Couldn't open socket for spliced flow: %s", - strerror(errno)); - goto cancel; - } - - if (flowside_connect(c, uflow->s[TGTSIDE], tgtpif, tgt) < 0) { - flow_dbg(uflow, - "Couldn't connect flow socket: %s", - strerror(errno)); - goto cancel; - } - - /* It's possible, if unlikely, that we could receive some - * unrelated packets in between the bind() and connect() of this - * socket. For now we just discard these. We could consider - * trying to redirect these to an appropriate handler, if we - * need to. - */ - rc = recvmmsg(uflow->s[TGTSIDE], discard, ARRAY_SIZE(discard), - MSG_DONTWAIT, NULL); - if (rc >= ARRAY_SIZE(discard)) { - flow_dbg(uflow, - "Too many (%d) spurious reply datagrams", rc); - goto cancel; - } else if (rc > 0) { - flow_trace(uflow, - "Discarded %d spurious reply datagrams", rc); - } else if (errno != EAGAIN) { - flow_err(uflow, - "Unexpected error discarding datagrams: %s", - strerror(errno)); - } - } - - flow_hash_insert(c, FLOW_SIDX(uflow, INISIDE)); - - /* If the target side is a socket, it will be a reply socket that knows - * its own flowside. But if it's tap, then we need to look it up by - * hash. - */ - if (!pif_is_socket(tgtpif)) - flow_hash_insert(c, FLOW_SIDX(uflow, TGTSIDE)); - FLOW_ACTIVATE(uflow); - - return FLOW_SIDX(uflow, TGTSIDE); - -cancel: - if (uflow) - udp_flow_close(c, uflow); - flow_alloc_cancel(flow); - return FLOW_SIDX_NONE; -} - -/** - * udp_flow_from_sock() - Find or create UDP flow for "listening" socket - * @c: Execution context - * @ref: epoll reference of the receiving socket - * @meta: Metadata buffer for the datagram - * @now: Timestamp - * - * #syscalls fcntl - * - * Return: sidx for the destination side of the flow for this packet, or - * FLOW_SIDX_NONE if we couldn't find or create a flow. - */ -static flow_sidx_t udp_flow_from_sock(const struct ctx *c, union epoll_ref ref, - struct udp_meta_t *meta, - const struct timespec *now) -{ - struct udp_flow *uflow; - union flow *flow; - flow_sidx_t sidx; - - ASSERT(ref.type == EPOLL_TYPE_UDP_LISTEN); - - sidx = flow_lookup_sa(c, IPPROTO_UDP, ref.udp.pif, &meta->s_in, ref.udp.port); - if ((uflow = udp_at_sidx(sidx))) { - uflow->ts = now->tv_sec; - return flow_sidx_opposite(sidx); - } - - if (!(flow = flow_alloc())) { - char sastr[SOCKADDR_STRLEN]; - - debug("Couldn't allocate flow for UDP datagram from %s %s", - pif_name(ref.udp.pif), - sockaddr_ntop(&meta->s_in, sastr, sizeof(sastr))); - return FLOW_SIDX_NONE; - } - - flow_initiate_sa(flow, ref.udp.pif, &meta->s_in, ref.udp.port); - return udp_flow_new(c, flow, ref.fd, now); -} - -/** * udp_splice_prepare() - Prepare one datagram for splicing * @mmh: Receiving mmsghdr array * @idx: Index of the datagram to prepare @@ -712,7 +517,7 @@ * the array, or recalculating tosidx for a single entry, we have to * populate it one entry *ahead* of the loop counter. */ - udp_meta[0].tosidx = udp_flow_from_sock(c, ref, &udp_meta[0], now); + udp_meta[0].tosidx = udp_flow_from_sock(c, ref, &udp_meta[0].s_in, now); for (i = 0; i < n; ) { flow_sidx_t batchsidx = udp_meta[i].tosidx; uint8_t batchpif = pif_at_sidx(batchsidx); @@ -730,7 +535,7 @@ break; udp_meta[i].tosidx = udp_flow_from_sock(c, ref, - &udp_meta[i], + &udp_meta[i].s_in, now); } while (flow_sidx_eq(udp_meta[i].tosidx, batchsidx)); @@ -805,53 +610,6 @@ } /** - * udp_flow_from_tap() - Find or create UDP flow for tap packets - * @c: Execution context - * @pif: pif on which the packet is arriving - * @af: Address family, AF_INET or AF_INET6 - * @saddr: Source address on guest side - * @daddr: Destination address guest side - * @srcport: Source port on guest side - * @dstport: Destination port on guest side - * - * Return: sidx for the destination side of the flow for this packet, or - * FLOW_SIDX_NONE if we couldn't find or create a flow. - */ -static flow_sidx_t udp_flow_from_tap(const struct ctx *c, - uint8_t pif, sa_family_t af, - const void *saddr, const void *daddr, - in_port_t srcport, in_port_t dstport, - const struct timespec *now) -{ - struct udp_flow *uflow; - union flow *flow; - flow_sidx_t sidx; - - ASSERT(pif == PIF_TAP); - - sidx = flow_lookup_af(c, IPPROTO_UDP, pif, af, saddr, daddr, - srcport, dstport); - if ((uflow = udp_at_sidx(sidx))) { - uflow->ts = now->tv_sec; - return flow_sidx_opposite(sidx); - } - - if (!(flow = flow_alloc())) { - char sstr[INET6_ADDRSTRLEN], dstr[INET6_ADDRSTRLEN]; - - debug("Couldn't allocate flow for UDP datagram from %s %s:%hu -> %s:%hu", - pif_name(pif), - inet_ntop(af, saddr, sstr, sizeof(sstr)), srcport, - inet_ntop(af, daddr, dstr, sizeof(dstr)), dstport); - return FLOW_SIDX_NONE; - } - - flow_initiate_af(flow, PIF_TAP, af, saddr, srcport, daddr, dstport); - - return udp_flow_new(c, flow, -1, now); -} - -/** * udp_tap_handler() - Handle packets from tap * @c: Execution context * @pif: pif on which the packet is arriving @@ -1099,24 +857,6 @@ } /** - * udp_flow_timer() - Handler for timed events related to a given flow - * @c: Execution context - * @uflow: UDP flow - * @now: Current timestamp - * - * Return: true if the flow is ready to free, false otherwise - */ -bool udp_flow_timer(const struct ctx *c, struct udp_flow *uflow, - const struct timespec *now) -{ - if (now->tv_sec - uflow->ts <= UDP_CONN_TIMEOUT) - return false; - - udp_flow_close(c, uflow); - return true; -} - -/** * udp_timer() - Scan activity bitmaps for ports with associated timed events * @c: Execution context * @now: Current timestamp diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/passt-20240726.57a21d2/udp_flow.c new/passt-20240806.ee36266/udp_flow.c --- old/passt-20240726.57a21d2/udp_flow.c 1970-01-01 01:00:00.000000000 +0100 +++ new/passt-20240806.ee36266/udp_flow.c 2024-08-06 15:03:48.000000000 +0200 @@ -0,0 +1,274 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright Red Hat + * Author: David Gibson <da...@gibson.dropbear.id.au> + * + * UDP flow tracking functions + */ + +#include <errno.h> +#include <fcntl.h> +#include <sys/uio.h> + +#include "util.h" +#include "passt.h" +#include "flow_table.h" + +#define UDP_CONN_TIMEOUT 180 /* s, timeout for ephemeral or local bind */ + +/** + * udp_at_sidx() - Get UDP specific flow at given sidx + * @sidx: Flow and side to retrieve + * + * Return: UDP specific flow at @sidx, or NULL of @sidx is invalid. Asserts if + * the flow at @sidx is not FLOW_UDP. + */ +struct udp_flow *udp_at_sidx(flow_sidx_t sidx) +{ + union flow *flow = flow_at_sidx(sidx); + + if (!flow) + return NULL; + + ASSERT(flow->f.type == FLOW_UDP); + return &flow->udp; +} + +/* + * udp_flow_close() - Close and clean up UDP flow + * @c: Execution context + * @uflow: UDP flow + */ +static void udp_flow_close(const struct ctx *c, struct udp_flow *uflow) +{ + if (uflow->s[INISIDE] >= 0) { + /* The listening socket needs to stay in epoll */ + close(uflow->s[INISIDE]); + uflow->s[INISIDE] = -1; + } + + if (uflow->s[TGTSIDE] >= 0) { + /* But the flow specific one needs to be removed */ + epoll_ctl(c->epollfd, EPOLL_CTL_DEL, uflow->s[TGTSIDE], NULL); + close(uflow->s[TGTSIDE]); + uflow->s[TGTSIDE] = -1; + } + flow_hash_remove(c, FLOW_SIDX(uflow, INISIDE)); + if (!pif_is_socket(uflow->f.pif[TGTSIDE])) + flow_hash_remove(c, FLOW_SIDX(uflow, TGTSIDE)); +} + +/** + * udp_flow_new() - Common setup for a new UDP flow + * @c: Execution context + * @flow: Initiated flow + * @s_ini: Initiating socket (or -1) + * @now: Timestamp + * + * Return: UDP specific flow, if successful, NULL on failure + */ +static flow_sidx_t udp_flow_new(const struct ctx *c, union flow *flow, + int s_ini, const struct timespec *now) +{ + const struct flowside *ini = &flow->f.side[INISIDE]; + struct udp_flow *uflow = NULL; + const struct flowside *tgt; + uint8_t tgtpif; + + if (!inany_is_unicast(&ini->eaddr) || ini->eport == 0) { + flow_trace(flow, "Invalid endpoint to initiate UDP flow"); + goto cancel; + } + + if (!(tgt = flow_target(c, flow, IPPROTO_UDP))) + goto cancel; + tgtpif = flow->f.pif[TGTSIDE]; + + uflow = FLOW_SET_TYPE(flow, FLOW_UDP, udp); + uflow->ts = now->tv_sec; + uflow->s[INISIDE] = uflow->s[TGTSIDE] = -1; + + if (s_ini >= 0) { + /* When using auto port-scanning the listening port could go + * away, so we need to duplicate the socket + */ + uflow->s[INISIDE] = fcntl(s_ini, F_DUPFD_CLOEXEC, 0); + if (uflow->s[INISIDE] < 0) { + flow_err(uflow, + "Couldn't duplicate listening socket: %s", + strerror(errno)); + goto cancel; + } + } + + if (pif_is_socket(tgtpif)) { + struct mmsghdr discard[UIO_MAXIOV] = { 0 }; + union { + flow_sidx_t sidx; + uint32_t data; + } fref = { + .sidx = FLOW_SIDX(flow, TGTSIDE), + }; + int rc; + + uflow->s[TGTSIDE] = flowside_sock_l4(c, EPOLL_TYPE_UDP_REPLY, + tgtpif, tgt, fref.data); + if (uflow->s[TGTSIDE] < 0) { + flow_dbg(uflow, + "Couldn't open socket for spliced flow: %s", + strerror(errno)); + goto cancel; + } + + if (flowside_connect(c, uflow->s[TGTSIDE], tgtpif, tgt) < 0) { + flow_dbg(uflow, + "Couldn't connect flow socket: %s", + strerror(errno)); + goto cancel; + } + + /* It's possible, if unlikely, that we could receive some + * unrelated packets in between the bind() and connect() of this + * socket. For now we just discard these. We could consider + * trying to redirect these to an appropriate handler, if we + * need to. + */ + rc = recvmmsg(uflow->s[TGTSIDE], discard, ARRAY_SIZE(discard), + MSG_DONTWAIT, NULL); + if (rc >= ARRAY_SIZE(discard)) { + flow_dbg(uflow, + "Too many (%d) spurious reply datagrams", rc); + goto cancel; + } else if (rc > 0) { + flow_trace(uflow, + "Discarded %d spurious reply datagrams", rc); + } else if (errno != EAGAIN) { + flow_err(uflow, + "Unexpected error discarding datagrams: %s", + strerror(errno)); + } + } + + flow_hash_insert(c, FLOW_SIDX(uflow, INISIDE)); + + /* If the target side is a socket, it will be a reply socket that knows + * its own flowside. But if it's tap, then we need to look it up by + * hash. + */ + if (!pif_is_socket(tgtpif)) + flow_hash_insert(c, FLOW_SIDX(uflow, TGTSIDE)); + FLOW_ACTIVATE(uflow); + + return FLOW_SIDX(uflow, TGTSIDE); + +cancel: + if (uflow) + udp_flow_close(c, uflow); + flow_alloc_cancel(flow); + return FLOW_SIDX_NONE; +} + +/** + * udp_flow_from_sock() - Find or create UDP flow for "listening" socket + * @c: Execution context + * @ref: epoll reference of the receiving socket + * @s_in: Source socket address, filled in by recvmmsg() + * @now: Timestamp + * + * #syscalls fcntl + * + * Return: sidx for the destination side of the flow for this packet, or + * FLOW_SIDX_NONE if we couldn't find or create a flow. + */ +flow_sidx_t udp_flow_from_sock(const struct ctx *c, union epoll_ref ref, + const union sockaddr_inany *s_in, + const struct timespec *now) +{ + struct udp_flow *uflow; + union flow *flow; + flow_sidx_t sidx; + + ASSERT(ref.type == EPOLL_TYPE_UDP_LISTEN); + + sidx = flow_lookup_sa(c, IPPROTO_UDP, ref.udp.pif, s_in, ref.udp.port); + if ((uflow = udp_at_sidx(sidx))) { + uflow->ts = now->tv_sec; + return flow_sidx_opposite(sidx); + } + + if (!(flow = flow_alloc())) { + char sastr[SOCKADDR_STRLEN]; + + debug("Couldn't allocate flow for UDP datagram from %s %s", + pif_name(ref.udp.pif), + sockaddr_ntop(s_in, sastr, sizeof(sastr))); + return FLOW_SIDX_NONE; + } + + flow_initiate_sa(flow, ref.udp.pif, s_in, ref.udp.port); + return udp_flow_new(c, flow, ref.fd, now); +} + +/** + * udp_flow_from_tap() - Find or create UDP flow for tap packets + * @c: Execution context + * @pif: pif on which the packet is arriving + * @af: Address family, AF_INET or AF_INET6 + * @saddr: Source address on guest side + * @daddr: Destination address guest side + * @srcport: Source port on guest side + * @dstport: Destination port on guest side + * + * Return: sidx for the destination side of the flow for this packet, or + * FLOW_SIDX_NONE if we couldn't find or create a flow. + */ +flow_sidx_t udp_flow_from_tap(const struct ctx *c, + uint8_t pif, sa_family_t af, + const void *saddr, const void *daddr, + in_port_t srcport, in_port_t dstport, + const struct timespec *now) +{ + struct udp_flow *uflow; + union flow *flow; + flow_sidx_t sidx; + + ASSERT(pif == PIF_TAP); + + sidx = flow_lookup_af(c, IPPROTO_UDP, pif, af, saddr, daddr, + srcport, dstport); + if ((uflow = udp_at_sidx(sidx))) { + uflow->ts = now->tv_sec; + return flow_sidx_opposite(sidx); + } + + if (!(flow = flow_alloc())) { + char sstr[INET6_ADDRSTRLEN], dstr[INET6_ADDRSTRLEN]; + + debug("Couldn't allocate flow for UDP datagram from %s %s:%hu -> %s:%hu", + pif_name(pif), + inet_ntop(af, saddr, sstr, sizeof(sstr)), srcport, + inet_ntop(af, daddr, dstr, sizeof(dstr)), dstport); + return FLOW_SIDX_NONE; + } + + flow_initiate_af(flow, PIF_TAP, af, saddr, srcport, daddr, dstport); + + return udp_flow_new(c, flow, -1, now); +} + +/** + * udp_flow_timer() - Handler for timed events related to a given flow + * @c: Execution context + * @uflow: UDP flow + * @now: Current timestamp + * + * Return: true if the flow is ready to free, false otherwise + */ +bool udp_flow_timer(const struct ctx *c, struct udp_flow *uflow, + const struct timespec *now) +{ + if (now->tv_sec - uflow->ts <= UDP_CONN_TIMEOUT) + return false; + + udp_flow_close(c, uflow); + return true; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/passt-20240726.57a21d2/udp_flow.h new/passt-20240806.ee36266/udp_flow.h --- old/passt-20240726.57a21d2/udp_flow.h 2024-07-26 14:07:42.000000000 +0200 +++ new/passt-20240806.ee36266/udp_flow.h 2024-08-06 15:03:48.000000000 +0200 @@ -21,6 +21,15 @@ int s[SIDES]; }; +struct udp_flow *udp_at_sidx(flow_sidx_t sidx); +flow_sidx_t udp_flow_from_sock(const struct ctx *c, union epoll_ref ref, + const union sockaddr_inany *s_in, + const struct timespec *now); +flow_sidx_t udp_flow_from_tap(const struct ctx *c, + uint8_t pif, sa_family_t af, + const void *saddr, const void *daddr, + in_port_t srcport, in_port_t dstport, + const struct timespec *now); bool udp_flow_timer(const struct ctx *c, struct udp_flow *uflow, const struct timespec *now); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/passt-20240726.57a21d2/util.c new/passt-20240806.ee36266/util.c --- old/passt-20240726.57a21d2/util.c 2024-07-26 14:07:42.000000000 +0200 +++ new/passt-20240806.ee36266/util.c 2024-08-06 15:03:48.000000000 +0200 @@ -592,10 +592,9 @@ * * #syscalls write writev */ -int write_remainder(int fd, const struct iovec *iov, int iovcnt, size_t skip) +int write_remainder(int fd, const struct iovec *iov, size_t iovcnt, size_t skip) { - int i; - size_t offset; + size_t offset, i; while ((i = iov_skip_bytes(iov, iovcnt, skip, &offset)) < iovcnt) { ssize_t rc; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/passt-20240726.57a21d2/util.h new/passt-20240806.ee36266/util.h --- old/passt-20240726.57a21d2/util.h 2024-07-26 14:07:42.000000000 +0200 +++ new/passt-20240806.ee36266/util.h 2024-08-06 15:03:48.000000000 +0200 @@ -182,7 +182,7 @@ int __daemon(int pidfile_fd, int devnull_fd); int fls(unsigned long x); int write_file(const char *path, const char *buf); -int write_remainder(int fd, const struct iovec *iov, int iovcnt, size_t skip); +int write_remainder(int fd, const struct iovec *iov, size_t iovcnt, size_t skip); /** * af_name() - Return name of an address family