Commit 1ab67b98 authored by Marc-André Lureau's avatar Marc-André Lureau Committed by Samuel Thibault
Browse files

slirp: replace global polling with per-instance & notifier



Remove hard-coded dependency on slirp in main-loop, and use a "poll"
notifier instead. The notifier is registered per slirp instance.

Signed-off-by: default avatarMarc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: default avatarSamuel Thibault <samuel.thibault@ens-lyon.org>
parent 625a526b
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -302,4 +302,19 @@ void qemu_fd_register(int fd);
QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque);
void qemu_bh_schedule_idle(QEMUBH *bh);

enum {
    MAIN_LOOP_POLL_FILL,
    MAIN_LOOP_POLL_ERR,
    MAIN_LOOP_POLL_OK,
};

typedef struct MainLoopPoll {
    int state;
    uint32_t timeout;
    GArray *pollfds;
} MainLoopPoll;

void main_loop_poll_add_notifier(Notifier *notify);
void main_loop_poll_remove_notifier(Notifier *notify);

#endif
+24 −0
Original line number Diff line number Diff line
@@ -86,6 +86,7 @@ typedef struct SlirpState {
    NetClientState nc;
    QTAILQ_ENTRY(SlirpState) entry;
    Slirp *slirp;
    Notifier poll_notifier;
    Notifier exit_notifier;
#ifndef _WIN32
    gchar *smb_dir;
@@ -144,6 +145,7 @@ static void net_slirp_cleanup(NetClientState *nc)
    SlirpState *s = DO_UPCAST(SlirpState, nc, nc);

    g_slist_free_full(s->fwd, slirp_free_fwd);
    main_loop_poll_remove_notifier(&s->poll_notifier);
    slirp_cleanup(s->slirp);
    if (s->exit_notifier.notify) {
        qemu_remove_exit_notifier(&s->exit_notifier);
@@ -209,6 +211,25 @@ static const SlirpCb slirp_cb = {
    .notify = qemu_notify_event,
};

static void net_slirp_poll_notify(Notifier *notifier, void *data)
{
    MainLoopPoll *poll = data;
    SlirpState *s = container_of(notifier, SlirpState, poll_notifier);

    switch (poll->state) {
    case MAIN_LOOP_POLL_FILL:
        slirp_pollfds_fill(s->slirp, poll->pollfds, &poll->timeout);
        break;
    case MAIN_LOOP_POLL_OK:
    case MAIN_LOOP_POLL_ERR:
        slirp_pollfds_poll(s->slirp, poll->pollfds,
                           poll->state == MAIN_LOOP_POLL_ERR);
        break;
    default:
        g_assert_not_reached();
    }
}

static int net_slirp_init(NetClientState *peer, const char *model,
                          const char *name, int restricted,
                          bool ipv4, const char *vnetwork, const char *vhost,
@@ -429,6 +450,9 @@ static int net_slirp_init(NetClientState *peer, const char *model,
                          &slirp_cb, s);
    QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry);

    s->poll_notifier.notify = net_slirp_poll_notify;
    main_loop_poll_add_notifier(&s->poll_notifier);

    for (config = slirp_configs; config; config = config->next) {
        if (config->flags & SLIRP_CFG_HOSTFWD) {
            if (slirp_hostfwd(s, config->str, errp) < 0) {
+2 −2
Original line number Diff line number Diff line
@@ -63,9 +63,9 @@ Slirp *slirp_init(int restricted, bool in_enabled, struct in_addr vnetwork,
                  void *opaque);
void slirp_cleanup(Slirp *slirp);

void slirp_pollfds_fill(GArray *pollfds, uint32_t *timeout);
void slirp_pollfds_fill(Slirp *slirp, GArray *pollfds, uint32_t *timeout);

void slirp_pollfds_poll(GArray *pollfds, int select_error);
void slirp_pollfds_poll(Slirp *slirp, GArray *pollfds, int select_error);

void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len);

+268 −287
Original line number Diff line number Diff line
@@ -368,9 +368,8 @@ void slirp_cleanup(Slirp *slirp)
#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)

static void slirp_update_timeout(uint32_t *timeout)
static void slirp_update_timeout(Slirp *slirp, uint32_t *timeout)
{
    Slirp *slirp;
    uint32_t t;

    if (*timeout <= TIMEOUT_FAST) {
@@ -382,7 +381,6 @@ static void slirp_update_timeout(uint32_t *timeout)
    /* If we have tcp timeout with slirp, then we will fill @timeout with
     * more precise value.
     */
    QTAILQ_FOREACH(slirp, &slirp_instances, entry) {
    if (slirp->time_fasttimo) {
        *timeout = TIMEOUT_FAST;
        return;
@@ -390,24 +388,17 @@ static void slirp_update_timeout(uint32_t *timeout)
    if (slirp->do_slowtimo) {
        t = MIN(TIMEOUT_SLOW, t);
    }
    }
    *timeout = t;
}

void slirp_pollfds_fill(GArray *pollfds, uint32_t *timeout)
void slirp_pollfds_fill(Slirp *slirp, GArray *pollfds, uint32_t *timeout)
{
    Slirp *slirp;
    struct socket *so, *so_next;

    if (QTAILQ_EMPTY(&slirp_instances)) {
        return;
    }

    /*
     * First, TCP sockets
     */

    QTAILQ_FOREACH(slirp, &slirp_instances, entry) {
    /*
     * *_slowtimo needs calling if there are IP fragments
     * in the fragment queue, or there are TCP connections active
@@ -415,8 +406,7 @@ void slirp_pollfds_fill(GArray *pollfds, uint32_t *timeout)
    slirp->do_slowtimo = ((slirp->tcb.so_next != &slirp->tcb) ||
                          (&slirp->ipq.ip_link != slirp->ipq.ip_link.next));

        for (so = slirp->tcb.so_next; so != &slirp->tcb;
                so = so_next) {
    for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so_next) {
        int events = 0;

        so_next = so->so_next;
@@ -495,8 +485,7 @@ void slirp_pollfds_fill(GArray *pollfds, uint32_t *timeout)
    /*
     * UDP sockets
     */
        for (so = slirp->udb.so_next; so != &slirp->udb;
                so = so_next) {
    for (so = slirp->udb.so_next; so != &slirp->udb; so = so_next) {
        so_next = so->so_next;

        so->pollfds_idx = -1;
@@ -536,8 +525,7 @@ void slirp_pollfds_fill(GArray *pollfds, uint32_t *timeout)
    /*
     * ICMP sockets
     */
        for (so = slirp->icmp.so_next; so != &slirp->icmp;
                so = so_next) {
    for (so = slirp->icmp.so_next; so != &slirp->icmp; so = so_next) {
        so_next = so->so_next;

        so->pollfds_idx = -1;
@@ -563,23 +551,17 @@ void slirp_pollfds_fill(GArray *pollfds, uint32_t *timeout)
            g_array_append_val(pollfds, pfd);
        }
    }
    }
    slirp_update_timeout(timeout);

    slirp_update_timeout(slirp, timeout);
}

void slirp_pollfds_poll(GArray *pollfds, int select_error)
void slirp_pollfds_poll(Slirp *slirp, GArray *pollfds, int select_error)
{
    Slirp *slirp = QTAILQ_FIRST(&slirp_instances);
    struct socket *so, *so_next;
    int ret;

    if (!slirp) {
        return;
    }

    curtime = slirp->cb->clock_get_ns() / SCALE_MS;

    QTAILQ_FOREACH(slirp, &slirp_instances, entry) {
    /*
     * See if anything has timed out
     */
@@ -746,7 +728,6 @@ void slirp_pollfds_poll(GArray *pollfds, int select_error)

    if_start(slirp);
}
}

static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
{
+0 −1
Original line number Diff line number Diff line
@@ -26,7 +26,6 @@ stub-obj-y += qtest.o
stub-obj-y += replay.o
stub-obj-y += runstate-check.o
stub-obj-y += set-fd-handler.o
stub-obj-y += slirp.o
stub-obj-y += sysbus.o
stub-obj-y += tpm.o
stub-obj-y += trace-control.o
Loading