diff options
Diffstat (limited to 'udp_flow.c')
-rw-r--r-- | udp_flow.c | 61 |
1 files changed, 47 insertions, 14 deletions
@@ -8,6 +8,7 @@ #include <errno.h> #include <fcntl.h> #include <sys/uio.h> +#include <unistd.h> #include "util.h" #include "passt.h" @@ -38,8 +39,11 @@ struct udp_flow *udp_at_sidx(flow_sidx_t sidx) * @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]); @@ -55,6 +59,8 @@ static void udp_flow_close(const struct ctx *c, struct udp_flow *uflow) 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; } /** @@ -69,16 +75,10 @@ static void udp_flow_close(const struct ctx *c, struct udp_flow *uflow) 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]; @@ -95,7 +95,7 @@ static flow_sidx_t udp_flow_new(const struct ctx *c, union flow *flow, if (uflow->s[INISIDE] < 0) { flow_err(uflow, "Couldn't duplicate listening socket: %s", - strerror(errno)); + strerror_(errno)); goto cancel; } } @@ -115,14 +115,14 @@ static flow_sidx_t udp_flow_new(const struct ctx *c, union flow *flow, if (uflow->s[TGTSIDE] < 0) { flow_dbg(uflow, "Couldn't open socket for spliced flow: %s", - strerror(errno)); + 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)); + strerror_(errno)); goto cancel; } @@ -144,7 +144,7 @@ static flow_sidx_t udp_flow_new(const struct ctx *c, union flow *flow, } else if (errno != EAGAIN) { flow_err(uflow, "Unexpected error discarding datagrams: %s", - strerror(errno)); + strerror_(errno)); } } @@ -174,7 +174,7 @@ cancel: * @s_in: Source socket address, filled in by recvmmsg() * @now: Timestamp * - * #syscalls fcntl + * #syscalls fcntl arm:fcntl64 ppc64:fcntl64 i686:fcntl64 * * 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. @@ -183,6 +183,7 @@ 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) { + const struct flowside *ini; struct udp_flow *uflow; union flow *flow; flow_sidx_t sidx; @@ -204,7 +205,19 @@ flow_sidx_t udp_flow_from_sock(const struct ctx *c, union epoll_ref ref, return FLOW_SIDX_NONE; } - flow_initiate_sa(flow, ref.udp.pif, s_in, ref.udp.port); + ini = flow_initiate_sa(flow, ref.udp.pif, s_in, ref.udp.port); + + if (!inany_is_unicast(&ini->eaddr) || + ini->eport == 0 || ini->oport == 0) { + /* In principle ini->oddr also must be specified, but when we've + * been initiated from a socket bound to 0.0.0.0 or ::, we don't + * know our address, so we have to leave it unpopulated. + */ + flow_err(flow, "Invalid endpoint on UDP recvfrom()"); + flow_alloc_cancel(flow); + return FLOW_SIDX_NONE; + } + return udp_flow_new(c, flow, ref.fd, now); } @@ -227,6 +240,7 @@ flow_sidx_t udp_flow_from_tap(const struct ctx *c, in_port_t srcport, in_port_t dstport, const struct timespec *now) { + const struct flowside *ini; struct udp_flow *uflow; union flow *flow; flow_sidx_t sidx; @@ -250,12 +264,31 @@ flow_sidx_t udp_flow_from_tap(const struct ctx *c, return FLOW_SIDX_NONE; } - flow_initiate_af(flow, PIF_TAP, af, saddr, srcport, daddr, dstport); + ini = flow_initiate_af(flow, PIF_TAP, af, saddr, srcport, + daddr, dstport); + + if (inany_is_unspecified(&ini->eaddr) || ini->eport == 0 || + inany_is_unspecified(&ini->oaddr) || ini->oport == 0) { + flow_dbg(flow, "Invalid endpoint on UDP packet"); + flow_alloc_cancel(flow); + return FLOW_SIDX_NONE; + } return udp_flow_new(c, flow, -1, now); } /** + * 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 |