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-09-10 21:12:37
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/passt (Old)
 and      /work/SRC/openSUSE:Factory/.passt.new.17570 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "passt"

Tue Sep 10 21:12:37 2024 rev:15 rq:1199710 version:20240906.6b38f07

Changes:
--------
--- /work/SRC/openSUSE:Factory/passt/passt.changes      2024-08-29 
15:42:45.947731463 +0200
+++ /work/SRC/openSUSE:Factory/.passt.new.17570/passt.changes   2024-09-10 
21:12:50.061040120 +0200
@@ -1,0 +2,30 @@
+Mon Sep 09 06:57:41 UTC 2024 - dcer...@suse.com
+
+- Update to version 20240906.6b38f07:
+  * apparmor: Allow read access to /proc/sys/net/ipv4/ip_local_port_range
+  * selinux: Allow read access to /proc/sys/net/ipv4/ip_local_port_range
+  * tap: Don't risk truncating frames on full buffer in tap_pasta_input()
+  * tap: Restructure in tap_pasta_input()
+  * tap: Improve handling of EINTR in tap_passt_input()
+  * tap: Split out handling of EPOLLIN events
+  * util: Fix order of operands and carry of one second in timespec_diff_us()
+  * cppcheck: Work around some cppcheck 2.15.0 redundantInitialization warnings
+  * tcp: Use EPOLLET for any state of not established connections
+  * udp: Handle more error conditions in udp_sock_errs()
+  * udp: Treat errors getting errors as unrecoverable
+  * udp: Split socket error handling out from udp_sock_recv()
+  * flow: Helpers to log details of a flow
+  * udp: Allow UDP flows to be prematurely closed
+  * flow: Fix incorrect hash probe in flowside_lookup()
+  * log: Don't prefix log file messages with time and severity if they're 
continuations
+  * Makefile: Enable _FORTIFY_SOURCE iff needed
+  * fwd, conf: Probe host's ephemeral ports
+  * conf, fwd: Don't attempt to forward port 0
+  * conf, fwd: Make ephemeral port logic more flexible
+  * seccomp.sh: Try to account for terminal width while formatting list of 
system calls
+  * udp: Use dual stack sockets for port forwarding when possible
+  * udp: Remove unnnecessary local from udp_sock_init()
+  * udp: Merge udp[46]_mh_recv arrays
+  * test: Look for possible sshd-session paths (if it's there at all) in 
mbuto's profile
+
+-------------------------------------------------------------------

Old:
----
  passt-20240821.1d6142f.tar.zst

New:
----
  passt-20240906.6b38f07.tar.zst

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ passt.spec ++++++
--- /var/tmp/diff_new_pack.zI9ihB/_old  2024-09-10 21:12:50.845072787 +0200
+++ /var/tmp/diff_new_pack.zI9ihB/_new  2024-09-10 21:12:50.849072954 +0200
@@ -44,7 +44,7 @@
 %endif
 
 Name:           passt
-Version:        20240821.1d6142f
+Version:        20240906.6b38f07
 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.zI9ihB/_old  2024-09-10 21:12:50.881074287 +0200
+++ /var/tmp/diff_new_pack.zI9ihB/_new  2024-09-10 21:12:50.885074453 +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_08_21.1d6142f</param>
+    <param name="revision">2024_09_06.6b38f07</param>
   </service>
   <service mode="manual" name="recompress">
     <param name="file">*.tar</param>

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.zI9ihB/_old  2024-09-10 21:12:50.905075287 +0200
+++ /var/tmp/diff_new_pack.zI9ihB/_new  2024-09-10 21:12:50.909075454 +0200
@@ -1,6 +1,6 @@
 <servicedata>
 <service name="tar_scm">
                 <param name="url">https://passt.top/passt</param>
-              <param 
name="changesrevision">1d6142f362c761ad800b0cbf6ab69cea426658e8</param></service></servicedata>
+              <param 
name="changesrevision">6b38f0723949f8b4b2787ee55d4330249a1a4a3e</param></service></servicedata>
 (No newline at EOF)
 

++++++ passt-20240821.1d6142f.tar.zst -> passt-20240906.6b38f07.tar.zst ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/passt-20240821.1d6142f/Makefile 
new/passt-20240906.6b38f07/Makefile
--- old/passt-20240821.1d6142f/Makefile 2024-08-21 12:05:26.000000000 +0200
+++ new/passt-20240906.6b38f07/Makefile 2024-09-06 15:34:06.000000000 +0200
@@ -33,9 +33,16 @@
 AUDIT_ARCH := $(shell echo $(AUDIT_ARCH) | sed 's/HPPA/PARISC/')
 AUDIT_ARCH := $(shell echo $(AUDIT_ARCH) | sed 's/SH4/SH/')
 
+# On some systems enabling optimization also enables source fortification,
+# automagically. Do not override it.
+FORTIFY_FLAG :=
+ifeq ($(shell $(CC) -O2 -dM -E - < /dev/null 2>&1 | grep ' _FORTIFY_SOURCE ' > 
/dev/null; echo $$?),1)
+FORTIFY_FLAG := -D_FORTIFY_SOURCE=2
+endif
+
 FLAGS := -Wall -Wextra -Wno-format-zero-length
 FLAGS += -pedantic -std=c11 -D_XOPEN_SOURCE=700 -D_GNU_SOURCE
-FLAGS += -D_FORTIFY_SOURCE=2 -O2 -pie -fPIE
+FLAGS +=  $(FORTIFY_FLAG) -O2 -pie -fPIE
 FLAGS += -DPAGE_SIZE=$(shell getconf PAGE_SIZE)
 FLAGS += -DNETNS_RUN_DIR=\"/run/netns\"
 FLAGS += -DPASST_AUDIT_ARCH=AUDIT_ARCH_$(AUDIT_ARCH)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/passt-20240821.1d6142f/conf.c 
new/passt-20240906.6b38f07/conf.c
--- old/passt-20240821.1d6142f/conf.c   2024-08-21 12:05:26.000000000 +0200
+++ new/passt-20240906.6b38f07/conf.c   2024-09-06 15:34:06.000000000 +0200
@@ -156,9 +156,15 @@
                        die("'all' port forwarding is only allowed for passt");
 
                fwd->mode = FWD_ALL;
-               memset(fwd->map, 0xff, PORT_EPHEMERAL_MIN / 8);
 
-               for (i = 0; i < PORT_EPHEMERAL_MIN; i++) {
+               /* Skip port 0.  It has special meaning for many socket APIs, so
+                * trying to bind it is not really safe.
+                */
+               for (i = 1; i < NUM_PORTS; i++) {
+                       if (fwd_port_is_ephemeral(i))
+                               continue;
+
+                       bitmap_set(fwd->map, i);
                        if (optname == 't') {
                                ret = tcp_sock_init(c, AF_UNSPEC, NULL, NULL,
                                                    i);
@@ -259,8 +265,12 @@
        } while ((p = next_chunk(p, ',')));
 
        if (exclude_only) {
-               for (i = 0; i < PORT_EPHEMERAL_MIN; i++) {
-                       if (bitmap_isset(exclude, i))
+               /* Skip port 0.  It has special meaning for many socket APIs, so
+                * trying to bind it is not really safe.
+                */
+               for (i = 1; i < NUM_PORTS; i++) {
+                       if (fwd_port_is_ephemeral(i) ||
+                           bitmap_isset(exclude, i))
                                continue;
 
                        bitmap_set(fwd->map, i);
@@ -1711,6 +1721,7 @@
        /* Inbound port options & DNS can be parsed now (after IPv4/IPv6
         * settings)
         */
+       fwd_probe_ephemeral();
        udp_portmap_clear();
        optind = 0;
        do {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/passt-20240821.1d6142f/contrib/apparmor/abstractions/passt 
new/passt-20240906.6b38f07/contrib/apparmor/abstractions/passt
--- old/passt-20240821.1d6142f/contrib/apparmor/abstractions/passt      
2024-08-21 12:05:26.000000000 +0200
+++ new/passt-20240906.6b38f07/contrib/apparmor/abstractions/passt      
2024-09-06 15:34:06.000000000 +0200
@@ -34,6 +34,8 @@
 
   owner @{PROC}/@{pid}/uid_map         r,      # conf_ugid()
 
+  @{PROC}/sys/net/ipv4/ip_local_port_range r,  # fwd_probe_ephemeral()
+
   network netlink raw,                         # nl_sock_init_do(), netlink.c
 
   network inet stream,                         # tcp.c
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/passt-20240821.1d6142f/contrib/selinux/passt.te 
new/passt-20240906.6b38f07/contrib/selinux/passt.te
--- old/passt-20240821.1d6142f/contrib/selinux/passt.te 2024-08-21 
12:05:26.000000000 +0200
+++ new/passt-20240906.6b38f07/contrib/selinux/passt.te 2024-09-06 
15:34:06.000000000 +0200
@@ -50,6 +50,7 @@
        type passwd_file_t;
 
        class netlink_route_socket { bind create nlmsg_read };
+       type sysctl_net_t;
 
        class capability { sys_tty_config setuid setgid };
        class cap_userns { setpcap sys_admin sys_ptrace };
@@ -104,6 +105,8 @@
 allow passt_t tmp_t:sock_file { create unlink write };
 allow passt_t self:netlink_route_socket { bind create nlmsg_read read write 
setopt };
 kernel_search_network_sysctl(passt_t)
+allow passt_t sysctl_net_t:dir search;
+allow passt_t sysctl_net_t:file { open read };
 
 corenet_tcp_bind_all_nodes(passt_t)
 corenet_udp_bind_all_nodes(passt_t)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/passt-20240821.1d6142f/contrib/selinux/pasta.te 
new/passt-20240906.6b38f07/contrib/selinux/pasta.te
--- old/passt-20240821.1d6142f/contrib/selinux/pasta.te 2024-08-21 
12:05:26.000000000 +0200
+++ new/passt-20240906.6b38f07/contrib/selinux/pasta.te 2024-09-06 
15:34:06.000000000 +0200
@@ -196,7 +196,7 @@
 allow pasta_t self:tun_socket create;
 allow pasta_t tun_tap_device_t:chr_file { ioctl open read write };
 allow pasta_t sysctl_net_t:dir search;
-allow pasta_t sysctl_net_t:file { open write };
+allow pasta_t sysctl_net_t:file { open read write };
 allow pasta_t kernel_t:system module_request;
 
 allow pasta_t nsfs_t:file read;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/passt-20240821.1d6142f/flow.c 
new/passt-20240906.6b38f07/flow.c
--- old/passt-20240821.1d6142f/flow.c   2024-08-21 12:05:26.000000000 +0200
+++ new/passt-20240906.6b38f07/flow.c   2024-09-06 15:34:06.000000000 +0200
@@ -283,28 +283,23 @@
               "Flow %u (%s): %s", flow_idx(f), type_or_state, msg);
 }
 
-/**
- * flow_set_state() - Change flow's state
- * @f:         Flow changing state
- * @state:     New state
+/** flow_log_details_() - Log the details of a flow
+ * @f:         flow to log
+ * @pri:       Log priority
+ * @state:     State to log details according to
+ *
+ * Logs the details of the flow: endpoints, interfaces, type etc.
  */
-static void flow_set_state(struct flow_common *f, enum flow_state state)
+void flow_log_details_(const struct flow_common *f, int pri,
+                      enum flow_state state)
 {
        char estr0[INANY_ADDRSTRLEN], fstr0[INANY_ADDRSTRLEN];
        char estr1[INANY_ADDRSTRLEN], fstr1[INANY_ADDRSTRLEN];
        const struct flowside *ini = &f->side[INISIDE];
        const struct flowside *tgt = &f->side[TGTSIDE];
-       uint8_t oldstate = f->state;
-
-       ASSERT(state < FLOW_NUM_STATES);
-       ASSERT(oldstate < FLOW_NUM_STATES);
-
-       f->state = state;
-       flow_log_(f, LOG_DEBUG, "%s -> %s", flow_state_str[oldstate],
-                 FLOW_STATE(f));
 
-       if (MAX(state, oldstate) >= FLOW_STATE_TGT)
-               flow_log_(f, LOG_DEBUG,
+       if (state >= FLOW_STATE_TGT)
+               flow_log_(f, pri,
                          "%s [%s]:%hu -> [%s]:%hu => %s [%s]:%hu -> [%s]:%hu",
                          pif_name(f->pif[INISIDE]),
                          inany_ntop(&ini->eaddr, estr0, sizeof(estr0)),
@@ -316,8 +311,8 @@
                          tgt->oport,
                          inany_ntop(&tgt->eaddr, estr1, sizeof(estr1)),
                          tgt->eport);
-       else if (MAX(state, oldstate) >= FLOW_STATE_INI)
-               flow_log_(f, LOG_DEBUG, "%s [%s]:%hu -> [%s]:%hu => ?",
+       else if (state >= FLOW_STATE_INI)
+               flow_log_(f, pri, "%s [%s]:%hu -> [%s]:%hu => ?",
                          pif_name(f->pif[INISIDE]),
                          inany_ntop(&ini->eaddr, estr0, sizeof(estr0)),
                          ini->eport,
@@ -326,6 +321,25 @@
 }
 
 /**
+ * flow_set_state() - Change flow's state
+ * @f:         Flow changing state
+ * @state:     New state
+ */
+static void flow_set_state(struct flow_common *f, enum flow_state state)
+{
+       uint8_t oldstate = f->state;
+
+       ASSERT(state < FLOW_NUM_STATES);
+       ASSERT(oldstate < FLOW_NUM_STATES);
+
+       f->state = state;
+       flow_log_(f, LOG_DEBUG, "%s -> %s", flow_state_str[oldstate],
+                 FLOW_STATE(f));
+
+       flow_log_details_(f, LOG_DEBUG, MAX(state, oldstate));
+}
+
+/**
  * flow_initiate_() - Move flow to INI, setting pif[INISIDE]
  * @flow:      Flow to change state
  * @pif:       pif of the initiating side
@@ -697,7 +711,7 @@
               !(FLOW_PROTO(&flow->f) == proto &&
                 flow->f.pif[sidx.sidei] == pif &&
                 flowside_eq(&flow->f.side[sidx.sidei], side)))
-               b = (b + 1) % FLOW_HASH_SIZE;
+               b = mod_sub(b, 1, FLOW_HASH_SIZE);
 
        return flow_hashtab[b];
 }
@@ -832,7 +846,8 @@
                                closed = icmp_ping_timer(c, &flow->ping, now);
                        break;
                case FLOW_UDP:
-                       if (timer)
+                       closed = udp_flow_defer(&flow->udp);
+                       if (!closed && timer)
                                closed = udp_flow_timer(c, &flow->udp, now);
                        break;
                default:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/passt-20240821.1d6142f/flow.h 
new/passt-20240906.6b38f07/flow.h
--- old/passt-20240821.1d6142f/flow.h   2024-08-21 12:05:26.000000000 +0200
+++ new/passt-20240906.6b38f07/flow.h   2024-09-06 15:34:06.000000000 +0200
@@ -264,4 +264,11 @@
                        flow_dbg((f), __VA_ARGS__);                     \
        } while (0)
 
+void flow_log_details_(const struct flow_common *f, int pri,
+                      enum flow_state state);
+#define flow_log_details(f_, pri) \
+       flow_log_details_(&((f_)->f), (pri), (f_)->f.state)
+#define flow_dbg_details(f_)   flow_log_details((f_), LOG_DEBUG)
+#define flow_err_details(f_)   flow_log_details((f_), LOG_ERR)
+
 #endif /* FLOW_H */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/passt-20240821.1d6142f/fwd.c 
new/passt-20240906.6b38f07/fwd.c
--- old/passt-20240821.1d6142f/fwd.c    2024-08-21 12:05:26.000000000 +0200
+++ new/passt-20240906.6b38f07/fwd.c    2024-09-06 15:34:06.000000000 +0200
@@ -27,6 +27,80 @@
 #include "lineread.h"
 #include "flow_table.h"
 
+/* Empheral port range: values from RFC 6335 */
+static in_port_t fwd_ephemeral_min = (1 << 15) + (1 << 14);
+static in_port_t fwd_ephemeral_max = NUM_PORTS - 1;
+
+#define PORT_RANGE_SYSCTL      "/proc/sys/net/ipv4/ip_local_port_range"
+
+/** fwd_probe_ephemeral() - Determine what ports this host considers ephemeral
+ *
+ * Work out what ports the host thinks are emphemeral and record it for later
+ * use by fwd_port_is_ephemeral().  If we're unable to probe, assume the range
+ * recommended by RFC 6335.
+ */
+void fwd_probe_ephemeral(void)
+{
+       char *line, *tab, *end;
+       struct lineread lr;
+       long min, max;
+       ssize_t len;
+       int fd;
+
+       fd = open(PORT_RANGE_SYSCTL, O_RDONLY | O_CLOEXEC);
+       if (fd < 0) {
+               warn_perror("Unable to open %s", PORT_RANGE_SYSCTL);
+               return;
+       }
+
+       lineread_init(&lr, fd);
+       len = lineread_get(&lr, &line);
+       close(fd);
+
+       if (len < 0)
+               goto parse_err;
+
+       tab = strchr(line, '\t');
+       if (!tab)
+               goto parse_err;
+       *tab = '\0';
+
+       errno = 0;
+       min = strtol(line, &end, 10);
+       if (*end || errno)
+               goto parse_err;
+
+       errno = 0;
+       max = strtol(tab + 1, &end, 10);
+       if (*end || errno)
+               goto parse_err;
+
+       if (min < 0 || min >= NUM_PORTS ||
+           max < 0 || max >= NUM_PORTS)
+               goto parse_err;
+
+       fwd_ephemeral_min = min;
+       fwd_ephemeral_max = max;
+
+       return;
+
+parse_err:
+       warn("Unable to parse %s", PORT_RANGE_SYSCTL);
+}
+
+/**
+ * fwd_port_is_ephemeral() - Is port number ephemeral?
+ * @port:      Port number
+ *
+ * Return: true if @port is ephemeral, that is may be allocated by the kernel 
as
+ *         a local port for outgoing connections or datagrams, but should not 
be
+ *         used for binding services to.
+ */
+bool fwd_port_is_ephemeral(in_port_t port)
+{
+       return (port >= fwd_ephemeral_min) && (port <= fwd_ephemeral_max);
+}
+
 /* See enum in kernel's include/net/tcp_states.h */
 #define UDP_LISTEN     0x07
 #define TCP_LISTEN     0x0a
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/passt-20240821.1d6142f/fwd.h 
new/passt-20240906.6b38f07/fwd.h
--- old/passt-20240821.1d6142f/fwd.h    2024-08-21 12:05:26.000000000 +0200
+++ new/passt-20240906.6b38f07/fwd.h    2024-09-06 15:34:06.000000000 +0200
@@ -12,6 +12,9 @@
 /* Number of ports for both TCP and UDP */
 #define        NUM_PORTS       (1U << 16)
 
+void fwd_probe_ephemeral(void);
+bool fwd_port_is_ephemeral(in_port_t port);
+
 enum fwd_ports_mode {
        FWD_UNSET = 0,
        FWD_SPEC = 1,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/passt-20240821.1d6142f/log.c 
new/passt-20240906.6b38f07/log.c
--- old/passt-20240821.1d6142f/log.c    2024-08-21 12:05:26.000000000 +0200
+++ new/passt-20240906.6b38f07/log.c    2024-09-06 15:34:06.000000000 +0200
@@ -224,19 +224,23 @@
 /**
  * logfile_write() - Write entry to log file, trigger rotation if full
  * @newline:   Append newline at the end of the message, if missing
+ * @cont:      Continuation of a previous message, on the same line
  * @pri:       Facility and level map, same as priority for vsyslog()
  * @now:       Timestamp
  * @format:    Same as vsyslog() format
  * @ap:                Same as vsyslog() ap
  */
-static void logfile_write(bool newline, int pri, const struct timespec *now,
+static void logfile_write(bool newline, bool cont, int pri,
+                         const struct timespec *now,
                          const char *format, va_list ap)
 {
        char buf[BUFSIZ];
-       int n;
+       int n = 0;
 
-       n  = logtime_fmt(buf, BUFSIZ, now);
-       n += snprintf(buf + n, BUFSIZ - n, ": %s", logfile_prefix[pri]);
+       if (!cont) {
+               n += logtime_fmt(buf, BUFSIZ, now);
+               n += snprintf(buf + n, BUFSIZ - n, ": %s", logfile_prefix[pri]);
+       }
 
        n += vsnprintf(buf + n, BUFSIZ - n, format, ap);
 
@@ -278,7 +282,7 @@
 
                va_copy(ap2, ap); /* Don't clobber ap, we need it again */
                if (log_file != -1)
-                       logfile_write(newline, pri, now, format, ap2);
+                       logfile_write(newline, cont, pri, now, format, ap2);
                else if (!(log_mask & LOG_MASK(LOG_DEBUG)))
                        passt_vsyslog(newline, pri, format, ap2);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/passt-20240821.1d6142f/pasta.c 
new/passt-20240906.6b38f07/pasta.c
--- old/passt-20240821.1d6142f/pasta.c  2024-08-21 12:05:26.000000000 +0200
+++ new/passt-20240906.6b38f07/pasta.c  2024-09-06 15:34:06.000000000 +0200
@@ -427,12 +427,12 @@
  */
 void pasta_netns_quit_init(const struct ctx *c)
 {
-       union epoll_ref ref = { .type = EPOLL_TYPE_NSQUIT_INOTIFY };
        struct epoll_event ev = { .events = EPOLLIN };
        int flags = O_NONBLOCK | O_CLOEXEC;
        struct statfs s = { 0 };
        bool try_inotify = true;
        int fd = -1, dir_fd;
+       union epoll_ref ref;
 
        if (c->mode != MODE_PASTA || c->no_netns_quit || !*c->netns_base)
                return;
@@ -463,6 +463,7 @@
                ref.type = EPOLL_TYPE_NSQUIT_TIMER;
        } else {
                close(dir_fd);
+               ref.type = EPOLL_TYPE_NSQUIT_INOTIFY;
        }
 
        if (fd > FD_REF_MAX)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/passt-20240821.1d6142f/seccomp.sh 
new/passt-20240906.6b38f07/seccomp.sh
--- old/passt-20240821.1d6142f/seccomp.sh       2024-08-21 12:05:26.000000000 
+0200
+++ new/passt-20240906.6b38f07/seccomp.sh       2024-09-06 15:34:06.000000000 
+0200
@@ -242,7 +242,10 @@
        __calls="$(sed -n 's/[\t ]*\*[\t ]*#syscalls\(:'"${__p}"'\|\)[\t 
]\{1,\}\(.*\)/\2/p' ${IN})"
        __calls="${__calls} ${EXTRA_SYSCALLS:-}"
        __calls="$(filter ${__calls})"
-       echo "seccomp profile ${__p} allows: ${__calls}" | tr '\n' ' ' | fmt -t
+
+       cols="$(stty -a | sed -n 's/.*columns \([0-9]*\).*/\1/p' || :)" 
2>/dev/null
+       case $cols in [0-9]*) col_args="-w ${cols}";; *) col_args="";; esac
+       echo "seccomp profile ${__p} allows: ${__calls}" | tr '\n' ' ' | fmt -t 
${col_args}
 
        # Pad here to keep gen_profile() "simple"
        __count=0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/passt-20240821.1d6142f/tap.c 
new/passt-20240906.6b38f07/tap.c
--- old/passt-20240821.1d6142f/tap.c    2024-08-21 12:05:26.000000000 +0200
+++ new/passt-20240906.6b38f07/tap.c    2024-09-06 15:34:06.000000000 +0200
@@ -982,24 +982,17 @@
 }
 
 /**
- * tap_handler_passt() - Packet handler for AF_UNIX file descriptor
+ * tap_passt_input() - Handler for new data on the socket to qemu
  * @c:         Execution context
- * @events:    epoll events
  * @now:       Current timestamp
  */
-void tap_handler_passt(struct ctx *c, uint32_t events,
-                      const struct timespec *now)
+static void tap_passt_input(struct ctx *c, const struct timespec *now)
 {
        static const char *partial_frame;
        static ssize_t partial_len = 0;
        ssize_t n;
        char *p;
 
-       if (events & (EPOLLRDHUP | EPOLLHUP | EPOLLERR)) {
-               tap_sock_reset(c);
-               return;
-       }
-
        tap_flush_pools();
 
        if (partial_len) {
@@ -1010,10 +1003,13 @@
                memmove(pkt_buf, partial_frame, partial_len);
        }
 
-       n = recv(c->fd_tap, pkt_buf + partial_len, TAP_BUF_BYTES - partial_len,
-                MSG_DONTWAIT);
+       do {
+               n = recv(c->fd_tap, pkt_buf + partial_len,
+                        TAP_BUF_BYTES - partial_len, MSG_DONTWAIT);
+       } while ((n < 0) && errno == EINTR);
+
        if (n < 0) {
-               if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK) {
+               if (errno != EAGAIN && errno != EWOULDBLOCK) {
                        err_perror("Receive error on guest connection, reset");
                        tap_sock_reset(c);
                }
@@ -1052,54 +1048,76 @@
 }
 
 /**
- * tap_handler_pasta() - Packet handler for /dev/net/tun file descriptor
+ * tap_handler_passt() - Event handler for AF_UNIX file descriptor
  * @c:         Execution context
  * @events:    epoll events
  * @now:       Current timestamp
  */
-void tap_handler_pasta(struct ctx *c, uint32_t events,
+void tap_handler_passt(struct ctx *c, uint32_t events,
                       const struct timespec *now)
 {
-       ssize_t n, len;
-       int ret;
+       if (events & (EPOLLRDHUP | EPOLLHUP | EPOLLERR)) {
+               tap_sock_reset(c);
+               return;
+       }
 
-       if (events & (EPOLLRDHUP | EPOLLHUP | EPOLLERR))
-               die("Disconnect event on /dev/net/tun device, exiting");
+       if (events & EPOLLIN)
+               tap_passt_input(c, now);
+}
 
-redo:
-       n = 0;
+/**
+ * tap_pasta_input() - Handler for new data on the socket to hypervisor
+ * @c:         Execution context
+ * @now:       Current timestamp
+ */
+static void tap_pasta_input(struct ctx *c, const struct timespec *now)
+{
+       ssize_t n, len;
 
        tap_flush_pools();
-restart:
-       while ((len = read(c->fd_tap, pkt_buf + n, TAP_BUF_BYTES - n)) > 0) {
 
-               if (len < (ssize_t)sizeof(struct ethhdr) ||
-                   len > (ssize_t)ETH_MAX_MTU) {
-                       n += len;
-                       continue;
-               }
+       for (n = 0; n <= (ssize_t)TAP_BUF_BYTES - ETH_MAX_MTU; n += len) {
+               len = read(c->fd_tap, pkt_buf + n, ETH_MAX_MTU);
 
+               if (len == 0) {
+                       die("EOF on tap device, exiting");
+               } else if (len < 0) {
+                       if (errno == EINTR) {
+                               len = 0;
+                               continue;
+                       }
 
-               tap_add_packet(c, len, pkt_buf + n);
+                       if (errno == EAGAIN && errno == EWOULDBLOCK)
+                               break; /* all done for now */
 
-               if ((n += len) == TAP_BUF_BYTES)
-                       break;
-       }
+                       die("Error on tap device, exiting");
+               }
 
-       if (len < 0 && errno == EINTR)
-               goto restart;
+               /* Ignore frames of bad length */
+               if (len < (ssize_t)sizeof(struct ethhdr) ||
+                   len > (ssize_t)ETH_MAX_MTU)
+                       continue;
 
-       ret = errno;
+               tap_add_packet(c, len, pkt_buf + n);
+       }
 
        tap_handler(c, now);
+}
 
-       if (len > 0 || ret == EAGAIN)
-               return;
-
-       if (n == TAP_BUF_BYTES)
-               goto redo;
+/**
+ * tap_handler_pasta() - Packet handler for /dev/net/tun file descriptor
+ * @c:         Execution context
+ * @events:    epoll events
+ * @now:       Current timestamp
+ */
+void tap_handler_pasta(struct ctx *c, uint32_t events,
+                      const struct timespec *now)
+{
+       if (events & (EPOLLRDHUP | EPOLLHUP | EPOLLERR))
+               die("Disconnect event on /dev/net/tun device, exiting");
 
-       die("Error on tap device, exiting");
+       if (events & EPOLLIN)
+               tap_pasta_input(c, now);
 }
 
 /**
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/passt-20240821.1d6142f/tcp.c 
new/passt-20240906.6b38f07/tcp.c
--- old/passt-20240821.1d6142f/tcp.c    2024-08-21 12:05:26.000000000 +0200
+++ new/passt-20240906.6b38f07/tcp.c    2024-09-06 15:34:06.000000000 +0200
@@ -440,7 +440,7 @@
        if (events == TAP_SYN_RCVD)
                return EPOLLOUT | EPOLLET | EPOLLRDHUP;
 
-       return EPOLLRDHUP;
+       return EPOLLET | EPOLLRDHUP;
 }
 
 /**
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/passt-20240821.1d6142f/test/passt.mbuto 
new/passt-20240906.6b38f07/test/passt.mbuto
--- old/passt-20240821.1d6142f/test/passt.mbuto 2024-08-21 12:05:26.000000000 
+0200
+++ new/passt-20240906.6b38f07/test/passt.mbuto 2024-09-06 15:34:06.000000000 
+0200
@@ -13,8 +13,15 @@
 PROGS="${PROGS:-ash,dash,bash ip mount ls insmod mkdir ln cat chmod lsmod
        modprobe find grep mknod mv rm umount jq iperf3 dhclient hostname
        sed tr chown sipcalc cut socat dd strace ping tail killall sleep sysctl
-       nproc tcp_rr tcp_crr udp_rr which tee seq bc sshd ssh-keygen cmp
-       /usr/lib/openssh/sshd-session}"
+       nproc tcp_rr tcp_crr udp_rr which tee seq bc sshd ssh-keygen cmp}"
+
+# OpenSSH 9.8 introduced split binaries, with sshd being the daemon, and
+# sshd-session the per-session program. We need the latter as well, and the 
path
+# depends on the distribution. It doesn't exist on older versions.
+for bin in /usr/lib/openssh/sshd-session /usr/lib/ssh/sshd-session \
+          /usr/libexec/openssh/sshd-session; do
+       command -v "${bin}" >/dev/null && PROGS="${PROGS} ${bin}"
+done
 
 KMODS="${KMODS:- virtio_net virtio_pci vmw_vsock_virtio_transport}"
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/passt-20240821.1d6142f/udp.c 
new/passt-20240906.6b38f07/udp.c
--- old/passt-20240821.1d6142f/udp.c    2024-08-21 12:05:26.000000000 +0200
+++ new/passt-20240906.6b38f07/udp.c    2024-09-06 15:34:06.000000000 +0200
@@ -178,8 +178,7 @@
 
 /* IOVs and msghdr arrays for receiving datagrams from sockets */
 static struct iovec    udp_iov_recv            [UDP_MAX_FRAMES];
-static struct mmsghdr  udp4_mh_recv            [UDP_MAX_FRAMES];
-static struct mmsghdr  udp6_mh_recv            [UDP_MAX_FRAMES];
+static struct mmsghdr  udp_mh_recv             [UDP_MAX_FRAMES];
 
 /* IOVs and msghdr arrays for sending "spliced" datagrams to sockets */
 static union sockaddr_inany udp_splice_to;
@@ -222,6 +221,7 @@
 static void udp_iov_init_one(const struct ctx *c, size_t i)
 {
        struct udp_payload_t *payload = &udp_payload[i];
+       struct msghdr *mh = &udp_mh_recv[i].msg_hdr;
        struct udp_meta_t *meta = &udp_meta[i];
        struct iovec *siov = &udp_iov_recv[i];
        struct iovec *tiov = udp_l2_iov[i];
@@ -236,27 +236,10 @@
        tiov[UDP_IOV_TAP] = tap_hdr_iov(c, &meta->taph);
        tiov[UDP_IOV_PAYLOAD].iov_base = payload;
 
-       /* It's useful to have separate msghdr arrays for receiving.  Otherwise,
-        * an IPv4 recv() will alter msg_namelen, so we'd have to reset it every
-        * time or risk truncating the address on future IPv6 recv()s.
-        */
-       if (c->ifi4) {
-               struct msghdr *mh = &udp4_mh_recv[i].msg_hdr;
-
-               mh->msg_name    = &meta->s_in;
-               mh->msg_namelen = sizeof(struct sockaddr_in);
-               mh->msg_iov     = siov;
-               mh->msg_iovlen  = 1;
-       }
-
-       if (c->ifi6) {
-               struct msghdr *mh = &udp6_mh_recv[i].msg_hdr;
-
-               mh->msg_name    = &meta->s_in;
-               mh->msg_namelen = sizeof(struct sockaddr_in6);
-               mh->msg_iov     = siov;
-               mh->msg_iovlen  = 1;
-       }
+       mh->msg_name    = &meta->s_in;
+       mh->msg_namelen = sizeof(meta->s_in);
+       mh->msg_iov     = siov;
+       mh->msg_iovlen  = 1;
 }
 
 /**
@@ -404,11 +387,12 @@
  * udp_sock_recverr() - Receive and clear an error from a socket
  * @s:         Socket to receive from
  *
- * Return: true if errors received and processed, false if no more errors
+ * Return: 1 if error received and processed, 0 if no more errors in queue, < 0
+ *         if there was an error reading the queue
  *
  * #syscalls recvmsg
  */
-static bool udp_sock_recverr(int s)
+static int udp_sock_recverr(int s)
 {
        const struct sock_extended_err *ee;
        const struct cmsghdr *hdr;
@@ -425,14 +409,16 @@
 
        rc = recvmsg(s, &mh, MSG_ERRQUEUE);
        if (rc < 0) {
-               if (errno != EAGAIN && errno != EWOULDBLOCK)
-                       err_perror("Failed to read error queue");
-               return false;
+               if (errno == EAGAIN || errno == EWOULDBLOCK)
+                       return 0;
+
+               err_perror("UDP: Failed to read error queue");
+               return -1;
        }
 
        if (!(mh.msg_flags & MSG_ERRQUEUE)) {
                err("Missing MSG_ERRQUEUE flag reading error queue");
-               return false;
+               return -1;
        }
 
        hdr = CMSG_FIRSTHDR(&mh);
@@ -441,7 +427,7 @@
              (hdr->cmsg_level == IPPROTO_IPV6 &&
               hdr->cmsg_type == IPV6_RECVERR))) {
                err("Unexpected cmsg reading error queue");
-               return false;
+               return -1;
        }
 
        ee = (const struct sock_extended_err *)CMSG_DATA(hdr);
@@ -450,7 +436,54 @@
        debug("%s error on UDP socket %i: %s",
              str_ee_origin(ee), s, strerror(ee->ee_errno));
 
-       return true;
+       return 1;
+}
+
+/**
+ * udp_sock_errs() - Process errors on a socket
+ * @c:         Execution context
+ * @s:         Socket to receive from
+ * @events:    epoll events bitmap
+ *
+ * Return: Number of errors handled, or < 0 if we have an unrecoverable error
+ */
+static int udp_sock_errs(const struct ctx *c, int s, uint32_t events)
+{
+       unsigned n_err = 0;
+       socklen_t errlen;
+       int rc, err;
+
+       ASSERT(!c->no_udp);
+
+       if (!(events & EPOLLERR))
+               return 0; /* Nothing to do */
+
+       /* Empty the error queue */
+       while ((rc = udp_sock_recverr(s)) > 0)
+               n_err += rc;
+
+       if (rc < 0)
+               return -1; /* error reading error, unrecoverable */
+
+       errlen = sizeof(err);
+       if (getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &errlen) < 0 ||
+           errlen != sizeof(err)) {
+               err_perror("Error reading SO_ERROR");
+               return -1;  /* error reading error, unrecoverable */
+       }
+
+       if (err) {
+               debug("Unqueued error on UDP socket %i: %s", s, strerror(err));
+               n_err++;
+       }
+
+       if (!n_err) {
+               /* EPOLLERR, but no errors to clear !? */
+               err("EPOLLERR event without reported errors on socket %i", s);
+               return -1; /* no way to clear, unrecoverable */
+       }
+
+       return n_err;
 }
 
 /**
@@ -460,6 +493,8 @@
  * @events:    epoll events bitmap
  * @mmh                mmsghdr array to receive into
  *
+ * Return: Number of datagrams received
+ *
  * #syscalls recvmmsg arm:recvmmsg_time64 i686:recvmmsg_time64
  */
 static int udp_sock_recv(const struct ctx *c, int s, uint32_t events,
@@ -476,12 +511,6 @@
 
        ASSERT(!c->no_udp);
 
-       /* Clear any errors first */
-       if (events & EPOLLERR) {
-               while (udp_sock_recverr(s))
-                       ;
-       }
-
        if (!(events & EPOLLIN))
                return 0;
 
@@ -506,10 +535,17 @@
 void udp_listen_sock_handler(const struct ctx *c, union epoll_ref ref,
                             uint32_t events, const struct timespec *now)
 {
-       struct mmsghdr *mmh_recv = ref.udp.v6 ? udp6_mh_recv : udp4_mh_recv;
+       const socklen_t sasize = sizeof(udp_meta[0].s_in);
        int n, i;
 
-       if ((n = udp_sock_recv(c, ref.fd, events, mmh_recv)) <= 0)
+       if (udp_sock_errs(c, ref.fd, events) < 0) {
+               err("UDP: Unrecoverable error on listening socket:"
+                   " (%s port %hu)", pif_name(ref.udp.pif), ref.udp.port);
+               /* FIXME: what now?  close/re-open socket? */
+               return;
+       }
+
+       if ((n = udp_sock_recv(c, ref.fd, events, udp_mh_recv)) <= 0)
                return;
 
        /* We divide datagrams into batches based on how we need to send them,
@@ -518,6 +554,7 @@
         * populate it one entry *ahead* of the loop counter.
         */
        udp_meta[0].tosidx = udp_flow_from_sock(c, ref, &udp_meta[0].s_in, now);
+       udp_mh_recv[0].msg_hdr.msg_namelen = sasize;
        for (i = 0; i < n; ) {
                flow_sidx_t batchsidx = udp_meta[i].tosidx;
                uint8_t batchpif = pif_at_sidx(batchsidx);
@@ -525,9 +562,9 @@
 
                do {
                        if (pif_is_socket(batchpif)) {
-                               udp_splice_prepare(mmh_recv, i);
+                               udp_splice_prepare(udp_mh_recv, i);
                        } else if (batchpif == PIF_TAP) {
-                               udp_tap_prepare(mmh_recv, i,
+                               udp_tap_prepare(udp_mh_recv, i,
                                                flowside_at_sidx(batchsidx));
                        }
 
@@ -537,6 +574,7 @@
                        udp_meta[i].tosidx = udp_flow_from_sock(c, ref,
                                                                
&udp_meta[i].s_in,
                                                                now);
+                       udp_mh_recv[i].msg_hdr.msg_namelen = sasize;
                } while (flow_sidx_eq(udp_meta[i].tosidx, batchsidx));
 
                if (pif_is_socket(batchpif)) {
@@ -572,19 +610,23 @@
 void udp_reply_sock_handler(const struct ctx *c, union epoll_ref ref,
                            uint32_t events, const struct timespec *now)
 {
-       const struct flowside *fromside = flowside_at_sidx(ref.flowside);
        flow_sidx_t tosidx = flow_sidx_opposite(ref.flowside);
        const struct flowside *toside = flowside_at_sidx(tosidx);
        struct udp_flow *uflow = udp_at_sidx(ref.flowside);
        int from_s = uflow->s[ref.flowside.sidei];
-       bool v6 = !inany_v4(&fromside->eaddr);
-       struct mmsghdr *mmh_recv = v6 ? udp6_mh_recv : udp4_mh_recv;
        uint8_t topif = pif_at_sidx(tosidx);
        int n, i;
 
        ASSERT(!c->no_udp && uflow);
 
-       if ((n = udp_sock_recv(c, from_s, events, mmh_recv)) <= 0)
+       if (udp_sock_errs(c, from_s, events) < 0) {
+               flow_err(uflow, "Unrecoverable error on reply socket");
+               flow_err_details(uflow);
+               udp_flow_close(c, uflow);
+               return;
+       }
+
+       if ((n = udp_sock_recv(c, from_s, events, udp_mh_recv)) <= 0)
                return;
 
        flow_trace(uflow, "Received %d datagrams on reply socket", n);
@@ -592,9 +634,11 @@
 
        for (i = 0; i < n; i++) {
                if (pif_is_socket(topif))
-                       udp_splice_prepare(mmh_recv, i);
+                       udp_splice_prepare(udp_mh_recv, i);
                else if (topif == PIF_TAP)
-                       udp_tap_prepare(mmh_recv, i, toside);
+                       udp_tap_prepare(udp_mh_recv, i, toside);
+               /* Restore sockaddr length clobbered by recvmsg() */
+               udp_mh_recv[i].msg_hdr.msg_namelen = sizeof(udp_meta[i].s_in);
        }
 
        if (pif_is_socket(topif)) {
@@ -729,45 +773,58 @@
 int udp_sock_init(const struct ctx *c, int ns, sa_family_t af,
                  const void *addr, const char *ifname, in_port_t port)
 {
-       union udp_listen_epoll_ref uref = { .port = port };
-       int s, r4 = FD_REF_MAX + 1, r6 = FD_REF_MAX + 1;
+       union udp_listen_epoll_ref uref = {
+               .pif = ns ? PIF_SPLICE : PIF_HOST,
+               .port = port,
+       };
+       int r4 = FD_REF_MAX + 1, r6 = FD_REF_MAX + 1;
 
        ASSERT(!c->no_udp);
 
-       if (ns)
-               uref.pif = PIF_SPLICE;
-       else
-               uref.pif = PIF_HOST;
-
-       if ((af == AF_INET || af == AF_UNSPEC) && c->ifi4) {
-               uref.v6 = 0;
+       if (af == AF_UNSPEC && c->ifi4 && c->ifi6) {
+               int s;
 
+               /* Attempt to get a dual stack socket */
                if (!ns) {
-                       r4 = s = sock_l4(c, AF_INET, EPOLL_TYPE_UDP_LISTEN,
-                                        addr, ifname, port, uref.u32);
-
+                       s = sock_l4(c, AF_UNSPEC, EPOLL_TYPE_UDP_LISTEN,
+                                   addr, ifname, port, uref.u32);
                        udp_splice_init[V4][port] = s < 0 ? -1 : s;
+                       udp_splice_init[V6][port] = s < 0 ? -1 : s;
                } else {
-                       r4 = s = sock_l4(c, AF_INET, EPOLL_TYPE_UDP_LISTEN,
-                                        &in4addr_loopback,
-                                        ifname, port, uref.u32);
+                       s = sock_l4(c, AF_UNSPEC, EPOLL_TYPE_UDP_LISTEN,
+                                   &in4addr_loopback, ifname, port, uref.u32);
                        udp_splice_ns[V4][port] = s < 0 ? -1 : s;
+                       udp_splice_ns[V6][port] = s < 0 ? -1 : s;
                }
+               if (IN_INTERVAL(0, FD_REF_MAX, s))
+                       return 0;
        }
 
-       if ((af == AF_INET6 || af == AF_UNSPEC) && c->ifi6) {
-               uref.v6 = 1;
+       if ((af == AF_INET || af == AF_UNSPEC) && c->ifi4) {
+               if (!ns) {
+                       r4 = sock_l4(c, AF_INET, EPOLL_TYPE_UDP_LISTEN,
+                                    addr, ifname, port, uref.u32);
+
+                       udp_splice_init[V4][port] = r4 < 0 ? -1 : r4;
+               } else {
+                       r4  = sock_l4(c, AF_INET, EPOLL_TYPE_UDP_LISTEN,
+                                     &in4addr_loopback,
+                                     ifname, port, uref.u32);
+                       udp_splice_ns[V4][port] = r4 < 0 ? -1 : r4;
+               }
+       }
 
+       if ((af == AF_INET6 || af == AF_UNSPEC) && c->ifi6) {
                if (!ns) {
-                       r6 = s = sock_l4(c, AF_INET6, EPOLL_TYPE_UDP_LISTEN,
-                                        addr, ifname, port, uref.u32);
+                       r6 = sock_l4(c, AF_INET6, EPOLL_TYPE_UDP_LISTEN,
+                                    addr, ifname, port, uref.u32);
 
-                       udp_splice_init[V6][port] = s < 0 ? -1 : s;
+                       udp_splice_init[V6][port] = r6 < 0 ? -1 : r6;
                } else {
-                       r6 = s = sock_l4(c, AF_INET6, EPOLL_TYPE_UDP_LISTEN,
-                                        &in6addr_loopback,
-                                        ifname, port, uref.u32);
-                       udp_splice_ns[V6][port] = s < 0 ? -1 : s;
+                       r6 = sock_l4(c, AF_INET6, EPOLL_TYPE_UDP_LISTEN,
+                                    &in6addr_loopback,
+                                    ifname, port, uref.u32);
+                       udp_splice_ns[V6][port] = r6 < 0 ? -1 : r6;
                }
        }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/passt-20240821.1d6142f/udp.h 
new/passt-20240906.6b38f07/udp.h
--- old/passt-20240821.1d6142f/udp.h    2024-08-21 12:05:26.000000000 +0200
+++ new/passt-20240906.6b38f07/udp.h    2024-09-06 15:34:06.000000000 +0200
@@ -26,14 +26,12 @@
  * union udp_listen_epoll_ref - epoll reference for "listening" UDP sockets
  * @port:              Source port for connected sockets, bound port otherwise
  * @pif:               pif for this socket
- * @v6:                        Set for IPv6 sockets or connections
  * @u32:               Opaque u32 value of reference
  */
 union udp_listen_epoll_ref {
        struct {
                in_port_t       port;
                uint8_t         pif;
-               bool            v6:1;
        };
        uint32_t u32;
 };
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/passt-20240821.1d6142f/udp_flow.c 
new/passt-20240906.6b38f07/udp_flow.c
--- old/passt-20240821.1d6142f/udp_flow.c       2024-08-21 12:05:26.000000000 
+0200
+++ new/passt-20240906.6b38f07/udp_flow.c       2024-09-06 15:34:06.000000000 
+0200
@@ -39,8 +39,11 @@
  * @c:         Execution context
  * @uflow:     UDP flow
  */
-static void udp_flow_close(const struct ctx *c, struct udp_flow *uflow)
+void udp_flow_close(const struct ctx *c, struct udp_flow *uflow)
 {
+       if (uflow->closed)
+               return; /* Nothing to do */
+
        if (uflow->s[INISIDE] >= 0) {
                /* The listening socket needs to stay in epoll */
                close(uflow->s[INISIDE]);
@@ -56,6 +59,8 @@
        flow_hash_remove(c, FLOW_SIDX(uflow, INISIDE));
        if (!pif_is_socket(uflow->f.pif[TGTSIDE]))
                flow_hash_remove(c, FLOW_SIDX(uflow, TGTSIDE));
+
+       uflow->closed = true;
 }
 
 /**
@@ -257,6 +262,17 @@
 }
 
 /**
+ * udp_flow_defer() - Deferred per-flow handling (clean up aborted flows)
+ * @uflow:     Flow to handle
+ *
+ * Return: true if the connection is ready to free, false otherwise
+ */
+bool udp_flow_defer(const struct udp_flow *uflow)
+{
+       return uflow->closed;
+}
+
+/**
  * udp_flow_timer() - Handler for timed events related to a given flow
  * @c:         Execution context
  * @uflow:     UDP flow
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/passt-20240821.1d6142f/udp_flow.h 
new/passt-20240906.6b38f07/udp_flow.h
--- old/passt-20240821.1d6142f/udp_flow.h       2024-08-21 12:05:26.000000000 
+0200
+++ new/passt-20240906.6b38f07/udp_flow.h       2024-09-06 15:34:06.000000000 
+0200
@@ -10,6 +10,7 @@
 /**
  * struct udp - Descriptor for a flow of UDP packets
  * @f:         Generic flow information
+ * @closed:    Flow is already closed
  * @ts:                Activity timestamp
  * @s:         Socket fd (or -1) for each side of the flow
  */
@@ -17,6 +18,7 @@
        /* Must be first element */
        struct flow_common f;
 
+       bool closed :1;
        time_t ts;
        int s[SIDES];
 };
@@ -30,6 +32,8 @@
                              const void *saddr, const void *daddr,
                              in_port_t srcport, in_port_t dstport,
                              const struct timespec *now);
+void udp_flow_close(const struct ctx *c, struct udp_flow *uflow);
+bool udp_flow_defer(const struct udp_flow *uflow);
 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-20240821.1d6142f/util.c 
new/passt-20240906.6b38f07/util.c
--- old/passt-20240821.1d6142f/util.c   2024-08-21 12:05:26.000000000 +0200
+++ new/passt-20240906.6b38f07/util.c   2024-09-06 15:34:06.000000000 +0200
@@ -249,7 +249,7 @@
 int64_t timespec_diff_us(const struct timespec *a, const struct timespec *b)
 {
        if (a->tv_nsec < b->tv_nsec) {
-               return (b->tv_nsec - a->tv_nsec) / 1000 +
+               return (a->tv_nsec + 1000000000 - b->tv_nsec) / 1000 +
                       (a->tv_sec - b->tv_sec - 1) * 1000000;
        }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/passt-20240821.1d6142f/util.h 
new/passt-20240906.6b38f07/util.h
--- old/passt-20240821.1d6142f/util.h   2024-08-21 12:05:26.000000000 +0200
+++ new/passt-20240906.6b38f07/util.h   2024-09-06 15:34:06.000000000 +0200
@@ -95,9 +95,6 @@
 #define FD_PROTO(x, proto)                                             \
        (IN_INTERVAL(c->proto.fd_min, c->proto.fd_max, (x)))
 
-#define PORT_EPHEMERAL_MIN     ((1 << 15) + (1 << 14))         /* RFC 6335 */
-#define PORT_IS_EPHEMERAL(port) ((port) >= PORT_EPHEMERAL_MIN)
-
 #define MAC_ZERO               ((uint8_t [ETH_ALEN]){ 0 })
 #define MAC_IS_ZERO(addr)      (!memcmp((addr), MAC_ZERO, ETH_ALEN))
 

Reply via email to