aboutgitcodebugslistschat
diff options
context:
space:
mode:
-rw-r--r--contrib/apparmor/abstractions/passt4
-rw-r--r--udp.c34
-rw-r--r--udp.h4
-rw-r--r--udp_flow.c30
-rw-r--r--udp_flow.h4
5 files changed, 69 insertions, 7 deletions
diff --git a/contrib/apparmor/abstractions/passt b/contrib/apparmor/abstractions/passt
index 0ffadaf..85bd1ee 100644
--- a/contrib/apparmor/abstractions/passt
+++ b/contrib/apparmor/abstractions/passt
@@ -41,6 +41,10 @@
@{PROC}/sys/net/ipv4/tcp_syn_linear_timeouts r,
@{PROC}/sys/net/ipv4/tcp_rto_max_ms r,
+ # udp_get_timeout_params(), udp.c
+ @{PROC}/sys/net/netfilter/nf_conntrack_udp_timeout r,
+ @{PROC}/sys/net/netfilter/nf_conntrack_udp_timeout_stream r,
+
network netlink raw, # nl_sock_init_do(), netlink.c
network inet stream, # tcp.c
diff --git a/udp.c b/udp.c
index b2383e2..19adda0 100644
--- a/udp.c
+++ b/udp.c
@@ -26,7 +26,10 @@
*
* We track pseudo-connections of this type as flow table entries of type
* FLOW_UDP. We store the time of the last traffic on the flow in uflow->ts,
- * and let the flow expire if there is no traffic for UDP_CONN_TIMEOUT seconds.
+ * and let the flow expire if there is no traffic for UDP_TIMEOUT seconds for
+ * unidirectional flows and flows with only one datagram and one reply, or
+ * UDP_TIMEOUT_STREAM seconds for bidirectional flows with more than one
+ * datagram on either side.
*
* NOTE: This won't handle multicast protocols, or some protocols with different
* port usage. We'll need specific logic if we want to handle those.
@@ -118,6 +121,13 @@
#define UDP_MAX_FRAMES 32 /* max # of frames to receive at once */
+#define UDP_TIMEOUT "/proc/sys/net/netfilter/nf_conntrack_udp_timeout"
+#define UDP_TIMEOUT_STREAM \
+ "/proc/sys/net/netfilter/nf_conntrack_udp_timeout_stream"
+
+#define UDP_TIMEOUT_DEFAULT 30 /* s */
+#define UDP_TIMEOUT_STREAM_DEFAULT 120 /* s */
+
/* Maximum UDP data to be returned in ICMP messages */
#define ICMP4_MAX_DLEN 8
#define ICMP6_MAX_DLEN (IPV6_MIN_MTU \
@@ -953,7 +963,7 @@ void udp_sock_handler(const struct ctx *c, union epoll_ref ref,
int s = ref.fd;
flow_trace(uflow, "Received data on reply socket");
- uflow->ts = now->tv_sec;
+ udp_flow_activity(uflow, !tosidx.sidei, now);
if (pif_is_socket(topif)) {
udp_sock_to_sock(c, ref.fd, n, tosidx);
@@ -1180,6 +1190,24 @@ static void udp_splice_iov_init(void)
}
/**
+ * udp_get_timeout_params() - Get host kernel UDP timeout parameters
+ * @c: Execution context
+ */
+static void udp_get_timeout_params(struct ctx *c)
+{
+ intmax_t v;
+
+ v = read_file_integer(UDP_TIMEOUT, UDP_TIMEOUT_DEFAULT);
+ c->udp.timeout = v;
+
+ v = read_file_integer(UDP_TIMEOUT_STREAM, UDP_TIMEOUT_STREAM_DEFAULT);
+ c->udp.stream_timeout = v;
+
+ debug("Using UDP timeout parameters, timeout: %d, stream_timeout: %d",
+ c->udp.timeout, c->udp.stream_timeout);
+}
+
+/**
* udp_init() - Initialise per-socket data, and sockets in namespace
* @c: Execution context
*
@@ -1189,6 +1217,8 @@ int udp_init(struct ctx *c)
{
ASSERT(!c->no_udp);
+ udp_get_timeout_params(c);
+
udp_iov_init(c);
if (fwd_listen_sync(c, &c->udp.fwd_in, PIF_HOST, IPPROTO_UDP) < 0)
diff --git a/udp.h b/udp.h
index 2b91d72..da9c2df 100644
--- a/udp.h
+++ b/udp.h
@@ -24,11 +24,15 @@ void udp_update_l2_buf(const unsigned char *eth_d);
* @fwd_in: Port forwarding configuration for inbound packets
* @fwd_out: Port forwarding configuration for outbound packets
* @timer_run: Timestamp of most recent timer run
+ * @timeout: Timeout for unidirectional flows (in s)
+ * @stream_timeout: Timeout for stream-like flows (in s)
*/
struct udp_ctx {
struct fwd_ports fwd_in;
struct fwd_ports fwd_out;
struct timespec timer_run;
+ int timeout;
+ int stream_timeout;
};
#endif /* UDP_H */
diff --git a/udp_flow.c b/udp_flow.c
index 1f5e84e..0023837 100644
--- a/udp_flow.c
+++ b/udp_flow.c
@@ -17,8 +17,6 @@
#include "udp_internal.h"
#include "epoll_ctl.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
@@ -152,6 +150,8 @@ static flow_sidx_t udp_flow_new(const struct ctx *c, union flow *flow,
uflow->ts = now->tv_sec;
uflow->s[INISIDE] = uflow->s[TGTSIDE] = -1;
uflow->ttl[INISIDE] = uflow->ttl[TGTSIDE] = 0;
+ uflow->activity[INISIDE] = 1;
+ uflow->activity[TGTSIDE] = 0;
flow_foreach_sidei(sidei) {
if (pif_is_socket(uflow->f.pif[sidei]))
@@ -228,7 +228,7 @@ flow_sidx_t udp_flow_from_sock(const struct ctx *c, uint8_t pif,
sidx = flow_lookup_sa(c, IPPROTO_UDP, pif, s_in, dst, port);
if ((uflow = udp_at_sidx(sidx))) {
- uflow->ts = now->tv_sec;
+ udp_flow_activity(uflow, sidx.sidei, now);
return flow_sidx_opposite(sidx);
}
@@ -285,7 +285,7 @@ flow_sidx_t udp_flow_from_tap(const struct ctx *c,
sidx = flow_lookup_af(c, IPPROTO_UDP, pif, af, saddr, daddr,
srcport, dstport);
if ((uflow = udp_at_sidx(sidx))) {
- uflow->ts = now->tv_sec;
+ udp_flow_activity(uflow, sidx.sidei, now);
return flow_sidx_opposite(sidx);
}
@@ -362,9 +362,29 @@ bool udp_flow_defer(const struct ctx *c, struct udp_flow *uflow,
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)
+ int timeout = c->udp.timeout;
+
+ if (uflow->activity[TGTSIDE] &&
+ (uflow->activity[INISIDE] > 1 || uflow->activity[TGTSIDE] > 1))
+ timeout = c->udp.stream_timeout;
+
+ if (now->tv_sec - uflow->ts <= timeout)
return false;
udp_flow_close(c, uflow);
return true;
}
+
+/**
+ * udp_flow_activity() - Track activity of a UDP flow
+ * @uflow: UDP flow
+ * @sidei: Side index of the flow (INISIDE or TGTSIDE)
+ * @now: Current timestamp
+ */
+void udp_flow_activity(struct udp_flow *uflow, unsigned int sidei,
+ const struct timespec *now)
+{
+ uflow->ts = now->tv_sec;
+ if (uflow->activity[sidei] < UINT8_MAX)
+ uflow->activity[sidei]++;
+}
diff --git a/udp_flow.h b/udp_flow.h
index 14e0f92..3ca49c5 100644
--- a/udp_flow.h
+++ b/udp_flow.h
@@ -16,6 +16,7 @@
* @flush1: @s[1] may have datagrams queued for other flows
* @ts: Activity timestamp
* @s: Socket fd (or -1) for each side of the flow
+ * @activity: Packets seen from each side of the flow, up to UINT8_MAX
*/
struct udp_flow {
/* Must be first element */
@@ -29,6 +30,7 @@ struct udp_flow {
time_t ts;
int s[SIDES];
+ uint8_t activity[SIDES];
};
struct udp_flow *udp_at_sidx(flow_sidx_t sidx);
@@ -46,5 +48,7 @@ bool udp_flow_defer(const struct ctx *c, struct udp_flow *uflow,
const struct timespec *now);
bool udp_flow_timer(const struct ctx *c, struct udp_flow *uflow,
const struct timespec *now);
+void udp_flow_activity(struct udp_flow *uflow, unsigned int sidei,
+ const struct timespec *now);
#endif /* UDP_FLOW_H */