@@ -575,10 +575,6 @@
mi->n_clients_delta = 0;
/* prevent dangling pointers */
- if (m->pending == mi)
- {
- multi_set_pending(m, NULL);
- }
if (m->earliest_wakeup == mi)
{
m->earliest_wakeup = NULL;
@@ -3098,18 +3094,15 @@
ret = false;
}
}
+#ifdef MULTI_DEBUG_EVENT_LOOP
else
{
- /* continue to pend on output? */
- multi_set_pending(m, ANY_OUT(&mi->context) ? mi : NULL);
-
-#ifdef MULTI_DEBUG_EVENT_LOOP
- printf("POST %s[%d] to=%d lo=%d/%d w=%" PRIi64 "/%ld\n", id(mi), (int)(mi == m->pending),
+ printf("POST %s[%d] to=%d lo=%d/%d w=%" PRIi64 "/%ld\n", id(mi), (int)ANY_OUT(&mi->context),
mi->context.c2.to_tun.len, mi->context.c2.to_link.len,
mi->context.c2.fragment ? mi->context.c2.fragment->outgoing.len : -1,
(int64_t)mi->context.c2.timeval.tv_sec, (long)mi->context.c2.timeval.tv_usec);
-#endif
}
+#endif
if ((flags & MPP_RECORD_TOUCH) && m->mpp_touched)
{
@@ -3400,13 +3393,14 @@
* data packets.
*/
static void
-multi_process_incoming_link_data(struct multi_context *m, bool floated, struct link_socket *sock)
+multi_process_incoming_link_data(struct multi_context *m, struct multi_instance *mi, bool floated,
+ struct link_socket *sock)
{
struct link_socket_info *lsi = &sock->info;
const uint8_t *orig_buf;
/* decrypt in instance context */
- struct context *c = &m->pending->context;
+ struct context *c = &mi->context;
orig_buf = c->c2.buf.data;
if (process_incoming_link_part1(c, lsi, floated))
@@ -3414,7 +3408,7 @@
/* nonzero length means that we have a valid, decrypted packed */
if (floated && c->c2.buf.len > 0)
{
- multi_process_float(m, m->pending, sock);
+ multi_process_float(m, mi, sock);
}
process_incoming_link_part2(c, lsi, orig_buf);
@@ -3433,7 +3427,7 @@
c->c2.to_tun.len = 0;
}
/* make sure that source address is associated with this client */
- else if (multi_get_instance_by_virtual_addr(m, &src, true) != m->pending)
+ else if (multi_get_instance_by_virtual_addr(m, &src, true) != mi)
{
/* IPv6 link-local address (fe80::xxx)? */
if ((src.type & MR_ADDR_MASK) == MR_ADDR_IPV6
@@ -3458,18 +3452,18 @@
if (mroute_flags & MROUTE_EXTRACT_MCAST)
{
/* for now, treat multicast as broadcast */
- multi_bcast(m, &c->c2.to_tun, m->pending, 0);
+ multi_bcast(m, &c->c2.to_tun, mi, 0);
}
else /* possible client to client routing */
{
ASSERT(!(mroute_flags & MROUTE_EXTRACT_BCAST));
- struct multi_instance *mi = multi_get_instance_by_virtual_addr(m, &dest, true);
+ struct multi_instance *dest_mi = multi_get_instance_by_virtual_addr(m, &dest, true);
/* if dest addr is a known client, route to it */
- if (mi)
+ if (dest_mi)
{
{
- multi_unicast(m, &c->c2.to_tun, mi);
+ multi_unicast(m, &c->c2.to_tun, dest_mi);
register_activity(c, BLEN(&c->c2.to_tun));
}
c->c2.to_tun.len = 0;
@@ -3502,23 +3496,24 @@
if (mroute_flags & MROUTE_EXTRACT_SUCCEEDED)
{
- if (multi_learn_addr(m, m->pending, &src, 0) == m->pending)
+ if (multi_learn_addr(m, mi, &src, 0) == mi)
{
/* check for broadcast */
if (m->enable_c2c)
{
if (mroute_flags & (MROUTE_EXTRACT_BCAST | MROUTE_EXTRACT_MCAST))
{
- multi_bcast(m, &c->c2.to_tun, m->pending, vid);
+ multi_bcast(m, &c->c2.to_tun, mi, vid);
}
else /* try client-to-client routing */
{
- struct multi_instance *mi = multi_get_instance_by_virtual_addr(m, &dest, false);
+ struct multi_instance *dest_mi =
+ multi_get_instance_by_virtual_addr(m, &dest, false);
/* if dest addr is a known client, route to it */
- if (mi)
+ if (dest_mi)
{
- multi_unicast(m, &c->c2.to_tun, mi);
+ multi_unicast(m, &c->c2.to_tun, dest_mi);
register_activity(c, BLEN(&c->c2.to_tun));
c->c2.to_tun.len = 0;
}
@@ -3550,35 +3545,27 @@
multi_process_incoming_link(struct multi_context *m, struct multi_instance *instance,
const unsigned int mpp_flags, struct link_socket *sock)
{
+ struct multi_instance *mi = instance;
struct context *c;
bool ret = true;
bool floated = false;
- if (m->pending)
- {
- return true;
- }
-
- if (!instance)
+ if (!mi)
{
#ifdef MULTI_DEBUG_EVENT_LOOP
printf("TCP/UDP -> TUN [%d]\n", BLEN(&m->top.c2.buf));
#endif
- multi_set_pending(m, multi_get_create_instance_udp(m, &floated, sock));
- }
- else
- {
- multi_set_pending(m, instance);
+ mi = multi_get_create_instance_udp(m, &floated, sock);
}
- if (!m->pending)
+ if (!mi)
{
return true;
}
- set_prefix(m->pending);
+ set_prefix(mi);
/* get instance context */
- c = &m->pending->context;
+ c = &mi->context;
if (!instance)
{
@@ -3594,11 +3581,11 @@
if (BLEN(&c->c2.buf) > 0)
{
- multi_process_incoming_link_data(m, floated, sock);
+ multi_process_incoming_link_data(m, mi, floated, sock);
}
/* postprocess and set wakeup */
- ret = multi_process_post(m, m->pending, mpp_flags);
+ ret = multi_process_post(m, mi, mpp_flags);
clear_prefix();
@@ -3625,11 +3612,6 @@
printf("TUN -> TCP/UDP [%d]\n", BLEN(&m->top.c2.buf));
#endif
- if (m->pending)
- {
- return true;
- }
-
if (dev_type == DEV_TYPE_TAP && m->top.options.vlan_tagging)
{
vid = vlan_decapsulate(&m->top, &m->top.c2.buf);
@@ -3657,18 +3639,18 @@
}
else
{
- multi_set_pending(
- m, multi_get_instance_by_virtual_addr(m, &dest, dev_type == DEV_TYPE_TUN));
+ struct multi_instance *mi =
+ multi_get_instance_by_virtual_addr(m, &dest, dev_type == DEV_TYPE_TUN);
- if (m->pending)
+ if (mi)
{
/* get instance context */
- c = &m->pending->context;
+ c = &mi->context;
- set_prefix(m->pending);
+ set_prefix(mi);
{
- if (multi_output_queue_ready(m, m->pending))
+ if (multi_output_queue_ready(m, mi))
{
/* transfer packet pointer from top-level context buffer to instance */
c->c2.buf = m->top.c2.buf;
@@ -3686,7 +3668,7 @@
process_incoming_tun(c, c->c2.link_sockets[0]);
/* postprocess and set wakeup */
- ret = multi_process_post(m, m->pending, mpp_flags);
+ ret = multi_process_post(m, mi, mpp_flags);
clear_prefix();
}
@@ -206,8 +206,11 @@
unsigned long cid_counter;
#endif
- struct multi_instance *pending;
struct multi_instance *earliest_wakeup;
+ /* While multi_io_dispatch() runs an action, points to its local where
+ * multi_process_post() with MPP_RECORD_TOUCH stores the instance it
+ * processed. An action post-processes at most one instance, which
+ * multi_io_action() then closes on signal or writes the output of. */
struct multi_instance **mpp_touched;
struct context_buffers *context_buffers;
time_t per_second_trigger;
@@ -638,11 +641,6 @@
*/
#define MULTI_CHECK_SIG(m) EVENT_LOOP_CHECK_SIGNAL(&(m)->top, multi_process_signal, (m))
-static inline void
-multi_set_pending(struct multi_context *m, struct multi_instance *mi)
-{
- m->pending = mi;
-}
/**
* Assigns a peer-id to a a client and adds the instance to the
* the instances array of the \c multi_context structure.
@@ -135,36 +135,6 @@
}
}
-/*
- * Return the io flags appropriate for
- * a point-to-multipoint tunnel.
- */
-static unsigned int
-p2mp_iow_flags(const struct multi_context *m, const struct link_socket *sock)
-{
- unsigned int flags = IOW_WAIT_SIGNAL;
-
- if (m->pending)
- {
- if (TUN_OUT(&m->pending->context))
- {
- flags |= IOW_TO_TUN;
- }
-
- /* If the to be processed socket happens to be the same one on the pending
- * UDP client instance, we set that socket ready for write */
- if (LINK_OUT(&m->pending->context) && m->pending->context.c2.link_sockets[0] == sock)
- {
- flags |= IOW_TO_LINK;
- }
- }
- else
- {
- flags |= IOW_READ;
- }
- return flags;
-}
-
int
multi_io_wait(struct multi_context *m)
{
@@ -177,7 +147,7 @@
if (proto_is_dgram(sock->info.proto))
{
- multi_io_process_flags(&m->top, m->multi_io->es, sock, p2mp_iow_flags(m, sock));
+ multi_io_process_flags(&m->top, m->multi_io->es, sock, IOW_READ | IOW_WAIT_SIGNAL);
}
else if (!tuntap_is_dco_win(m->top.c1.tuntap))
{
@@ -281,6 +251,7 @@
* perform server-mode postprocessing.
*
* @param m - The single \c multi_context structure.
+ * @param mi - The \c multi_instance with the packet to send.
* @param mpp_flags - Fast I/O optimization flags.
*
* @return
@@ -289,12 +260,10 @@
* - Falls, if the \c multi_instance was closed.
*/
static bool
-multi_io_write_tun(struct multi_context *m, const unsigned int mpp_flags)
+multi_io_write_tun(struct multi_context *m, struct multi_instance *mi, const unsigned int mpp_flags)
{
- struct multi_instance *mi = m->pending;
bool ret = true;
- ASSERT(mi);
#ifdef MULTI_DEBUG_EVENT_LOOP
printf("%s -> TUN len=%d\n", id(mi), mi->context.c2.to_tun.len);
#endif
@@ -310,12 +279,8 @@
* Drop a TUN/TAP outgoing packet..
*/
static void
-multi_io_drop_tun(struct multi_context *m, const unsigned int mpp_flags)
+multi_io_drop_tun(struct multi_context *m, struct multi_instance *mi, const unsigned int mpp_flags)
{
- struct multi_instance *mi = m->pending;
-
- ASSERT(mi);
-
set_prefix(mi);
msg(D_MULTI_ERRORS, "MULTI: Outgoing TUN queue full, dropped packet len=%d",
@@ -328,24 +293,22 @@
}
/*
- * Determine which instance has pending output
- * and prepare the output for sending in
- * the to_link buffer.
+ * Determine which instance has output for the
+ * link: mi itself, or else the next queued
+ * bcast/c2c packet, prepared in its to_link buffer.
*/
static struct multi_instance *
-multi_io_write_link_pre(struct multi_context *m)
+multi_io_write_link_pre(struct multi_context *m, struct multi_instance *mi)
{
- struct multi_instance *mi = NULL;
-
- if (m->pending)
+ if (mi && LINK_OUT(&mi->context))
{
- mi = m->pending;
+ return mi;
}
- else if (mbuf_defined(m->mbuf))
+ if (mbuf_defined(m->mbuf))
{
- mi = multi_get_queue(m->mbuf);
+ return multi_get_queue(m->mbuf);
}
- return mi;
+ return NULL;
}
static bool
@@ -381,11 +344,12 @@
}
static bool
-multi_io_write_link(struct multi_context *m, bool defer, const unsigned int mpp_flags)
+multi_io_write_link(struct multi_context *m, struct multi_instance *mi, bool defer,
+ const unsigned int mpp_flags)
{
- struct multi_instance *mi = multi_io_write_link_pre(m);
bool ret = true;
+ mi = multi_io_write_link_pre(m, mi);
if (mi)
{
if ((defer && !proto_is_dgram(mi->context.c2.link_sockets[0]->info.proto))
@@ -406,20 +370,12 @@
mbuf_free_buf(mb);
buf_reset(buf);
ret = multi_process_post(m, mi, mpp_flags);
- if (!ret)
- {
- mi = NULL;
- }
clear_prefix();
}
}
else
{
ret = multi_io_send_link(m, mi, mpp_flags);
- if (!ret)
- {
- mi = NULL;
- }
}
}
return ret;
@@ -477,11 +433,13 @@
break;
case TA_TUN_WRITE:
- multi_io_write_tun(m, mpp_flags);
+ ASSERT(mi);
+ multi_io_write_tun(m, mi, mpp_flags);
break;
case TA_TUN_WRITE_TIMEOUT:
- multi_io_drop_tun(m, mpp_flags);
+ ASSERT(mi);
+ multi_io_drop_tun(m, mi, mpp_flags);
break;
case TA_SOCKET_WRITE_READY:
@@ -490,11 +448,11 @@
break;
case TA_SOCKET_WRITE:
- multi_io_write_link(m, false, mpp_flags);
+ multi_io_write_link(m, mi, false, mpp_flags);
break;
case TA_SOCKET_WRITE_DEFERRED:
- multi_io_write_link(m, true, mpp_flags);
+ multi_io_write_link(m, mi, true, mpp_flags);
break;
case TA_INITIAL:
@@ -629,10 +587,6 @@
multi_io_action(m, mi, NULL, TA_INITIAL, false);
}
}
- else if (e->rwflags & EVENT_WRITE)
- {
- multi_io_action(m, NULL, NULL, TA_SOCKET_WRITE, false);
- }
else if (e->rwflags & EVENT_READ)
{
multi_io_action(m, NULL, ev_arg->u.sock, TA_SOCKET_READ, false);
@@ -653,11 +607,7 @@
/* incoming data on TUN? */
if (e->arg == MULTI_IO_TUN)
{
- if (e->rwflags & EVENT_WRITE)
- {
- multi_io_action(m, NULL, NULL, TA_TUN_WRITE, false);
- }
- else if (e->rwflags & EVENT_READ)
+ if (e->rwflags & EVENT_READ)
{
multi_io_action(m, NULL, NULL, TA_TUN_READ, false);
}
@@ -749,17 +699,17 @@
mi = NULL;
}
multi_close_instance_on_signal(m, touched);
+ touched = NULL;
}
-
/*
- * If dispatch produced any pending output
- * for a particular instance, point to
- * that instance.
+ * touched is the only instance this action
+ * post-processed: having closed it above if
+ * it was signalled, write its output if any.
*/
- if (m->pending)
+ if (touched && ANY_OUT(&touched->context))
{
- mi = m->pending;
+ mi = touched;
}
/*