From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from gandalf.ozlabs.org (gandalf.ozlabs.org [150.107.74.76]) by passt.top (Postfix) with ESMTPS id 49D0F5A0271 for ; Thu, 3 Aug 2023 04:27:05 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gibson.dropbear.id.au; s=201602; t=1691029621; bh=aLChq7pH9M4sb/yOl1IVLgII4dkTsGFeyW4+xHBqmtE=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=kj/0nUfHruzuYIhaNFY3uKy7GQoEXhneuW6Iip2yaAzRaDd13+72nmdBx8NA0OMOa +hi85N8oKApt5PRjKPaqIR8qpdN/JFmJY4TcuCHQIMduxlOmGvzP4M+CIqkLaKztVP 7o/OYa3nrjTv1R/qUBjFRcVJYSKlVZnhXjZxhs8Y= Received: by gandalf.ozlabs.org (Postfix, from userid 1007) id 4RGXmP4SsXz4wxR; Thu, 3 Aug 2023 12:27:01 +1000 (AEST) Date: Thu, 3 Aug 2023 12:11:13 +1000 From: David Gibson To: Stefano Brivio Subject: Re: [PATCH 02/17] netlink: Split nl_addr() into separate operation functions Message-ID: References: <20230724060936.952659-1-david@gibson.dropbear.id.au> <20230724060936.952659-3-david@gibson.dropbear.id.au> <20230803004750.4e2feb37@elisabeth> MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha256; protocol="application/pgp-signature"; boundary="o1KNtJ/U6Q2IVyss" Content-Disposition: inline In-Reply-To: <20230803004750.4e2feb37@elisabeth> Message-ID-Hash: H6GW36LZS7V7KGP6W2FHX5CEARVBCAPL X-Message-ID-Hash: H6GW36LZS7V7KGP6W2FHX5CEARVBCAPL 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: --o1KNtJ/U6Q2IVyss Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable On Thu, Aug 03, 2023 at 12:47:50AM +0200, Stefano Brivio wrote: > On Mon, 24 Jul 2023 16:09:21 +1000 > David Gibson wrote: >=20 > > nl_addr() can perform three quite different operations based on the 'op' > > parameter, each of which uses a different subset of the parameters. Sp= lit > > them up into a function for each operation. This does use more lines of > > code, but the overlap wasn't that great, and the separated logic is much > > easier to follow. > >=20 > > It's also clearer in the callers what we expect the netlink operations = to > > do, and what information it uses. > >=20 > > Signed-off-by: David Gibson > > --- > > conf.c | 12 ++- > > netlink.c | 232 ++++++++++++++++++++++++++++++++---------------------- > > netlink.h | 6 +- > > pasta.c | 17 ++-- > > 4 files changed, 159 insertions(+), 108 deletions(-) > >=20 > > diff --git a/conf.c b/conf.c > > index 2ff9e2a..2057028 100644 > > --- a/conf.c > > +++ b/conf.c > > @@ -650,10 +650,8 @@ static unsigned int conf_ip4(unsigned int ifi, > > if (IN4_IS_ADDR_UNSPECIFIED(&ip4->gw)) > > nl_route(NL_GET, ifi, 0, AF_INET, &ip4->gw); > > =20 > > - if (IN4_IS_ADDR_UNSPECIFIED(&ip4->addr)) { > > - nl_addr(NL_GET, ifi, 0, AF_INET, > > - &ip4->addr, &ip4->prefix_len, NULL); > > - } > > + if (IN4_IS_ADDR_UNSPECIFIED(&ip4->addr)) > > + nl_addr_get(ifi, AF_INET, &ip4->addr, &ip4->prefix_len, NULL); > > =20 > > if (!ip4->prefix_len) { > > in_addr_t addr =3D ntohl(ip4->addr.s_addr); > > @@ -703,9 +701,9 @@ static unsigned int conf_ip6(unsigned int ifi, > > if (IN6_IS_ADDR_UNSPECIFIED(&ip6->gw)) > > nl_route(NL_GET, ifi, 0, AF_INET6, &ip6->gw); > > =20 > > - nl_addr(NL_GET, ifi, 0, AF_INET6, > > - IN6_IS_ADDR_UNSPECIFIED(&ip6->addr) ? &ip6->addr : NULL, > > - &prefix_len, &ip6->addr_ll); > > + nl_addr_get(ifi, AF_INET6, > > + IN6_IS_ADDR_UNSPECIFIED(&ip6->addr) ? &ip6->addr : NULL, > > + &prefix_len, &ip6->addr_ll); > > =20 > > memcpy(&ip6->addr_seen, &ip6->addr, sizeof(ip6->addr)); > > memcpy(&ip6->addr_ll_seen, &ip6->addr_ll, sizeof(ip6->addr_ll)); > > diff --git a/netlink.c b/netlink.c > > index 4b1f75e..269d738 100644 > > --- a/netlink.c > > +++ b/netlink.c > > @@ -334,17 +334,76 @@ next: > > } > > =20 > > /** > > - * nl_addr() - Get/set/copy IP addresses for given interface and addre= ss family > > - * @op: Requested operation > > + * nl_addr_get() - Get IP address for given interface and address fami= ly > > * @ifi: Interface index in outer network namespace > > - * @ifi_ns: Interface index in target namespace for NL_SET, NL_DUP > > * @af: Address family > > - * @addr: Global address to fill on NL_GET, to set on NL_SET > > - * @prefix_len: Mask or prefix length, set or fetched (for IPv4) > > - * @addr_l: Link-scoped address to fill on NL_GET > > + * @addr: Global address to fill > > + * @prefix_len: Mask or prefix length, to fill (for IPv4) > > + * @addr_l: Link-scoped address to fill (for IPv6) > > + */ > > +void nl_addr_get(unsigned int ifi, sa_family_t af, void *addr, > > + int *prefix_len, void *addr_l) > > +{ > > + struct req_t { > > + struct nlmsghdr nlh; > > + struct ifaddrmsg ifa; > > + } req =3D { > > + .nlh.nlmsg_type =3D RTM_GETADDR, > > + .nlh.nlmsg_flags =3D NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP, > > + .nlh.nlmsg_len =3D sizeof(req), > > + .nlh.nlmsg_seq =3D nl_seq++, > > + > > + .ifa.ifa_family =3D af, > > + .ifa.ifa_index =3D ifi, > > + }; > > + struct nlmsghdr *nh; > > + char buf[NLBUFSIZ]; > > + ssize_t n; > > + > > + if ((n =3D nl_req(0, buf, &req, req.nlh.nlmsg_len)) < 0) > > + return; > > + > > + for (nh =3D (struct nlmsghdr *)buf; > > + NLMSG_OK(nh, n) && nh->nlmsg_type !=3D NLMSG_DONE; > > + nh =3D NLMSG_NEXT(nh, n)) { > > + struct ifaddrmsg *ifa =3D (struct ifaddrmsg *)NLMSG_DATA(nh); > > + struct rtattr *rta; > > + size_t na; > > + > > + if (nh->nlmsg_type !=3D RTM_NEWADDR) > > + continue; > > + > > + if (ifa->ifa_index !=3D ifi) > > + continue; > > + > > + for (rta =3D IFA_RTA(ifa), na =3D RTM_PAYLOAD(nh); RTA_OK(rta, na); > > + rta =3D RTA_NEXT(rta, na)) { > > + if (rta->rta_type !=3D IFA_ADDRESS) > > + continue; > > + > > + if (af =3D=3D AF_INET) { > > + memcpy(addr, RTA_DATA(rta), RTA_PAYLOAD(rta)); > > + *prefix_len =3D ifa->ifa_prefixlen; > > + } else if (af =3D=3D AF_INET6 && addr && > > + ifa->ifa_scope =3D=3D RT_SCOPE_UNIVERSE) { > > + memcpy(addr, RTA_DATA(rta), RTA_PAYLOAD(rta)); > > + } > > + > > + if (addr_l && > > + af =3D=3D AF_INET6 && ifa->ifa_scope =3D=3D RT_SCOPE_LINK) > > + memcpy(addr_l, RTA_DATA(rta), RTA_PAYLOAD(rta)); > > + } > > + } > > +} > > + > > +/** > > + * nl_add_set() - Set IP addresses for given interface and address fam= ily > > + * @ifi: Interface index > > + * @af: Address family > > + * @addr: Global address to set > > + * @prefix_len: Mask or prefix length to set > > */ > > -void nl_addr(enum nl_op op, unsigned int ifi, unsigned int ifi_ns, > > - sa_family_t af, void *addr, int *prefix_len, void *addr_l) > > +void nl_addr_set(unsigned int ifi, sa_family_t af, void *addr, int pre= fix_len) > > { > > struct req_t { > > struct nlmsghdr nlh; > > @@ -364,125 +423,112 @@ void nl_addr(enum nl_op op, unsigned int ifi, u= nsigned int ifi_ns, > > } a6; > > } set; > > } req =3D { > > - .nlh.nlmsg_type =3D op =3D=3D NL_SET ? RTM_NEWADDR : RTM_GETADDR, > > - .nlh.nlmsg_flags =3D NLM_F_REQUEST, > > + .nlh.nlmsg_type =3D RTM_NEWADDR, > > + .nlh.nlmsg_flags =3D NLM_F_REQUEST | NLM_F_ACK | > > + NLM_F_CREATE | NLM_F_EXCL, > > .nlh.nlmsg_len =3D NLMSG_LENGTH(sizeof(struct ifaddrmsg)), > > .nlh.nlmsg_seq =3D nl_seq++, > > =20 > > .ifa.ifa_family =3D af, > > - .ifa.ifa_index =3D op =3D=3D NL_SET ? ifi_ns : ifi, > > - .ifa.ifa_prefixlen =3D op =3D=3D NL_SET ? *prefix_len : 0, > > + .ifa.ifa_index =3D ifi, > > + .ifa.ifa_prefixlen =3D prefix_len, > > + .ifa.ifa_scope =3D RT_SCOPE_UNIVERSE, > > }; > > - ssize_t n, nlmsgs_size; > > - struct ifaddrmsg *ifa; > > - struct nlmsghdr *nh; > > - struct rtattr *rta; > > char buf[NLBUFSIZ]; > > - size_t na; > > =20 > > - if (op =3D=3D NL_SET) { > > - if (af =3D=3D AF_INET6) { > > - size_t rta_len =3D RTA_LENGTH(sizeof(req.set.a6.l)); > > + if (af =3D=3D AF_INET6) { > > + size_t rta_len =3D RTA_LENGTH(sizeof(req.set.a6.l)); > > =20 > > - /* By default, strictly speaking, it's duplicated */ > > - req.ifa.ifa_flags =3D IFA_F_NODAD; > > + /* By default, strictly speaking, it's duplicated */ > > + req.ifa.ifa_flags =3D IFA_F_NODAD; > > =20 > > - req.nlh.nlmsg_len =3D offsetof(struct req_t, set.a6) > > - + sizeof(req.set.a6); > > + req.nlh.nlmsg_len =3D offsetof(struct req_t, set.a6) > > + + sizeof(req.set.a6); > > =20 > > - memcpy(&req.set.a6.l, addr, sizeof(req.set.a6.l)); > > - req.set.a6.rta_l.rta_len =3D rta_len; > > - req.set.a4.rta_l.rta_type =3D IFA_LOCAL; > > - memcpy(&req.set.a6.a, addr, sizeof(req.set.a6.a)); > > - req.set.a6.rta_a.rta_len =3D rta_len; > > - req.set.a6.rta_a.rta_type =3D IFA_ADDRESS; > > - } else { > > - size_t rta_len =3D RTA_LENGTH(sizeof(req.set.a4.l)); > > - > > - req.nlh.nlmsg_len =3D offsetof(struct req_t, set.a4) > > - + sizeof(req.set.a4); > > + memcpy(&req.set.a6.l, addr, sizeof(req.set.a6.l)); > > + req.set.a6.rta_l.rta_len =3D rta_len; > > + req.set.a4.rta_l.rta_type =3D IFA_LOCAL; > > + memcpy(&req.set.a6.a, addr, sizeof(req.set.a6.a)); > > + req.set.a6.rta_a.rta_len =3D rta_len; > > + req.set.a6.rta_a.rta_type =3D IFA_ADDRESS; > > + } else { > > + size_t rta_len =3D RTA_LENGTH(sizeof(req.set.a4.l)); > > =20 > > - req.set.a4.l =3D req.set.a4.a =3D *(uint32_t *)addr; > > - req.set.a4.rta_l.rta_len =3D rta_len; > > - req.set.a4.rta_l.rta_type =3D IFA_LOCAL; > > - req.set.a4.rta_a.rta_len =3D rta_len; > > - req.set.a4.rta_a.rta_type =3D IFA_ADDRESS; > > - } > > + req.nlh.nlmsg_len =3D offsetof(struct req_t, set.a4) > > + + sizeof(req.set.a4); > > =20 > > - req.ifa.ifa_scope =3D RT_SCOPE_UNIVERSE; > > - req.nlh.nlmsg_flags |=3D NLM_F_CREATE | NLM_F_ACK | NLM_F_EXCL; > > - } else { > > - req.nlh.nlmsg_flags |=3D NLM_F_DUMP; > > + req.set.a4.l =3D req.set.a4.a =3D *(uint32_t *)addr; > > + req.set.a4.rta_l.rta_len =3D rta_len; > > + req.set.a4.rta_l.rta_type =3D IFA_LOCAL; > > + req.set.a4.rta_a.rta_len =3D rta_len; > > + req.set.a4.rta_a.rta_type =3D IFA_ADDRESS; > > } > > =20 > > - if ((n =3D nl_req(op =3D=3D NL_SET, buf, &req, req.nlh.nlmsg_len)) < = 0) > > - return; > > + nl_req(1, buf, &req, req.nlh.nlmsg_len); > > +} > > =20 > > - if (op =3D=3D NL_SET) > > +/** > > + * nl_addr_dup() - Copy IP addresses for given interface and address f= amily > > + * @ifi: Interface index in outer network namespace > > + * @ifi_ns: Interface index in target namespace > > + * @af: Address family > > + */ > > +void nl_addr_dup(unsigned int ifi, unsigned int ifi_ns, sa_family_t af) > > +{ > > + struct req_t { > > + struct nlmsghdr nlh; > > + struct ifaddrmsg ifa; > > + } req =3D { > > + .nlh.nlmsg_type =3D RTM_GETADDR, > > + .nlh.nlmsg_flags =3D NLM_F_REQUEST | NLM_F_DUMP, > > + .nlh.nlmsg_len =3D sizeof(req), > > + .nlh.nlmsg_seq =3D nl_seq++, > > + > > + .ifa.ifa_family =3D af, > > + .ifa.ifa_index =3D ifi, > > + .ifa.ifa_prefixlen =3D 0, > > + }; > > + char buf[NLBUFSIZ], resp[NLBUFSIZ]; > > + ssize_t n, nlmsgs_size; > > + struct nlmsghdr *nh; > > + > > + if ((n =3D nl_req(0, buf, &req, sizeof(req))) < 0) > > return; > > =20 > > - nh =3D (struct nlmsghdr *)buf; > > nlmsgs_size =3D n; > > =20 > > - for ( ; NLMSG_OK(nh, n); nh =3D NLMSG_NEXT(nh, n)) { > > + for (nh =3D (struct nlmsghdr *)buf; > > + NLMSG_OK(nh, n) && nh->nlmsg_type !=3D NLMSG_DONE; > > + nh =3D NLMSG_NEXT(nh, n)) { > > + struct ifaddrmsg *ifa; > > + struct rtattr *rta; > > + size_t na; > > + > > if (nh->nlmsg_type !=3D RTM_NEWADDR) > > - goto next; > > + continue; > > =20 > > - if (op =3D=3D NL_DUP) { > > - nh->nlmsg_seq =3D nl_seq++; > > - nh->nlmsg_pid =3D 0; > > - nh->nlmsg_flags &=3D ~NLM_F_DUMP_FILTERED; > > - nh->nlmsg_flags |=3D NLM_F_REQUEST | NLM_F_ACK | > > - NLM_F_CREATE; > > - } > > + nh->nlmsg_seq =3D nl_seq++; > > + nh->nlmsg_pid =3D 0; > > + nh->nlmsg_flags &=3D ~NLM_F_DUMP_FILTERED; > > + nh->nlmsg_flags |=3D NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE; > > =20 > > ifa =3D (struct ifaddrmsg *)NLMSG_DATA(nh); > > =20 > > - if (op =3D=3D NL_DUP && (ifa->ifa_scope =3D=3D RT_SCOPE_LINK || > > - ifa->ifa_index !=3D ifi)) { > > + if (ifa->ifa_scope =3D=3D RT_SCOPE_LINK || ifa->ifa_index !=3D ifi) { > > ifa->ifa_family =3D AF_UNSPEC; > > - goto next; > > + continue; > > } > > =20 > > - if (ifa->ifa_index !=3D ifi) > > - goto next; > > - > > - if (op =3D=3D NL_DUP) > > - ifa->ifa_index =3D ifi_ns; > > + ifa->ifa_index =3D ifi_ns; > > =20 > > for (rta =3D IFA_RTA(ifa), na =3D RTM_PAYLOAD(nh); RTA_OK(rta, na); > > rta =3D RTA_NEXT(rta, na)) { > > - if (op =3D=3D NL_DUP && rta->rta_type =3D=3D IFA_LABEL) > > + if (rta->rta_type =3D=3D IFA_LABEL) > > rta->rta_type =3D IFA_UNSPEC; > > - > > - if (op =3D=3D NL_DUP || rta->rta_type !=3D IFA_ADDRESS) > > - continue; > > - > > - if (af =3D=3D AF_INET && addr && !*(uint32_t *)addr) { > > - memcpy(addr, RTA_DATA(rta), RTA_PAYLOAD(rta)); > > - *prefix_len =3D ifa->ifa_prefixlen; > > - } else if (af =3D=3D AF_INET6 && addr && > > - ifa->ifa_scope =3D=3D RT_SCOPE_UNIVERSE && > > - IN6_IS_ADDR_UNSPECIFIED(addr)) { > > - memcpy(addr, RTA_DATA(rta), RTA_PAYLOAD(rta)); > > - } > > - > > - if (addr_l && > > - af =3D=3D AF_INET6 && ifa->ifa_scope =3D=3D RT_SCOPE_LINK && > > - IN6_IS_ADDR_UNSPECIFIED(addr_l)) > > - memcpy(addr_l, RTA_DATA(rta), RTA_PAYLOAD(rta)); > > } > > -next: > > - if (nh->nlmsg_type =3D=3D NLMSG_DONE) > > - break; > > } > > =20 > > - if (op =3D=3D NL_DUP) { > > - char resp[NLBUFSIZ]; > > - > > - nh =3D (struct nlmsghdr *)buf; > > - nl_req(1, resp, nh, nlmsgs_size); > > - } > > + nl_req(1, resp, buf, nlmsgs_size); > > } > > =20 > > /** > > diff --git a/netlink.h b/netlink.h > > index 980ac44..5ac972d 100644 > > --- a/netlink.h > > +++ b/netlink.h > > @@ -16,8 +16,10 @@ void nl_sock_init(const struct ctx *c, bool ns); > > unsigned int nl_get_ext_if(sa_family_t af); > > void nl_route(enum nl_op op, unsigned int ifi, unsigned int ifi_ns, > > sa_family_t af, void *gw); > > -void nl_addr(enum nl_op op, unsigned int ifi, unsigned int ifi_ns, > > - sa_family_t af, void *addr, int *prefix_len, void *addr_l); > > +void nl_addr_get(unsigned int ifi, sa_family_t af, void *addr, > > + int *prefix_len, void *addr_l); > > +void nl_addr_set(unsigned int ifi, sa_family_t af, void *addr, int pre= fix_len); > > +void nl_addr_dup(unsigned int ifi, unsigned int ifi_ns, sa_family_t af= ); > > void nl_link_get_mac(int ns, unsigned int ifi, void *mac); > > void nl_link_set_mac(int ns, unsigned int ifi, void *mac); > > void nl_link_up(int ns, unsigned int ifi, int mtu); > > diff --git a/pasta.c b/pasta.c > > index 3b5537d..1a8f09c 100644 > > --- a/pasta.c > > +++ b/pasta.c > > @@ -282,21 +282,26 @@ void pasta_ns_conf(struct ctx *c) > > =20 > > if (c->pasta_conf_ns) { > > enum nl_op op_routes =3D c->no_copy_routes ? NL_SET : NL_DUP; > > - enum nl_op op_addrs =3D c->no_copy_addrs ? NL_SET : NL_DUP; > > =20 > > nl_link_up(1, c->pasta_ifi, c->mtu); > > =20 > > if (c->ifi4) { > > - nl_addr(op_addrs, c->ifi4, c->pasta_ifi, AF_INET, > > - &c->ip4.addr, &c->ip4.prefix_len, NULL); > > + if (c->no_copy_addrs) > > + nl_addr_set(c->pasta_ifi, AF_INET,=20 > > + &c->ip4.addr, c->ip4.prefix_len); > > + else > > + nl_addr_dup(c->ifi4, c->pasta_ifi, AF_INET); > > + > > nl_route(op_routes, c->ifi4, c->pasta_ifi, AF_INET, > > &c->ip4.gw); > > } > > =20 > > if (c->ifi6) { > > - int prefix_len =3D 64; > > - nl_addr(op_addrs, c->ifi6, c->pasta_ifi, AF_INET6, > > - &c->ip6.addr, &prefix_len, NULL); > > + if (c->no_copy_addrs) > > + nl_addr_set(c->pasta_ifi, AF_INET6, &c->ip6.addr, 64); > > + else > > + nl_addr_dup(c->ifi4, c->pasta_ifi, AF_INET6); >=20 > I guess this should be c->ifi6 (also in 17/17). Oops, yes. Fixed. --=20 David Gibson | 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 --o1KNtJ/U6Q2IVyss Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- iQIzBAEBCAAdFiEEO+dNsU4E3yXUXRK2zQJF27ox2GcFAmTLDLoACgkQzQJF27ox 2GeXWg/9FnYhRp62EXLjuMdeTrPnjiLUI++2wiUsvXH8nxqqQ6WBY8+/dDi+z6oM Fw/CVIzZsibvgl4gQ07X3JIUsxvDsNWkaypb0rpzIaaGZ4y9HI8RwRAr88cP9g0W R2sjaaHxlr9M6wKfxeQT9Uof3JXoJIs2XiDk6BEUdb1k3t5lsaEvmbhB2bEQhm9Z 9rFtVqIBgCHT2jyLK753eUNOVQYL2lAA++GpZUCwNaM4O007MFyjWCjzk+j5kgBM ZzMz+iqtvOmuh3yNXd2zJfxYCcPX1MeB/P2OpZzJBeIcz0t8/wpDATCbiX9zTfty 2F0AY38GQyeHUgtRxsTIbT6pDa5GD4+LoMeyDgbmQwgaxi7nKRyW//lqaKo6oix8 PbB//9BmtvW+2Khkr/jJOaYYFAdPnmlK2aGdd6A3R0kAmkbEix1oVz5xmpQwvKN6 8v5M2/+JI9frNMyo4A2azq6ijw7NZia06pMKodDhCk15cXqJeCwRj5qfr+sE1L/6 SByYapJ8z6Is0SawVZXdGc6RhJXSmNnwiPBlIOwRPzmyTwij4WHDAKoVIFAMDvby j+eleCIPueaPYOC26qwI/pRsD8ybWb6jY8HbnxRYNXxPoJXSe2PESVhJTJZ/9tvp GcNOPAz4drbc2AcrsbFHEcpjHm/h8kP9qNiKNBjZhS28y7TgFt4= =o1mq -----END PGP SIGNATURE----- --o1KNtJ/U6Q2IVyss--