From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (unknown [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 43AF34602E; Thu, 16 Jan 2025 23:20:39 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 3B3BA40EDD; Thu, 16 Jan 2025 23:20:21 +0100 (CET) Received: from mail-il1-f182.google.com (mail-il1-f182.google.com [209.85.166.182]) by mails.dpdk.org (Postfix) with ESMTP id 0F71840696 for ; Thu, 16 Jan 2025 23:20:20 +0100 (CET) Received: by mail-il1-f182.google.com with SMTP id e9e14a558f8ab-3ce873818a3so12905485ab.1 for ; Thu, 16 Jan 2025 14:20:19 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=6wind.com; s=google; t=1737066019; x=1737670819; darn=dpdk.org; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=t12tQQUOeXoX/Kgj6iNdJ4Me4c0L9iYlVGzlcyqPf7w=; b=DaqXZHitzXbw1G9A4Oiho1vcUPvtQaGX01Lfi3bq7xSlV3/wGH0DBo6cyxNRttxOwp 9Ll3S0NxJNzZfFgozz6FNQISq6uPveVuiL2MTuYVjFKlJmH1NNyIeril0imnVkY/JkD6 jeBwd1zN+ZhOM/oWhddZFaahfaNWn2LbBOlQCWHvUpqpv3WSRVO0OFiYVpZrNYEFYQK8 UMeV4JUaofcoeiYLPPs3O1wvfnmQJZLdsUMv/eCkY++uqlaNnO0dHDb9ZOLdkxywso0s xJQTq5CSfFwKrEkrQkBh3nkDf3WLM1BlHfZGfGCF23VsOOkecdAncvinS0W2oUTdUL9C KxOg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1737066019; x=1737670819; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=t12tQQUOeXoX/Kgj6iNdJ4Me4c0L9iYlVGzlcyqPf7w=; b=axF8PBvKBspv9SHY5rcNLTB4tcvGWD1hEQ4N9hiXxC7vLwlX4omp2JXmhCI7Zi8EkV zLnhncC58CVE7I9f+G05SFd0DpuJwYhwruaImn18dUOt2i89plXXbiigBFwPOavaqM+/ J/KgC5CvCQzX9upDs4bLMtv55YsFk59ibGsCWId6YhGKzhIHYB3LRC3wThh79t8DvGdM L/erqJrV5ktGXst8osusnZZyt16aY8nlzaMbiD7/YNSEhmaHc2T9hLvhD79DuQ/nWsDI DgnZps0LFkE+fpxRrrL3ZOyLGw+ns1T/qfRMOPOgZ1tfEAl8T+WGmQejvkNh7EDlUD1r XsbA== X-Gm-Message-State: AOJu0Yz5qYMxz4RL+f5AplkIM5kghaVwF/WdbJX3B/mtb+ZrWazhEG3P d9AnHb8D1iIgmlkpDrVLMAtpt3Jz2U2rY4srb+TtKgL6486O8Bv+7F2vmPI4CfcqxOXhHNdy17H Av3uncLyDumhsmoMDD52TjLjYR5HkveqdN5DeaQ== X-Gm-Gg: ASbGncsgjjCXaCcoL6BA/aKLvoWoV4L3Fm/0yyhCu2Ou8htbW4njDd71dPiRhRo0x4J wsKCgLNLSnrix0kT1/DGrR/vx8RxR1RSJT8hWeAunZ6ST4p6IRa/TXbxdNPpgwIavsGHihA== X-Google-Smtp-Source: AGHT+IFYR+DqhJ0YDH2O/7UK4ndPUg2cJq/dV489updFuMm9DSSN9sSr+vXtlYux+C+gKAzMxMXROi0xlGt6he9oLos= X-Received: by 2002:a05:6e02:1c07:b0:3ce:84cd:a885 with SMTP id e9e14a558f8ab-3cf74490966mr2739975ab.16.1737066019242; Thu, 16 Jan 2025 14:20:19 -0800 (PST) MIME-Version: 1.0 References: <20250116195640.68885-1-ariel.otilibili@6wind.com> <20250116195640.68885-3-ariel.otilibili@6wind.com> <20250116134746.2c0b1a7e@hermes.local> In-Reply-To: <20250116134746.2c0b1a7e@hermes.local> From: Ariel Otilibili Date: Thu, 16 Jan 2025 23:20:06 +0100 X-Gm-Features: AbW1kvYO6thNmRrc8oVD8V3lrh5ouuqvVwpTQ3uu_EvszCPef0Z-CXjf-0aBA8U Message-ID: Subject: Re: [PATCH 2/2] net/af_xdp: Refactor af_xdp_tx_zc() To: stephen@networkplumber.org Cc: dev@dpdk.org, stable@dpdk.org, Thomas Monjalon , David Marchand , Ciara Loftus , Maryam Tahhan Content-Type: multipart/alternative; boundary="0000000000000762eb062bda3386" X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org --0000000000000762eb062bda3386 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Hi Stephen, On Thu, Jan 16, 2025 at 10:47=E2=80=AFPM Stephen Hemminger < stephen@networkplumber.org> wrote: > On Thu, 16 Jan 2025 20:56:39 +0100 > Ariel Otilibili wrote: > > > Both branches of the loop share the same logic. Now each one is a > > goto dispatcher; either to out (end of function), or to > > stats (continuation of the loop). > > > > Bugzilla ID: 1440 > > Depends-on: patch-1 ("net/af_xdp: fix use after free in af_xdp_tx_zc()"= ) > > Signed-off-by: Ariel Otilibili > > --- > > drivers/net/af_xdp/rte_eth_af_xdp.c | 57 ++++++++++++++--------------- > > 1 file changed, 27 insertions(+), 30 deletions(-) > > > > diff --git a/drivers/net/af_xdp/rte_eth_af_xdp.c > b/drivers/net/af_xdp/rte_eth_af_xdp.c > > index 4326a29f7042..8b42704b6d9f 100644 > > --- a/drivers/net/af_xdp/rte_eth_af_xdp.c > > +++ b/drivers/net/af_xdp/rte_eth_af_xdp.c > > @@ -551,6 +551,7 @@ af_xdp_tx_zc(void *queue, struct rte_mbuf **bufs, > uint16_t nb_pkts) > > uint64_t addr, offset; > > struct xsk_ring_cons *cq =3D &txq->pair->cq; > > uint32_t free_thresh =3D cq->size >> 1; > > + struct rte_mbuf *local_mbuf =3D NULL; > > > > if (xsk_cons_nb_avail(cq, free_thresh) >=3D free_thresh) > > pull_umem_cq(umem, XSK_RING_CONS__DEFAULT_NUM_DESCS, cq); > > @@ -565,21 +566,10 @@ af_xdp_tx_zc(void *queue, struct rte_mbuf **bufs, > uint16_t nb_pkts) > > &idx_tx)) > > goto out; > > } > > - desc =3D xsk_ring_prod__tx_desc(&txq->tx, idx_tx)= ; > > - desc->len =3D mbuf->pkt_len; > > - addr =3D (uint64_t)mbuf - (uint64_t)umem->buffer = - > > - umem->mb_pool->header_size; > > - offset =3D rte_pktmbuf_mtod(mbuf, uint64_t) - > > - (uint64_t)mbuf + > > - umem->mb_pool->header_size; > > - offset =3D offset << XSK_UNALIGNED_BUF_OFFSET_SHI= FT; > > - desc->addr =3D addr | offset; > > - tx_bytes +=3D mbuf->pkt_len; > > - count++; > > + > > + goto stats; > > } else { > > - struct rte_mbuf *local_mbuf =3D > > - rte_pktmbuf_alloc(umem->mb_pool); > > - void *pkt; > > + local_mbuf =3D rte_pktmbuf_alloc(umem->mb_pool); > > > > if (local_mbuf =3D=3D NULL) > > goto out; > > @@ -589,23 +579,30 @@ af_xdp_tx_zc(void *queue, struct rte_mbuf **bufs, > uint16_t nb_pkts) > > goto out; > > } > > > > - desc =3D xsk_ring_prod__tx_desc(&txq->tx, idx_tx)= ; > > - desc->len =3D mbuf->pkt_len; > > - > > - addr =3D (uint64_t)local_mbuf - > (uint64_t)umem->buffer - > > - umem->mb_pool->header_size; > > - offset =3D rte_pktmbuf_mtod(local_mbuf, uint64_t)= - > > - (uint64_t)local_mbuf + > > - umem->mb_pool->header_size; > > - pkt =3D xsk_umem__get_data(umem->buffer, addr + > offset); > > - offset =3D offset << XSK_UNALIGNED_BUF_OFFSET_SHI= FT; > > - desc->addr =3D addr | offset; > > - rte_memcpy(pkt, rte_pktmbuf_mtod(mbuf, void *), > > - desc->len); > > - tx_bytes +=3D mbuf->pkt_len; > > - rte_pktmbuf_free(mbuf); > > - count++; > > + goto stats; > > } > > +stats: > > + struct rte_mbuf *tmp; > > + void *pkt; > > + tmp =3D mbuf->pool =3D=3D umem->mb_pool ? mbuf : local_mbuf; > > + > > + desc =3D xsk_ring_prod__tx_desc(&txq->tx, idx_tx); > > + desc->len =3D mbuf->pkt_len; > > + > > + addr =3D (uint64_t)tmp - (uint64_t)umem->buffer - > umem->mb_pool->header_size; > > + offset =3D rte_pktmbuf_mtod(tmp, uint64_t) - (uint64_t)tmp + > umem->mb_pool->header_size; > > + offset =3D offset << XSK_UNALIGNED_BUF_OFFSET_SHIFT; > > + desc->addr =3D addr | offset; > > + > > + if (mbuf->pool =3D=3D umem->mb_pool) { > > + tx_bytes +=3D mbuf->pkt_len; > > + } else { > > + pkt =3D xsk_umem__get_data(umem->buffer, addr + offset); > > + rte_memcpy(pkt, rte_pktmbuf_mtod(mbuf, void *), desc->len= ); > > + tx_bytes +=3D mbuf->pkt_len; > > + rte_pktmbuf_free(mbuf); > > + } > > + count++; > > } > > > > out: > > Indentation here is wrong, and looks suspect. > Either stats tag should be outside of loop > Or stats is inside loop, and both of those goto's are unnecessary > Thanks for the feedback; I am pushing a new series with an extra tab. So it be obvious that stats belongs to the the loop. --0000000000000762eb062bda3386 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: base64 PGRpdiBkaXI9Imx0ciI+PGRpdj5IaSBTdGVwaGVuLDxicj48L2Rpdj48YnI+PGRpdiBjbGFzcz0i Z21haWxfcXVvdGUgZ21haWxfcXVvdGVfY29udGFpbmVyIj48ZGl2IGRpcj0ibHRyIiBjbGFzcz0i Z21haWxfYXR0ciI+T24gVGh1LCBKYW4gMTYsIDIwMjUgYXQgMTA6NDfigK9QTSBTdGVwaGVuIEhl bW1pbmdlciAmbHQ7PGEgaHJlZj0ibWFpbHRvOnN0ZXBoZW5AbmV0d29ya3BsdW1iZXIub3JnIj5z dGVwaGVuQG5ldHdvcmtwbHVtYmVyLm9yZzwvYT4mZ3Q7IHdyb3RlOjxicj48L2Rpdj48YmxvY2tx dW90ZSBjbGFzcz0iZ21haWxfcXVvdGUiIHN0eWxlPSJtYXJnaW46MHB4IDBweCAwcHggMC44ZXg7 Ym9yZGVyLWxlZnQ6MXB4IHNvbGlkIHJnYigyMDQsMjA0LDIwNCk7cGFkZGluZy1sZWZ0OjFleCI+ T24gVGh1LCAxNiBKYW4gMjAyNSAyMDo1NjozOSArMDEwMDxicj4NCkFyaWVsIE90aWxpYmlsaSAm bHQ7PGEgaHJlZj0ibWFpbHRvOmFyaWVsLm90aWxpYmlsaUA2d2luZC5jb20iIHRhcmdldD0iX2Js YW5rIj5hcmllbC5vdGlsaWJpbGlANndpbmQuY29tPC9hPiZndDsgd3JvdGU6PGJyPg0KPGJyPg0K Jmd0OyBCb3RoIGJyYW5jaGVzIG9mIHRoZSBsb29wIHNoYXJlIHRoZSBzYW1lIGxvZ2ljLiBOb3cg ZWFjaCBvbmUgaXMgYTxicj4NCiZndDsgZ290byBkaXNwYXRjaGVyOyBlaXRoZXIgdG8gb3V0IChl bmQgb2YgZnVuY3Rpb24pLCBvciB0bzxicj4NCiZndDsgc3RhdHMgKGNvbnRpbnVhdGlvbiBvZiB0 aGUgbG9vcCkuPGJyPg0KJmd0OyA8YnI+DQomZ3Q7IEJ1Z3ppbGxhIElEOiAxNDQwPGJyPg0KJmd0 OyBEZXBlbmRzLW9uOiBwYXRjaC0xICgmcXVvdDtuZXQvYWZfeGRwOiBmaXggdXNlIGFmdGVyIGZy ZWUgaW4gYWZfeGRwX3R4X3pjKCkmcXVvdDspPGJyPg0KJmd0OyBTaWduZWQtb2ZmLWJ5OiBBcmll bCBPdGlsaWJpbGkgJmx0OzxhIGhyZWY9Im1haWx0bzphcmllbC5vdGlsaWJpbGlANndpbmQuY29t IiB0YXJnZXQ9Il9ibGFuayI+YXJpZWwub3RpbGliaWxpQDZ3aW5kLmNvbTwvYT4mZ3Q7PGJyPg0K Jmd0OyAtLS08YnI+DQomZ3Q7wqAgZHJpdmVycy9uZXQvYWZfeGRwL3J0ZV9ldGhfYWZfeGRwLmMg fCA1NyArKysrKysrKysrKysrKy0tLS0tLS0tLS0tLS0tLTxicj4NCiZndDvCoCAxIGZpbGUgY2hh bmdlZCwgMjcgaW5zZXJ0aW9ucygrKSwgMzAgZGVsZXRpb25zKC0pPGJyPg0KJmd0OyA8YnI+DQom Z3Q7IGRpZmYgLS1naXQgYS9kcml2ZXJzL25ldC9hZl94ZHAvcnRlX2V0aF9hZl94ZHAuYyBiL2Ry aXZlcnMvbmV0L2FmX3hkcC9ydGVfZXRoX2FmX3hkcC5jPGJyPg0KJmd0OyBpbmRleCA0MzI2YTI5 ZjcwNDIuLjhiNDI3MDRiNmQ5ZiAxMDA2NDQ8YnI+DQomZ3Q7IC0tLSBhL2RyaXZlcnMvbmV0L2Fm X3hkcC9ydGVfZXRoX2FmX3hkcC5jPGJyPg0KJmd0OyArKysgYi9kcml2ZXJzL25ldC9hZl94ZHAv cnRlX2V0aF9hZl94ZHAuYzxicj4NCiZndDsgQEAgLTU1MSw2ICs1NTEsNyBAQCBhZl94ZHBfdHhf emModm9pZCAqcXVldWUsIHN0cnVjdCBydGVfbWJ1ZiAqKmJ1ZnMsIHVpbnQxNl90IG5iX3BrdHMp PGJyPg0KJmd0O8KgIMKgIMKgIMKgdWludDY0X3QgYWRkciwgb2Zmc2V0Ozxicj4NCiZndDvCoCDC oCDCoCDCoHN0cnVjdCB4c2tfcmluZ19jb25zICpjcSA9ICZhbXA7dHhxLSZndDtwYWlyLSZndDtj cTs8YnI+DQomZ3Q7wqAgwqAgwqAgwqB1aW50MzJfdCBmcmVlX3RocmVzaCA9IGNxLSZndDtzaXpl ICZndDsmZ3Q7IDE7PGJyPg0KJmd0OyArwqAgwqAgwqBzdHJ1Y3QgcnRlX21idWYgKmxvY2FsX21i dWYgPSBOVUxMOzxicj4NCiZndDvCoCA8YnI+DQomZ3Q7wqAgwqAgwqAgwqBpZiAoeHNrX2NvbnNf bmJfYXZhaWwoY3EsIGZyZWVfdGhyZXNoKSAmZ3Q7PSBmcmVlX3RocmVzaCk8YnI+DQomZ3Q7wqAg wqAgwqAgwqAgwqAgwqAgwqAgwqBwdWxsX3VtZW1fY3EodW1lbSwgWFNLX1JJTkdfQ09OU19fREVG QVVMVF9OVU1fREVTQ1MsIGNxKTs8YnI+DQomZ3Q7IEBAIC01NjUsMjEgKzU2NiwxMCBAQCBhZl94 ZHBfdHhfemModm9pZCAqcXVldWUsIHN0cnVjdCBydGVfbWJ1ZiAqKmJ1ZnMsIHVpbnQxNl90IG5i X3BrdHMpPGJyPg0KJmd0O8KgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgJmFtcDtpZHhf dHgpKTxicj4NCiZndDvCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoGdvdG8gb3V0Ozxicj4NCiZndDvCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoH08YnI+DQomZ3Q7IC3CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oGRlc2MgPSB4c2tfcmluZ19wcm9kX190eF9kZXNjKCZhbXA7dHhxLSZndDt0eCwgaWR4X3R4KTs8 YnI+DQomZ3Q7IC3CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoGRlc2MtJmd0O2xlbiA9 IG1idWYtJmd0O3BrdF9sZW47PGJyPg0KJmd0OyAtwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAgwqBhZGRyID0gKHVpbnQ2NF90KW1idWYgLSAodWludDY0X3QpdW1lbS0mZ3Q7YnVmZmVyIC08 YnI+DQomZ3Q7IC3CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoHVtZW0tJmd0O21iX3Bvb2wtJmd0O2hlYWRlcl9zaXplOzxicj4NCiZndDsgLcKg IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgb2Zmc2V0ID0gcnRlX3BrdG1idWZfbXRvZCht YnVmLCB1aW50NjRfdCkgLTxicj4NCiZndDsgLcKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgKHVpbnQ2NF90KW1idWYgKzxicj4NCiZndDsgLcKg IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgdW1l bS0mZ3Q7bWJfcG9vbC0mZ3Q7aGVhZGVyX3NpemU7PGJyPg0KJmd0OyAtwqAgwqAgwqAgwqAgwqAg wqAgwqAgwqAgwqAgwqAgwqBvZmZzZXQgPSBvZmZzZXQgJmx0OyZsdDsgWFNLX1VOQUxJR05FRF9C VUZfT0ZGU0VUX1NISUZUOzxicj4NCiZndDsgLcKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgZGVzYy0mZ3Q7YWRkciA9IGFkZHIgfCBvZmZzZXQ7PGJyPg0KJmd0OyAtwqAgwqAgwqAgwqAg wqAgwqAgwqAgwqAgwqAgwqAgwqB0eF9ieXRlcyArPSBtYnVmLSZndDtwa3RfbGVuOzxicj4NCiZn dDsgLcKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgY291bnQrKzs8YnI+DQomZ3Q7ICs8 YnI+DQomZ3Q7ICvCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoGdvdG8gc3RhdHM7PGJy Pg0KJmd0O8KgIMKgIMKgIMKgIMKgIMKgIMKgIMKgfSBlbHNlIHs8YnI+DQomZ3Q7IC3CoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoHN0cnVjdCBydGVfbWJ1ZiAqbG9jYWxfbWJ1ZiA9PGJy Pg0KJmd0OyAtwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAgwqAgwqBydGVfcGt0bWJ1Zl9hbGxvYyh1bWVtLSZndDttYl9wb29sKTs8YnI+DQomZ3Q7IC3C oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoHZvaWQgKnBrdDs8YnI+DQomZ3Q7ICvCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoGxvY2FsX21idWYgPSBydGVfcGt0bWJ1Zl9hbGxv Yyh1bWVtLSZndDttYl9wb29sKTs8YnI+DQomZ3Q7wqAgPGJyPg0KJmd0O8KgIMKgIMKgIMKgIMKg IMKgIMKgIMKgIMKgIMKgIMKgIMKgaWYgKGxvY2FsX21idWYgPT0gTlVMTCk8YnI+DQomZ3Q7wqAg wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBnb3RvIG91dDs8YnI+ DQomZ3Q7IEBAIC01ODksMjMgKzU3OSwzMCBAQCBhZl94ZHBfdHhfemModm9pZCAqcXVldWUsIHN0 cnVjdCBydGVfbWJ1ZiAqKmJ1ZnMsIHVpbnQxNl90IG5iX3BrdHMpPGJyPg0KJmd0O8KgIMKgIMKg IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgZ290byBvdXQ7PGJyPg0KJmd0 O8KgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgfTxicj4NCiZndDvCoCA8YnI+DQom Z3Q7IC3CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoGRlc2MgPSB4c2tfcmluZ19wcm9k X190eF9kZXNjKCZhbXA7dHhxLSZndDt0eCwgaWR4X3R4KTs8YnI+DQomZ3Q7IC3CoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoGRlc2MtJmd0O2xlbiA9IG1idWYtJmd0O3BrdF9sZW47PGJy Pg0KJmd0OyAtPGJyPg0KJmd0OyAtwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBhZGRy ID0gKHVpbnQ2NF90KWxvY2FsX21idWYgLSAodWludDY0X3QpdW1lbS0mZ3Q7YnVmZmVyIC08YnI+ DQomZ3Q7IC3CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoHVtZW0tJmd0O21iX3Bvb2wtJmd0O2hlYWRlcl9zaXplOzxicj4NCiZndDsgLcKgIMKg IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgb2Zmc2V0ID0gcnRlX3BrdG1idWZfbXRvZChsb2Nh bF9tYnVmLCB1aW50NjRfdCkgLTxicj4NCiZndDsgLcKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgKHVpbnQ2NF90KWxvY2FsX21idWYgKzxicj4N CiZndDsgLcKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgIMKgdW1lbS0mZ3Q7bWJfcG9vbC0mZ3Q7aGVhZGVyX3NpemU7PGJyPg0KJmd0OyAtwqAgwqAg wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBwa3QgPSB4c2tfdW1lbV9fZ2V0X2RhdGEodW1lbS0m Z3Q7YnVmZmVyLCBhZGRyICsgb2Zmc2V0KTs8YnI+DQomZ3Q7IC3CoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoG9mZnNldCA9IG9mZnNldCAmbHQ7Jmx0OyBYU0tfVU5BTElHTkVEX0JVRl9P RkZTRVRfU0hJRlQ7PGJyPg0KJmd0OyAtwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBk ZXNjLSZndDthZGRyID0gYWRkciB8IG9mZnNldDs8YnI+DQomZ3Q7IC3CoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoHJ0ZV9tZW1jcHkocGt0LCBydGVfcGt0bWJ1Zl9tdG9kKG1idWYsIHZv aWQgKiksPGJyPg0KJmd0OyAtwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAgwqAgwqAgwqAgwqAgwqBkZXNjLSZndDtsZW4pOzxicj4NCiZndDsgLcKgIMKgIMKgIMKgIMKg IMKgIMKgIMKgIMKgIMKgIMKgdHhfYnl0ZXMgKz0gbWJ1Zi0mZ3Q7cGt0X2xlbjs8YnI+DQomZ3Q7 IC3CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoHJ0ZV9wa3RtYnVmX2ZyZWUobWJ1Zik7 PGJyPg0KJmd0OyAtwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBjb3VudCsrOzxicj4N CiZndDsgK8KgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgZ290byBzdGF0czs8YnI+DQom Z3Q7wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqB9PGJyPg0KJmd0OyArc3RhdHM6PGJyPg0KJmd0OyAr wqAgwqAgwqBzdHJ1Y3QgcnRlX21idWYgKnRtcDs8YnI+DQomZ3Q7ICvCoCDCoCDCoHZvaWQgKnBr dDs8YnI+DQomZ3Q7ICvCoCDCoCDCoHRtcCA9IG1idWYtJmd0O3Bvb2wgPT0gdW1lbS0mZ3Q7bWJf cG9vbCA/IG1idWYgOiBsb2NhbF9tYnVmOzxicj4NCiZndDsgKzxicj4NCiZndDsgK8KgIMKgIMKg ZGVzYyA9IHhza19yaW5nX3Byb2RfX3R4X2Rlc2MoJmFtcDt0eHEtJmd0O3R4LCBpZHhfdHgpOzxi cj4NCiZndDsgK8KgIMKgIMKgZGVzYy0mZ3Q7bGVuID0gbWJ1Zi0mZ3Q7cGt0X2xlbjs8YnI+DQom Z3Q7ICs8YnI+DQomZ3Q7ICvCoCDCoCDCoGFkZHIgPSAodWludDY0X3QpdG1wIC0gKHVpbnQ2NF90 KXVtZW0tJmd0O2J1ZmZlciAtIHVtZW0tJmd0O21iX3Bvb2wtJmd0O2hlYWRlcl9zaXplOzxicj4N CiZndDsgK8KgIMKgIMKgb2Zmc2V0ID0gcnRlX3BrdG1idWZfbXRvZCh0bXAsIHVpbnQ2NF90KSAt ICh1aW50NjRfdCl0bXAgKyB1bWVtLSZndDttYl9wb29sLSZndDtoZWFkZXJfc2l6ZTs8YnI+DQom Z3Q7ICvCoCDCoCDCoG9mZnNldCA9IG9mZnNldCAmbHQ7Jmx0OyBYU0tfVU5BTElHTkVEX0JVRl9P RkZTRVRfU0hJRlQ7PGJyPg0KJmd0OyArwqAgwqAgwqBkZXNjLSZndDthZGRyID0gYWRkciB8IG9m ZnNldDs8YnI+DQomZ3Q7ICs8YnI+DQomZ3Q7ICvCoCDCoCDCoGlmIChtYnVmLSZndDtwb29sID09 IHVtZW0tJmd0O21iX3Bvb2wpIHs8YnI+DQomZ3Q7ICvCoCDCoCDCoCDCoCDCoCDCoCDCoHR4X2J5 dGVzICs9IG1idWYtJmd0O3BrdF9sZW47PGJyPg0KJmd0OyArwqAgwqAgwqB9IGVsc2Ugezxicj4N CiZndDsgK8KgIMKgIMKgIMKgIMKgIMKgIMKgcGt0ID0geHNrX3VtZW1fX2dldF9kYXRhKHVtZW0t Jmd0O2J1ZmZlciwgYWRkciArIG9mZnNldCk7PGJyPg0KJmd0OyArwqAgwqAgwqAgwqAgwqAgwqAg wqBydGVfbWVtY3B5KHBrdCwgcnRlX3BrdG1idWZfbXRvZChtYnVmLCB2b2lkICopLCBkZXNjLSZn dDtsZW4pOzxicj4NCiZndDsgK8KgIMKgIMKgIMKgIMKgIMKgIMKgdHhfYnl0ZXMgKz0gbWJ1Zi0m Z3Q7cGt0X2xlbjs8YnI+DQomZ3Q7ICvCoCDCoCDCoCDCoCDCoCDCoCDCoHJ0ZV9wa3RtYnVmX2Zy ZWUobWJ1Zik7PGJyPg0KJmd0OyArwqAgwqAgwqB9PGJyPg0KJmd0OyArwqAgwqAgwqBjb3VudCsr Ozxicj4NCiZndDvCoCDCoCDCoCDCoH08YnI+DQomZ3Q7wqAgPGJyPg0KJmd0O8KgIG91dDo8YnI+ DQo8YnI+DQpJbmRlbnRhdGlvbiBoZXJlIGlzIHdyb25nLCBhbmQgbG9va3Mgc3VzcGVjdC48YnI+ DQpFaXRoZXIgc3RhdHMgdGFnIHNob3VsZCBiZSBvdXRzaWRlIG9mIGxvb3A8YnI+DQpPciBzdGF0 cyBpcyBpbnNpZGUgbG9vcCwgYW5kIGJvdGggb2YgdGhvc2UgZ290byYjMzk7cyBhcmUgdW5uZWNl c3Nhcnk8YnI+PC9ibG9ja3F1b3RlPjxkaXY+VGhhbmtzIGZvciB0aGUgZmVlZGJhY2s7IEkgYW0g cHVzaGluZyBhIG5ldyBzZXJpZXMgd2l0aCBhbiBleHRyYSB0YWIuPC9kaXY+PGRpdj5TbyBpdCBi ZSBvYnZpb3VzIHRoYXQgc3RhdHMgYmVsb25ncyB0byB0aGUgdGhlIGxvb3AuIDxicj48L2Rpdj48 L2Rpdj48L2Rpdj4NCg== --0000000000000762eb062bda3386--