From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: passt.top; dmarc=none (p=none dis=none) header.from=gibson.dropbear.id.au Authentication-Results: passt.top; dkim=pass (2048-bit key; secure) header.d=gibson.dropbear.id.au header.i=@gibson.dropbear.id.au header.a=rsa-sha256 header.s=202512 header.b=qKx9T14z; dkim-atps=neutral Received: from mail.ozlabs.org (mail.ozlabs.org [IPv6:2404:9400:2221:ea00::3]) by passt.top (Postfix) with ESMTPS id 3DAD75A004E for ; Mon, 12 Jan 2026 05:16:34 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gibson.dropbear.id.au; s=202512; t=1768191392; bh=FCg13vPx+biNayQ4hgox1ZYVNOoMhWAFzVToM9P2858=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=qKx9T14zj2jgLCqEt8We3p5LIbc3uK9iQBJZ8ufxb5CDSPdmYThgw0cDd4r7XW2gK iLQvDy4hqjdbsftUUkXCHakpeV1Urv/eTuVg3OpXzQi+UDMD5V2TZbe7rTUF5WxF9I BG4PHPhTBU8U6j+Kkf+r4zUGTdg+8FpO6CWm+TGggusqlycVpn6USBd7gBTtFR43+A J91019EBUGprh5roFp1rVaMuAiKduwTuaxdhqV1vtH3OrbOnVdeRC6LPyY22zYxaCx lxnrviCCQLTwJKcTKlaHRYVGjC9ad8G+HkImhg6oaTkzqWmnTSyZWOyvAwIfXKJS+W pyfxjITEjsnRA== Received: by gandalf.ozlabs.org (Postfix, from userid 1007) id 4dqJwc0Hxqz4wCY; Mon, 12 Jan 2026 15:16:32 +1100 (AEDT) Date: Mon, 12 Jan 2026 15:16:28 +1100 From: David Gibson To: Laurent Vivier Subject: Re: [PATCH v3 6/6] flow: Introduce flow_epoll_set() to centralize epoll operations Message-ID: References: <20260109165438.2492285-1-lvivier@redhat.com> <20260109165438.2492285-7-lvivier@redhat.com> MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha512; protocol="application/pgp-signature"; boundary="3887PGb86gn5STXZ" Content-Disposition: inline In-Reply-To: <20260109165438.2492285-7-lvivier@redhat.com> Message-ID-Hash: O3WS2VXTSMDARE6SD2U7LQB52I6OC4QO X-Message-ID-Hash: O3WS2VXTSMDARE6SD2U7LQB52I6OC4QO X-MailFrom: dgibson@gandalf.ozlabs.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: passt-dev@passt.top X-Mailman-Version: 3.3.8 Precedence: list List-Id: Development discussion and patches for passt Archived-At: Archived-At: List-Archive: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: --3887PGb86gn5STXZ Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable On Fri, Jan 09, 2026 at 05:54:38PM +0100, Laurent Vivier wrote: > 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. >=20 > Introduce flow_epoll_set() in flow.c to handle epoll operations for > all flow types in a unified way. >=20 > This will be needed to migrate queue pair from an epollfd to another. >=20 > Signed-off-by: Laurent Vivier Reviewed-by: David Gibson > --- > flow.c | 37 ++++++++++++++++++++++++ > flow.h | 2 ++ > icmp.c | 10 ++----- > tcp.c | 48 ++++++++++++++++++------------ > tcp_splice.c | 82 ++++++++++++++++++++++++---------------------------- > udp_flow.c | 11 ++----- > 6 files changed, 111 insertions(+), 79 deletions(-) >=20 > diff --git a/flow.c b/flow.c > index 4f53486586cd..cefe6c8b5b24 100644 > --- a/flow.c > +++ b/flow.c > @@ -20,6 +20,7 @@ > #include "flow.h" > #include "flow_table.h" > #include "repair.h" > +#include "epoll_ctl.h" > =20 > const char *flow_state_str[] =3D { > [FLOW_STATE_FREE] =3D "FREE", > @@ -53,6 +54,16 @@ const uint8_t flow_proto[] =3D { > static_assert(ARRAY_SIZE(flow_proto) =3D=3D FLOW_NUM_TYPES, > "flow_proto[] doesn't match enum flow_type"); > =20 > +static const enum epoll_type flow_epoll[] =3D { > + [FLOW_TCP] =3D EPOLL_TYPE_TCP, > + [FLOW_TCP_SPLICE] =3D EPOLL_TYPE_TCP_SPLICE, > + [FLOW_PING4] =3D EPOLL_TYPE_PING, > + [FLOW_PING6] =3D EPOLL_TYPE_PING, > + [FLOW_UDP] =3D EPOLL_TYPE_UDP, > +}; > +static_assert(ARRAY_SIZE(flow_epoll) =3D=3D FLOW_NUM_TYPES, > + "flow_epoll[] doesn't match enum flow_type"); > + > #define foreach_established_tcp_flow(flow) \ > flow_foreach_of_type((flow), FLOW_TCP) \ > if (!tcp_flow_is_established(&(flow)->tcp)) \ > @@ -390,6 +401,32 @@ void flow_epollid_clear(struct flow_common *f) > f->epollid =3D EPOLLFD_ID_INVALID; > } > =20 > +/** > + * flow_epoll_set() - Add or modify epoll registration for a flow socket > + * @f: Flow to register socket for > + * @command: epoll_ctl() command: EPOLL_CTL_ADD or EPOLL_CTL_MOD > + * @events: epoll events to watch for > + * @fd: File descriptor to register > + * @sidei: Side index of the flow > + * > + * Return: 0 on success, -1 on error (from epoll_ctl()) > + */ > +int flow_epoll_set(const struct flow_common *f, int command, uint32_t ev= ents, > + int fd, unsigned int sidei) > +{ > + struct epoll_event ev; > + union epoll_ref ref; > + > + ref.fd =3D fd; > + ref.type =3D flow_epoll[f->type]; > + ref.flowside =3D flow_sidx(f, sidei); > + > + ev.events =3D events; > + ev.data.u64 =3D ref.u64; > + > + return epoll_ctl(flow_epollfd(f), command, fd, &ev); > +} > + > /** > * flow_epollid_register() - Initialize the epoll id -> fd mapping > * @epollid: epoll id to associate to > diff --git a/flow.h b/flow.h > index b43b0b1dd7f2..1b78d596fb17 100644 > --- a/flow.h > +++ b/flow.h > @@ -265,6 +265,8 @@ bool flow_in_epoll(const struct flow_common *f); > int flow_epollfd(const struct flow_common *f); > void flow_epollid_set(struct flow_common *f, int epollid); > void flow_epollid_clear(struct flow_common *f); > +int flow_epoll_set(const struct flow_common *f, int command, uint32_t ev= ents, > + int fd, unsigned int sidei); > void flow_epollid_register(int epollid, int epollfd); > void flow_defer_handler(const struct ctx *c, const struct timespec *now); > int flow_migrate_source_early(struct ctx *c, const struct migrate_stage = *stage, > diff --git a/icmp.c b/icmp.c > index 9564c4963f7b..eb7f11be5dad 100644 > --- a/icmp.c > +++ b/icmp.c > @@ -177,7 +177,6 @@ static struct icmp_ping_flow *icmp_ping_new(const str= uct ctx *c, > union flow *flow =3D flow_alloc(); > struct icmp_ping_flow *pingf; > const struct flowside *tgt; > - union epoll_ref ref; > =20 > if (!flow) > return NULL; > @@ -211,13 +210,10 @@ static struct icmp_ping_flow *icmp_ping_new(const s= truct ctx *c, > goto cancel; > =20 > flow_epollid_set(&pingf->f, EPOLLFD_ID_DEFAULT); > - > - ref.type =3D EPOLL_TYPE_PING; > - ref.flowside =3D FLOW_SIDX(flow, TGTSIDE); > - ref.fd =3D pingf->sock; > - > - if (epoll_add(flow_epollfd(&pingf->f), EPOLLIN, ref) < 0) { > + if (flow_epoll_set(&pingf->f, EPOLL_CTL_ADD, EPOLLIN, pingf->sock, > + TGTSIDE) < 0) { > close(pingf->sock); > + flow_epollid_clear(&pingf->f); > goto cancel; > } > =20 > diff --git a/tcp.c b/tcp.c > index 4b746b4ca16c..e7f284be6a52 100644 > --- a/tcp.c > +++ b/tcp.c > @@ -523,34 +523,44 @@ static uint32_t tcp_conn_epoll_events(uint8_t event= s, uint8_t conn_flags) > =20 > /** > * tcp_epoll_ctl() - Add/modify/delete epoll state from connection events > - * @c: Execution context > * @conn: Connection pointer > * > * Return: 0 on success, negative error code on failure (not on deletion) > */ > -static int tcp_epoll_ctl(const struct ctx *c, struct tcp_tap_conn *conn) > +static int tcp_epoll_ctl(struct tcp_tap_conn *conn) > { > - int m =3D flow_in_epoll(&conn->f) ? EPOLL_CTL_MOD : EPOLL_CTL_ADD; > - union epoll_ref ref =3D { .type =3D EPOLL_TYPE_TCP, .fd =3D conn->sock, > - .flowside =3D FLOW_SIDX(conn, !TAPSIDE(conn)), }; > - struct epoll_event ev =3D { .data.u64 =3D ref.u64 }; > - int epollfd =3D flow_in_epoll(&conn->f) ? flow_epollfd(&conn->f) > - : c->epollfd; > + uint32_t events; > + int m; > =20 > if (conn->events =3D=3D CLOSED) { > - if (flow_in_epoll(&conn->f)) > + if (flow_in_epoll(&conn->f)) { > + int epollfd =3D flow_epollfd(&conn->f); > + > epoll_del(epollfd, conn->sock); > - if (conn->timer !=3D -1) > - epoll_del(epollfd, conn->timer); > + if (conn->timer !=3D -1) > + epoll_del(epollfd, conn->timer); > + } > + > return 0; > } > =20 > - ev.events =3D tcp_conn_epoll_events(conn->events, conn->flags); > + events =3D tcp_conn_epoll_events(conn->events, conn->flags); > =20 > - if (epoll_ctl(epollfd, m, conn->sock, &ev)) > - return -errno; > + if (flow_in_epoll(&conn->f)) { > + m =3D EPOLL_CTL_MOD; > + } else { > + flow_epollid_set(&conn->f, EPOLLFD_ID_DEFAULT); > + m =3D EPOLL_CTL_ADD; > + } > =20 > - flow_epollid_set(&conn->f, EPOLLFD_ID_DEFAULT); > + if (flow_epoll_set(&conn->f, m, events, conn->sock, > + !TAPSIDE(conn)) < 0) { > + int ret =3D -errno; > + > + if (m =3D=3D EPOLL_CTL_ADD) > + flow_epollid_clear(&conn->f); > + return ret; > + } > =20 > return 0; > } > @@ -671,7 +681,7 @@ void conn_flag_do(const struct ctx *c, struct tcp_tap= _conn *conn, > } > =20 > if (flag =3D=3D STALLED || flag =3D=3D ~STALLED) > - tcp_epoll_ctl(c, conn); > + tcp_epoll_ctl(conn); > =20 > if (flag =3D=3D ACK_FROM_TAP_DUE || flag =3D=3D ACK_TO_TAP_DUE || > (flag =3D=3D ~ACK_FROM_TAP_DUE && (conn->flags & ACK_TO_TAP_DUE)) || > @@ -728,7 +738,7 @@ void conn_event_do(const struct ctx *c, struct tcp_ta= p_conn *conn, > } else { > if (event =3D=3D CLOSED) > flow_hash_remove(c, TAP_SIDX(conn)); > - tcp_epoll_ctl(c, conn); > + tcp_epoll_ctl(conn); > } > =20 > if (CONN_HAS(conn, SOCK_FIN_SENT | TAP_FIN_ACKED)) > @@ -1744,7 +1754,7 @@ static void tcp_conn_from_tap(const struct ctx *c, = sa_family_t af, > conn_event(c, conn, TAP_SYN_ACK_SENT); > } > =20 > - tcp_epoll_ctl(c, conn); > + tcp_epoll_ctl(conn); > =20 > if (c->mode =3D=3D MODE_VU) { /* To rebind to same oport after migratio= n */ > socklen_t sl =3D sizeof(sa); > @@ -3986,7 +3996,7 @@ int tcp_flow_migrate_target_ext(struct ctx *c, stru= ct tcp_tap_conn *conn, int fd > tcp_send_flag(c, conn, ACK); > tcp_data_from_sock(c, conn); > =20 > - if ((rc =3D tcp_epoll_ctl(c, conn))) { > + if ((rc =3D tcp_epoll_ctl(conn))) { > flow_dbg(conn, > "Failed to subscribe to epoll for migrated socket: %s", > strerror_(-rc)); > diff --git a/tcp_splice.c b/tcp_splice.c > index bf4ff466de07..a7c04ca8652a 100644 > --- a/tcp_splice.c > +++ b/tcp_splice.c > @@ -135,37 +135,31 @@ static uint32_t tcp_splice_conn_epoll_events(uint16= _t events, unsigned sidei) > =20 > /** > * tcp_splice_epoll_ctl() - Add/modify/delete epoll state from connectio= n events > - * @c: Execution context > * @conn: Connection pointer > * > * Return: 0 on success, negative error code on failure (not on deletion) > */ > -static int tcp_splice_epoll_ctl(const struct ctx *c, > - struct tcp_splice_conn *conn) > +static int tcp_splice_epoll_ctl(struct tcp_splice_conn *conn) > { > - int epollfd =3D flow_in_epoll(&conn->f) ? flow_epollfd(&conn->f) > - : c->epollfd; > - int m =3D flow_in_epoll(&conn->f) ? EPOLL_CTL_MOD : EPOLL_CTL_ADD; > - const union epoll_ref ref[SIDES] =3D { > - { .type =3D EPOLL_TYPE_TCP_SPLICE, .fd =3D conn->s[0], > - .flowside =3D FLOW_SIDX(conn, 0) }, > - { .type =3D EPOLL_TYPE_TCP_SPLICE, .fd =3D conn->s[1], > - .flowside =3D FLOW_SIDX(conn, 1) } > - }; > - struct epoll_event ev[SIDES] =3D { { .data.u64 =3D ref[0].u64 }, > - { .data.u64 =3D ref[1].u64 } }; > - > - ev[0].events =3D tcp_splice_conn_epoll_events(conn->events, 0); > - ev[1].events =3D tcp_splice_conn_epoll_events(conn->events, 1); > - > - > - if (epoll_ctl(epollfd, m, conn->s[0], &ev[0]) || > - epoll_ctl(epollfd, m, conn->s[1], &ev[1])) { > + uint32_t events[2]; > + int m; > + > + if (flow_in_epoll(&conn->f)) { > + m =3D EPOLL_CTL_MOD; > + } else { > + flow_epollid_set(&conn->f, EPOLLFD_ID_DEFAULT); > + m =3D EPOLL_CTL_ADD; > + } > + > + events[0] =3D tcp_splice_conn_epoll_events(conn->events, 0); > + events[1] =3D tcp_splice_conn_epoll_events(conn->events, 1); > + > + if (flow_epoll_set(&conn->f, m, events[0], conn->s[0], 0) || > + flow_epoll_set(&conn->f, m, events[1], conn->s[1], 1)) { > int ret =3D -errno; > flow_perror(conn, "ERROR on epoll_ctl()"); > return ret; > } > - flow_epollid_set(&conn->f, EPOLLFD_ID_DEFAULT); > =20 > return 0; > } > @@ -205,7 +199,7 @@ static void conn_flag_do(struct tcp_splice_conn *conn, > } > } > =20 > -#define conn_flag(c, conn, flag) \ > +#define conn_flag(conn, flag) \ > do { \ > flow_trace(conn, "flag at %s:%i", __func__, __LINE__); \ > conn_flag_do(conn, flag); \ > @@ -213,12 +207,10 @@ static void conn_flag_do(struct tcp_splice_conn *co= nn, > =20 > /** > * conn_event_do() - Set and log connection events, update epoll state > - * @c: Execution context > * @conn: Connection pointer > * @event: Connection event > */ > -static void conn_event_do(const struct ctx *c, struct tcp_splice_conn *c= onn, > - unsigned long event) > +static void conn_event_do(struct tcp_splice_conn *conn, unsigned long ev= ent) > { > if (event & (event - 1)) { > int flag_index =3D fls(~event); > @@ -240,14 +232,14 @@ static void conn_event_do(const struct ctx *c, stru= ct tcp_splice_conn *conn, > flow_dbg(conn, "%s", tcp_splice_event_str[flag_index]); > } > =20 > - if (tcp_splice_epoll_ctl(c, conn)) > - conn_flag(c, conn, CLOSING); > + if (tcp_splice_epoll_ctl(conn)) > + conn_flag(conn, CLOSING); > } > =20 > -#define conn_event(c, conn, event) \ > +#define conn_event(conn, event) \ > do { \ > flow_trace(conn, "event at %s:%i",__func__, __LINE__); \ > - conn_event_do(c, conn, event); \ > + conn_event_do(conn, event); \ > } while (0) > =20 > =20 > @@ -315,7 +307,7 @@ static int tcp_splice_connect_finish(const struct ctx= *c, > if (pipe2(conn->pipe[sidei], O_NONBLOCK | O_CLOEXEC)) { > flow_perror(conn, "cannot create %d->%d pipe", > sidei, !sidei); > - conn_flag(c, conn, CLOSING); > + conn_flag(conn, CLOSING); > return -EIO; > } > =20 > @@ -329,7 +321,7 @@ static int tcp_splice_connect_finish(const struct ctx= *c, > } > =20 > if (!(conn->events & SPLICE_ESTABLISHED)) > - conn_event(c, conn, SPLICE_ESTABLISHED); > + conn_event(conn, SPLICE_ESTABLISHED); > =20 > return 0; > } > @@ -376,7 +368,7 @@ static int tcp_splice_connect(const struct ctx *c, st= ruct tcp_splice_conn *conn) > =20 > pif_sockaddr(c, &sa, tgtpif, &tgt->eaddr, tgt->eport); > =20 > - conn_event(c, conn, SPLICE_CONNECT); > + conn_event(conn, SPLICE_CONNECT); > =20 > if (connect(conn->s[1], &sa.sa, socklen_inany(&sa))) { > if (errno !=3D EINPROGRESS) { > @@ -385,7 +377,7 @@ static int tcp_splice_connect(const struct ctx *c, st= ruct tcp_splice_conn *conn) > return -errno; > } > } else { > - conn_event(c, conn, SPLICE_ESTABLISHED); > + conn_event(conn, SPLICE_ESTABLISHED); > return tcp_splice_connect_finish(c, conn); > } > =20 > @@ -445,7 +437,7 @@ void tcp_splice_conn_from_sock(const struct ctx *c, u= nion flow *flow, int s0) > flow_trace(conn, "failed to set TCP_QUICKACK on %i", s0); > =20 > if (tcp_splice_connect(c, conn)) > - conn_flag(c, conn, CLOSING); > + conn_flag(conn, CLOSING); > =20 > FLOW_ACTIVATE(conn); > } > @@ -494,14 +486,14 @@ void tcp_splice_sock_handler(struct ctx *c, union e= poll_ref ref, > =20 > if (events & EPOLLOUT) { > fromsidei =3D !evsidei; > - conn_event(c, conn, ~OUT_WAIT(evsidei)); > + conn_event(conn, ~OUT_WAIT(evsidei)); > } else { > fromsidei =3D evsidei; > } > =20 > if (events & EPOLLRDHUP) > /* For side 0 this is fake, but implied */ > - conn_event(c, conn, FIN_RCVD(evsidei)); > + conn_event(conn, FIN_RCVD(evsidei)); > =20 > swap: > eof =3D 0; > @@ -536,7 +528,7 @@ retry: > more =3D SPLICE_F_MORE; > =20 > if (conn->flags & lowat_set_flag) > - conn_flag(c, conn, lowat_act_flag); > + conn_flag(conn, lowat_act_flag); > } > =20 > do > @@ -568,8 +560,8 @@ retry: > "Setting SO_RCVLOWAT %i: %s", > lowat, strerror_(errno)); > } else { > - conn_flag(c, conn, lowat_set_flag); > - conn_flag(c, conn, lowat_act_flag); > + conn_flag(conn, lowat_set_flag); > + conn_flag(conn, lowat_act_flag); > } > } > =20 > @@ -583,7 +575,7 @@ retry: > if (conn->read[fromsidei] =3D=3D conn->written[fromsidei]) > break; > =20 > - conn_event(c, conn, OUT_WAIT(!fromsidei)); > + conn_event(conn, OUT_WAIT(!fromsidei)); > break; > } > =20 > @@ -605,7 +597,7 @@ retry: > if ((conn->events & FIN_RCVD(sidei)) && > !(conn->events & FIN_SENT(!sidei))) { > shutdown(conn->s[!sidei], SHUT_WR); > - conn_event(c, conn, FIN_SENT(!sidei)); > + conn_event(conn, FIN_SENT(!sidei)); > } > } > } > @@ -626,7 +618,7 @@ retry: > return; > =20 > close: > - conn_flag(c, conn, CLOSING); > + conn_flag(conn, CLOSING); > } > =20 > /** > @@ -762,10 +754,10 @@ void tcp_splice_timer(struct tcp_splice_conn *conn) > flow_trace(conn, "can't set SO_RCVLOWAT on %d", > conn->s[sidei]); > } > - conn_flag(c, conn, ~RCVLOWAT_SET(sidei)); > + conn_flag(conn, ~RCVLOWAT_SET(sidei)); > } > } > =20 > flow_foreach_sidei(sidei) > - conn_flag(c, conn, ~RCVLOWAT_ACT(sidei)); > + conn_flag(conn, ~RCVLOWAT_ACT(sidei)); > } > diff --git a/udp_flow.c b/udp_flow.c > index c4cf35c2c89d..80b15433f0ac 100644 > --- a/udp_flow.c > +++ b/udp_flow.c > @@ -74,7 +74,6 @@ static int udp_flow_sock(const struct ctx *c, > { > const struct flowside *side =3D &uflow->f.side[sidei]; > uint8_t pif =3D uflow->f.pif[sidei]; > - union epoll_ref ref; > int rc; > int s; > =20 > @@ -84,14 +83,10 @@ static int udp_flow_sock(const struct ctx *c, > return s; > } > =20 > - ref.type =3D EPOLL_TYPE_UDP; > - ref.flowside =3D FLOW_SIDX(uflow, sidei); > - ref.fd =3D s; > - > flow_epollid_set(&uflow->f, EPOLLFD_ID_DEFAULT); > - > - rc =3D epoll_add(flow_epollfd(&uflow->f), EPOLLIN, ref); > - if (rc < 0) { > + if (flow_epoll_set(&uflow->f, EPOLL_CTL_ADD, EPOLLIN, s, sidei) < 0) { > + rc =3D -errno; > + flow_epollid_clear(&uflow->f); > close(s); > return rc; > } > --=20 > 2.52.0 >=20 --=20 David Gibson (he or they) | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you, not the other way | around. http://www.ozlabs.org/~dgibson --3887PGb86gn5STXZ Content-Type: application/pgp-signature; name=signature.asc -----BEGIN PGP SIGNATURE----- iQIzBAEBCgAdFiEEO+dNsU4E3yXUXRK2zQJF27ox2GcFAmlkdZsACgkQzQJF27ox 2Ge5Nw/9EU1xCxHM7RPr5wFC+m2o4Yi2QxcZ2XZzbfPEmNAw5gNXTfjXafCHGFXS ty8vg36v3U0+/DGKgow5CzF1TT+IWw67w/Rf8j/phdcrx+UFvGenHr+Q4ZDBYoFq cjEiYlk8vcWkeb/Io9T/hwGiQeKd1V4WXhx4rYIxpCc3Ad7oKw/LIlkg79HjQ6u2 qURbE+JCaZbPh6gkAUQA4We6n/H+IFUa0A82/oJhZByoXbF70GBCWsP+dYwqO95o UtTXstwSbimno9U/X/iZ17LSbjcnThNwfUpx1HmKNuXcKEWN23mqpLb8Fxhirodt PMKa8xC0f8hIapOY+qAyt8jFSO9+p2s+2d3Yqb+lrOwStN4dYDVEOaMvdypcrZ5s ATjFsn6eRHabOf1UUnmSgKuaHikMGCEQlwEZHLU2teJxvOM1dMy3a2oP7zCZAKSU 5M7PmzuXdQgcaGbn39CdygfgWfB7uVe3RL+wBU0j6sLB5dWBWp7aDNhXS8ad1TDy /OpRymlb0nAco7w+r+dnp8+aJDe9Rn4yxnjQCZkCc7YrNSR8sTlbEVrSLCuaTDMJ 7nX0XqDoqbUWpLZEumb15XpW+98Yq9yZzETz+Hx1/YjBQLoUgI/rnwlhSA8qvOC5 NS7aTjvZj94AzXvyg2odhOk53p+b+O2zgYVxVmX2ysAO6c18Mxk= =G1h1 -----END PGP SIGNATURE----- --3887PGb86gn5STXZ--