<feed xmlns='http://www.w3.org/2005/Atom'>
<title>passt/tcp_splice.c, branch 2026_05_07.1afd4ed</title>
<subtitle>Plug A Simple Socket Transport</subtitle>
<link rel='alternate' type='text/html' href='https://passt.top/passt/'/>
<entry>
<title>treewide: Spell ASSERT() as assert()</title>
<updated>2026-03-20T20:05:29+00:00</updated>
<author>
<name>David Gibson</name>
<email>david@gibson.dropbear.id.au</email>
</author>
<published>2026-03-19T06:11:43+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=bc872d91765dfd6ff34b0e9a34bce410fac1cef3'/>
<id>bc872d91765dfd6ff34b0e9a34bce410fac1cef3</id>
<content type='text'>
The standard library assert(3), at least with glibc, hits our seccomp
filter and dies with SIGSYS before it's able to print a message, making it
near useless.  Therefore, since 7a8ed9459dfe ("Make assertions actually
useful") we've instead used our own implementation, named ASSERT().

This makes our code look slightly odd though - ASSERT() has the same
overall effect as assert(), it's just a different implementation.  More
importantly this makes it awkward to share code between passt/pasta proper
and things that compile in a more typical environment.  We're going to want
that for our upcoming dynamic configuration tool.

Address this by overriding the standard library's assert() implementation
with our own, instead of giving ours its own name.

The standard assert() is supposed to be omitted if NDEBUG is defined,
which ours doesn't do.  Implement that as well, so ours doesn't
unexpectedly differ.  For the -DNDEBUG case we do this by *not* overriding
assert(), since it will be a no-op anyway.  This requires a few places to
add a #include &lt;assert.h&gt; to let us compile (albeit with warnings) when
-DNDEBUG.

Signed-off-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
[sbrivio: Fix some conflicts and missing conversions as a result of
 applying "vu_common: Move iovec management into vu_collect()" first]
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The standard library assert(3), at least with glibc, hits our seccomp
filter and dies with SIGSYS before it's able to print a message, making it
near useless.  Therefore, since 7a8ed9459dfe ("Make assertions actually
useful") we've instead used our own implementation, named ASSERT().

This makes our code look slightly odd though - ASSERT() has the same
overall effect as assert(), it's just a different implementation.  More
importantly this makes it awkward to share code between passt/pasta proper
and things that compile in a more typical environment.  We're going to want
that for our upcoming dynamic configuration tool.

Address this by overriding the standard library's assert() implementation
with our own, instead of giving ours its own name.

The standard assert() is supposed to be omitted if NDEBUG is defined,
which ours doesn't do.  Implement that as well, so ours doesn't
unexpectedly differ.  For the -DNDEBUG case we do this by *not* overriding
assert(), since it will be a no-op anyway.  This requires a few places to
add a #include &lt;assert.h&gt; to let us compile (albeit with warnings) when
-DNDEBUG.

Signed-off-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
[sbrivio: Fix some conflicts and missing conversions as a result of
 applying "vu_common: Move iovec management into vu_collect()" first]
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>tcp, tcp_splice: Check for failures of shutdown(2)</title>
<updated>2026-01-31T02:56:57+00:00</updated>
<author>
<name>David Gibson</name>
<email>david@gibson.dropbear.id.au</email>
</author>
<published>2026-01-30T04:41:04+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=768baf42f1485a7f7c867c8eb3a7e5ddcddb9d86'/>
<id>768baf42f1485a7f7c867c8eb3a7e5ddcddb9d86</id>
<content type='text'>
shutdown(2) should never fail, unless we give it bad parameters (e.g.
passing it an fd which isn't a connected socket).  However, if it ever did,
we'd currently ignore the error and carry on which could lead to very
confusing behaviour.

In the interests of debugability, check for failure of shutdown(2), log an
error and:
 - during runtime, reset the affected connection
 - during migration, fail the migration

Signed-off-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
shutdown(2) should never fail, unless we give it bad parameters (e.g.
passing it an fd which isn't a connected socket).  However, if it ever did,
we'd currently ignore the error and carry on which could lead to very
confusing behaviour.

In the interests of debugability, check for failure of shutdown(2), log an
error and:
 - during runtime, reset the affected connection
 - during migration, fail the migration

Signed-off-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>tcp_splice: Force TCP RST on abnormal close conditions</title>
<updated>2026-01-27T11:40:29+00:00</updated>
<author>
<name>David Gibson</name>
<email>david@gibson.dropbear.id.au</email>
</author>
<published>2026-01-27T08:39:53+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=e3f70c05bad90368a1a89bf31a9015125232b9ae'/>
<id>e3f70c05bad90368a1a89bf31a9015125232b9ae</id>
<content type='text'>
When we need to prematurely close a spliced connection, we use:
    conn_flag(conn, CLOSING);
This does destroy the flow, but does so in the same way as a clean close
from both ends.  That's not what we want in error conditions, or when one
side of the flow has signalled an abnormal exit with an EPOLLHUP event.

Replace all places where we close the connection - except for the happy
path close - with calls to a new tcp_splice_rst() function, which forces
the sockets to emit a TCP RST on each side.

Link: https://bugs.passt.top/show_bug.cgi?id=193
Signed-off-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
When we need to prematurely close a spliced connection, we use:
    conn_flag(conn, CLOSING);
This does destroy the flow, but does so in the same way as a clean close
from both ends.  That's not what we want in error conditions, or when one
side of the flow has signalled an abnormal exit with an EPOLLHUP event.

Replace all places where we close the connection - except for the happy
path close - with calls to a new tcp_splice_rst() function, which forces
the sockets to emit a TCP RST on each side.

Link: https://bugs.passt.top/show_bug.cgi?id=193
Signed-off-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>tcp_splice: Register fds with epoll at flow creation</title>
<updated>2026-01-20T18:37:39+00:00</updated>
<author>
<name>Laurent Vivier</name>
<email>lvivier@redhat.com</email>
</author>
<published>2026-01-19T16:19:13+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=0fbd7af77d5222f46863cfc144f0582bd08eaf29'/>
<id>0fbd7af77d5222f46863cfc144f0582bd08eaf29</id>
<content type='text'>
Register both splice connection sockets with epoll using empty events
(events=0) in tcp_splice_connect(), before initiating the connection.

This allows tcp_splice_epoll_ctl() to always use EPOLL_CTL_MOD, removing
the need to check whether fds are already registered. As a result, the
conditional ADD/MOD logic is no longer needed, simplifying the function.

If the second flow_epoll_set() fails after the first succeeds, we don't
need explicit rollback: tcp_splice_conn_from_sock() sets the CLOSING
flag on error, and conn_flag() handles it by calling epoll_del() for
both sockets.

Signed-off-by: Laurent Vivier &lt;lvivier@redhat.com&gt;
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Register both splice connection sockets with epoll using empty events
(events=0) in tcp_splice_connect(), before initiating the connection.

This allows tcp_splice_epoll_ctl() to always use EPOLL_CTL_MOD, removing
the need to check whether fds are already registered. As a result, the
conditional ADD/MOD logic is no longer needed, simplifying the function.

If the second flow_epoll_set() fails after the first succeeds, we don't
need explicit rollback: tcp_splice_conn_from_sock() sets the CLOSING
flag on error, and conn_flag() handles it by calling epoll_del() for
both sockets.

Signed-off-by: Laurent Vivier &lt;lvivier@redhat.com&gt;
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>flow: Introduce flow_epoll_set() to centralize epoll operations</title>
<updated>2026-01-14T00:07:51+00:00</updated>
<author>
<name>Laurent Vivier</name>
<email>lvivier@redhat.com</email>
</author>
<published>2026-01-09T16:54:38+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=c0be730f2aa2243a132b3ee40c2bf05ebc84fedf'/>
<id>c0be730f2aa2243a132b3ee40c2bf05ebc84fedf</id>
<content type='text'>
Currently, each flow type (TCP, TCP_SPLICE, PING, UDP) has its own
code to add or modify file descriptors in epoll. This leads to
duplicated boilerplate code across icmp.c, tcp.c, tcp_splice.c, and
udp_flow.c, each setting up epoll_ref unions and calling epoll_ctl()
with flow-type-specific details.

Introduce flow_epoll_set() in flow.c to handle epoll operations for
all flow types in a unified way.

This will be needed to migrate queue pair from an epollfd to another.

Signed-off-by: Laurent Vivier &lt;lvivier@redhat.com&gt;
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Currently, each flow type (TCP, TCP_SPLICE, PING, UDP) has its own
code to add or modify file descriptors in epoll. This leads to
duplicated boilerplate code across icmp.c, tcp.c, tcp_splice.c, and
udp_flow.c, each setting up epoll_ref unions and calling epoll_ctl()
with flow-type-specific details.

Introduce flow_epoll_set() in flow.c to handle epoll operations for
all flow types in a unified way.

This will be needed to migrate queue pair from an epollfd to another.

Signed-off-by: Laurent Vivier &lt;lvivier@redhat.com&gt;
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>tcp_splice: Refactor tcp_splice_conn_epoll_events() to per-side computation</title>
<updated>2026-01-14T00:07:51+00:00</updated>
<author>
<name>Laurent Vivier</name>
<email>lvivier@redhat.com</email>
</author>
<published>2026-01-09T16:54:37+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=23da651ab08e564b84c532f6f93b0817d2ae850f'/>
<id>23da651ab08e564b84c532f6f93b0817d2ae850f</id>
<content type='text'>
The function tcp_splice_conn_epoll_events() currently takes an array of
struct epoll_event and fills in the .events field for both sides using
flow_foreach_sidei() loops.

This works, but the function is doing two conceptually separate things
at once: computing events for side 0 and computing events for side 1.
The OUT_WAIT handling is particularly subtle, as it has cross-side
effects: when OUT_WAIT(sidei) is set, we add EPOLLOUT to ev[sidei] but
also remove EPOLLIN from ev[!sidei].

Refactor to make the function compute events for a single side at a
time, taking sidei as a parameter and returning uint32_t. This makes
the logic more focused and easier to follow. The cross-side effects of
OUT_WAIT are preserved by checking both OUT_WAIT(sidei) and
OUT_WAIT(!sidei) within each call.

The caller tcp_splice_epoll_ctl() now invokes the function twice, once
for each side, making the two-sided nature of the operation explicit.

No functional change.

Signed-off-by: Laurent Vivier &lt;lvivier@redhat.com&gt;
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The function tcp_splice_conn_epoll_events() currently takes an array of
struct epoll_event and fills in the .events field for both sides using
flow_foreach_sidei() loops.

This works, but the function is doing two conceptually separate things
at once: computing events for side 0 and computing events for side 1.
The OUT_WAIT handling is particularly subtle, as it has cross-side
effects: when OUT_WAIT(sidei) is set, we add EPOLLOUT to ev[sidei] but
also remove EPOLLIN from ev[!sidei].

Refactor to make the function compute events for a single side at a
time, taking sidei as a parameter and returning uint32_t. This makes
the logic more focused and easier to follow. The cross-side effects of
OUT_WAIT are preserved by checking both OUT_WAIT(sidei) and
OUT_WAIT(!sidei) within each call.

The caller tcp_splice_epoll_ctl() now invokes the function twice, once
for each side, making the two-sided nature of the operation explicit.

No functional change.

Signed-off-by: Laurent Vivier &lt;lvivier@redhat.com&gt;
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>tcp_splice, flow: Add socket to epoll set before connect(), drop assert</title>
<updated>2025-12-09T00:27:24+00:00</updated>
<author>
<name>Stefano Brivio</name>
<email>sbrivio@redhat.com</email>
</author>
<published>2025-12-08T21:18:01+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=c3f1ba70237a9e66822aff3aa5765d0adf6f6307'/>
<id>c3f1ba70237a9e66822aff3aa5765d0adf6f6307</id>
<content type='text'>
...otherwise, if we have a real error on connect() (that is, not
EINPROGRESS), we'll return early from tcp_splice_connect() and later
try to fetch the epoll file descriptor:

  ASSERTION FAILED in flow_epollfd (flow.c:362): f-&gt;epollid &lt; ((1 &lt;&lt; 8) - 1)

which is still (correctly) EPOLLFD_ID_INVALID.

Replace the ASSERT() in flow_epollfd() with a warning, as it looks
like there might be harmless cases where the socket is not in the
epoll set yet, and we'll just crash for nothing. We can turn this back
to an ASSERT() once we audit these paths in more detail.

Link: https://bodhi.fedoraproject.org/updates/FEDORA-2025-93b4eb64c3#comment-4473411
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
...otherwise, if we have a real error on connect() (that is, not
EINPROGRESS), we'll return early from tcp_splice_connect() and later
try to fetch the epoll file descriptor:

  ASSERTION FAILED in flow_epollfd (flow.c:362): f-&gt;epollid &lt; ((1 &lt;&lt; 8) - 1)

which is still (correctly) EPOLLFD_ID_INVALID.

Replace the ASSERT() in flow_epollfd() with a warning, as it looks
like there might be harmless cases where the socket is not in the
epoll set yet, and we'll just crash for nothing. We can turn this back
to an ASSERT() once we audit these paths in more detail.

Link: https://bodhi.fedoraproject.org/updates/FEDORA-2025-93b4eb64c3#comment-4473411
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>inany: Let length of sockaddr_inany be implicit from the family</title>
<updated>2025-12-02T22:07:14+00:00</updated>
<author>
<name>David Gibson</name>
<email>david@gibson.dropbear.id.au</email>
</author>
<published>2025-12-02T04:02:05+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=b0523f6b0629358024e95b5d01dc81512cfa8e10'/>
<id>b0523f6b0629358024e95b5d01dc81512cfa8e10</id>
<content type='text'>
sockaddr_inany can contain either an IPv4 or IPv6 socket address, so the
relevant length for bind() or connect() can vary.  In pif_sockaddr() we
return that length, and in sock_l4_sa() we take it as an extra parameter.

However, sockaddr_inany always contains exactly a sockaddr_in or a
sockaddr_in6 each with a fixed size.  Therefore we can derive the relevant
length from the family, and don't need to pass it around separately.

Make a tiny helper to get the relevant address length, and update all
interfaces to use that approach instead.

In the process, fix a buglet in tcp_flow_repair_bind(): we passed
sizeof(union sockaddr_inany) to bind() instead of the specific length for
the address family.  Since the sizeof() is always longer than the specific
length, this is probably fine, but not theoretically correct.

Signed-off-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
sockaddr_inany can contain either an IPv4 or IPv6 socket address, so the
relevant length for bind() or connect() can vary.  In pif_sockaddr() we
return that length, and in sock_l4_sa() we take it as an extra parameter.

However, sockaddr_inany always contains exactly a sockaddr_in or a
sockaddr_in6 each with a fixed size.  Therefore we can derive the relevant
length from the family, and don't need to pass it around separately.

Make a tiny helper to get the relevant address length, and update all
interfaces to use that approach instead.

In the process, fix a buglet in tcp_flow_repair_bind(): we passed
sizeof(union sockaddr_inany) to bind() instead of the specific length for
the address family.  Since the sizeof() is always longer than the specific
length, this is probably fine, but not theoretically correct.

Signed-off-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>tcp, flow: Replace per-connection in_epoll flag with an epollid in flow_common</title>
<updated>2025-10-30T14:32:50+00:00</updated>
<author>
<name>Laurent Vivier</name>
<email>lvivier@redhat.com</email>
</author>
<published>2025-10-21T21:01:13+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=dd5302dd7bf518aa2c50a9819ee06ea2d6fd0061'/>
<id>dd5302dd7bf518aa2c50a9819ee06ea2d6fd0061</id>
<content type='text'>
The in_epoll boolean flag in tcp_tap_conn and tcp_splice_conn only tracked
whether a connection was registered with epoll, not which epoll instance.
This limited flexibility for future multi-epoll support.

Replace the boolean with an epollid field in flow_common that identifies
which epoll instance the flow is registered with.
Use FLOW_EPOLLID_INVALID to indicate when a flow is not registered with
any epoll instance. An epoll_id_to_fd[] mapping table translates
epoll ids to their corresponding epoll file descriptors.

Add helper functions:
- flow_in_epoll() to check if a flow is registered with epoll
- flow_epollfd() to retrieve the epoll fd for a flow's thread
- flow_epollid_register() to register an epoll fd with an epollid
- flow_epollid_set() to set the epollid of a flow
- flow_epollid_clear() to reset the epoll id of a flow

This change also simplifies tcp_timer_ctl() and conn_flag_do() by removing
the need to pass the context 'c', since the epoll fd is now directly
accessible from the flow structure via flow_epollfd().

Add a defensive check at the beginning of tcp_flow_repair_queue() to
avoid a false positive with "make clang-tidy":
  error: The 1st argument to 'send' is &lt; 0 but should be &gt;= 0
   3230 |                 ssize_t rc = send(conn-&gt;sock, p, MIN(len, chunk), 0);

Signed-off-by: Laurent Vivier &lt;lvivier@redhat.com&gt;
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The in_epoll boolean flag in tcp_tap_conn and tcp_splice_conn only tracked
whether a connection was registered with epoll, not which epoll instance.
This limited flexibility for future multi-epoll support.

Replace the boolean with an epollid field in flow_common that identifies
which epoll instance the flow is registered with.
Use FLOW_EPOLLID_INVALID to indicate when a flow is not registered with
any epoll instance. An epoll_id_to_fd[] mapping table translates
epoll ids to their corresponding epoll file descriptors.

Add helper functions:
- flow_in_epoll() to check if a flow is registered with epoll
- flow_epollfd() to retrieve the epoll fd for a flow's thread
- flow_epollid_register() to register an epoll fd with an epollid
- flow_epollid_set() to set the epollid of a flow
- flow_epollid_clear() to reset the epoll id of a flow

This change also simplifies tcp_timer_ctl() and conn_flag_do() by removing
the need to pass the context 'c', since the epoll fd is now directly
accessible from the flow structure via flow_epollfd().

Add a defensive check at the beginning of tcp_flow_repair_queue() to
avoid a false positive with "make clang-tidy":
  error: The 1st argument to 'send' is &lt; 0 but should be &gt;= 0
   3230 |                 ssize_t rc = send(conn-&gt;sock, p, MIN(len, chunk), 0);

Signed-off-by: Laurent Vivier &lt;lvivier@redhat.com&gt;
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>epoll_ctl: Extract epoll operations</title>
<updated>2025-10-30T14:32:12+00:00</updated>
<author>
<name>Laurent Vivier</name>
<email>lvivier@redhat.com</email>
</author>
<published>2025-10-21T21:01:11+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=965ea66068e653934c0016281df86c17e2a65625'/>
<id>965ea66068e653934c0016281df86c17e2a65625</id>
<content type='text'>
Centralize epoll_add() and epoll_del() helper functions into new
epoll_ctl.c/h files.

This also moves the union epoll_ref definition from passt.h to
epoll_ctl.h where it's more logically placed.

The new epoll_add() helper simplifies adding file descriptors to epoll
by taking an epoll_ref and events, handling error reporting
consistently across all call sites.

Signed-off-by: Laurent Vivier &lt;lvivier@redhat.com&gt;
[sbrivio: Include epoll_ctl.h from netlink.c as it's now needed there]
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Centralize epoll_add() and epoll_del() helper functions into new
epoll_ctl.c/h files.

This also moves the union epoll_ref definition from passt.h to
epoll_ctl.h where it's more logically placed.

The new epoll_add() helper simplifies adding file descriptors to epoll
by taking an epoll_ref and events, handling error reporting
consistently across all call sites.

Signed-off-by: Laurent Vivier &lt;lvivier@redhat.com&gt;
[sbrivio: Include epoll_ctl.h from netlink.c as it's now needed there]
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</pre>
</div>
</content>
</entry>
</feed>
