367 Commits

Author SHA1 Message Date
65fa036ec7 api: add heap alloc to vpp stats
The Python VPP Stats module also used the VPP heap.
Fix so it now explicitly allocates a heap.

Fixes: f68fccfe7e188fec2c9f91da38ca9acf6f67d811
Type: fix
Signed-off-by: Ole Troan <ot@cisco.com>
Change-Id: I0bd4ae64d6c89cdf634d8d9a91c23ab38017c5cc
Signed-off-by: Ole Troan <ot@cisco.com>
2020-10-07 12:46:08 +02:00
4537c30925 vppinfra: don't call dlmalloc API directly from the code
- it is confusing from end consumer perspective that some thing
   is somewhere called heap and somewhere mspace

 - this is base for additional work where heap pointer is not the same
   thing like mspace

Type: improvement
Change-Id: I644d5a0de17690d65d164d8cec3c5654571629ef
Signed-off-by: Damjan Marion <damarion@cisco.com>
2020-09-28 20:34:07 +02:00
f68fccfe7e api: remove clib_mem_init from vppapiclient contructor
Having the constructor in the vppapiclient library led to
conflicts with applications wanting to allocate their own heap.
Note: Change of behaviour, applications that do not use a CLIB
heap must now call vac_mem_init() before using any functions from
vppapiclient.

Type: fix
Signed-off-by: Ole Troan <ot@cisco.com>
Change-Id: Ib155a54579ea5a0dbc26cb4b6daca1274e1dfdfa
2020-09-28 16:17:25 +00:00
765008670b stats: Fix stat_segment to set timeout directly
Type: fix

Signed-off-by: Rajesh Goel <rajegoel@cisco.com>
Change-Id: Ib37802f4270fe894a31e871c7fbb12b5a1cdf058
2020-09-09 06:47:15 +00:00
9a412bcec4 stats: Move misplaced comment block
Type: fix
Fixes: fdc678081ca5f0971b8bcbf312c1e83017365c33

Change-Id: I64d15b050cfd3d88923bf996cb68b13504dbf6af
Signed-off-by: Vratko Polak <vrpolak@cisco.com>
2020-08-17 10:35:48 +00:00
7d29e320fb stats: remove offsets on vpp side
Represent pointers directly in shared memory and require clients to adjust for
shared memory segment being mapped at different base address.
Deprecated: stat_segment_pointer() / stat_segment_offset()
Added: stat_segment_adjust()

Bumped the stat segment version to 2.

Type: refactor
Signed-off-by: Ole Troan <ot@cisco.com>
Change-Id: I33e756187b8903b45dcd353e6c1a101b7a4acb79
2020-08-13 07:28:13 +00:00
710fe10462 papi: allow unknown address family
In unions all representations of the union are decoded.
Which means trying to decode something that isn't an address
might have invalid address family types.

Type: fix
Ticket: VPP-1884
Signed-off-by: Ole Troan <ot@cisco.com>
Change-Id: Id3381ef8cc885952c1eb488ebc70e276eaceb366
2020-08-11 13:51:59 +00:00
fdc678081c stats: add timeout for in_progress access to stat segment
add new api stat_segment_set_timeout_nsec to limit time waiting for vpp
in_progress state.

Change-Id: Ic78a97bc5013d67d7e4bbcc4a6f0ef918f9f9b33
Type: improvement
Signed-off-by: Ole Troan <ot@cisco.com>
2020-08-11 09:48:13 +02:00
3c70c05e1f stats: name and error index client memory leak
Type: fix
Change-Id: I6c9999b93d4f4ad4b8540a21e793c9a90e7c8ecf
Signed-off-by: Ole Troan <ot@cisco.com>
2020-08-10 17:29:09 +02:00
35418ba491 vapi: memset allocated messages to zero
This avoids using dirty data from shared memory by client.

Type: fix
Signed-off-by: Klement Sekera <ksekera@cisco.com>
Change-Id: I96eecf655bf344ec29609cedbd8dc891b572e207
2020-06-10 11:11:07 +00:00
f5db3711b2 api: add new stream message convention
Instead of having to wrap dump/detail calls in control ping, send details messages in between a normal
reply / request pair. As expressed in the below service statement.

Example:

service {
  rpc map_domains_gets returns map_domains_get_reply
    stream map_domain_details;
};

define map_domains_get
{
  u32 client_index;
  u32 context;
  u32 cursor;
};

define map_domains_get_reply
{
  u32 context;
  i32 retval;
  u32 cursor;
};

To avoid blocking the main thread for too long, the replies are now sent in client message queue size
chunks. The reply message returns VNET_API_ERROR_EAGAIN when there is more to read.
The API handler must also include a "cursor" that is used to the next call to the get function.

API handler example:
  REPLY_AND_DETAILS_MACRO (VL_API_MAP_DOMAINS_GET_REPLY, mm->domains,
  ({
    send_domain_details (cursor, rp, mp->context);
  }));

The macro starts from cursor and iterates through the pool
until vl_api_process_may_suspend() returns true or the iteration
reaches the end of the list.

Client Example:

cursor = 0
d = []
while True:
    rv, details = map_domains_get(cursor=cursor)
    d += details
    if rv.retval == 0 or rv.retval != -165:
        break
    cursor = rv.cursor

or the convenience iterator:
for x in vpp.details_iter(vpp.api.map_domains_get):
  pass

or

list(details_iter(map_domains_get))

Change-Id: Iad9f6b41b0ef886adb584c97708dd91cf552749e
Type: feature
Signed-off-by: Ole Troan <ot@cisco.com>
2020-05-25 11:22:34 +00:00
a416493d3b misc: fix ubuntu 20.04 python deps
Type: fix
Change-Id: I9cdfbffd6333d090f970422bf047aaa90c1e4c65
Signed-off-by: Damjan Marion <damarion@cisco.com>
2020-05-15 23:42:40 +00:00
599efc67e8 build: various improvements
- add option to install only host tools
- add option to specify lib and runtime dir

Type: improvement

Change-Id: I6356b52df459120fc9b0127948bae7679fb10e52
Signed-off-by: Damjan Marion <damarion@cisco.com>
2020-05-08 17:01:32 +00:00
c5c788bfa1 papi: use python3 for papi install
Breaks on Ubuntu 20.04 otherwise.

Type: fix
Signed-off-by: Ole Troan <ot@cisco.com>
Change-Id: I407215a03948d6e49152ee97099539bb625c12ef
2020-05-08 12:47:55 +00:00
d7a32ebd99 vapi: add support for defaults in typedefs
refactored out of Neale's change:
    https://gerrit.fd.io/r/c/vpp/+/26276

Type: refactor

Change-Id: Ibb0c019856dc44640e94d6d80a5d119a6296d95c
Signed-off-by: Paul Vinciguerra <pvinci@vinciconsulting.com>
(cherry picked from commit a751d8d61fe5880f6d447e63b81e2df30561e9f9)
2020-05-04 17:26:28 +00:00
7f286f720d api: fix include_guard when path contains a plus
The path to VPP source might contain a '+' when building it
with Yocto/OpenEmbedded.

Type: fix

Signed-off-by: Ruslan Babayev <ruslan@babayev.com>
Change-Id: I205ac0de7d8726724af0e30f5b199391e05dc615
2020-05-01 17:06:52 -07:00
e64e5fff4d tests: implement ipaddress convenience methods
Add vpp specific properties to ip addresses for use in the api.
  .vapi_af  -- returns [ADDRESS_IP4, ADDRESS_IP6]
  .vapi_af_name -- returns the string ['ip4', 'ip6']

  Update tests to demonstrate usage.

Type: feature

Change-Id: I43447a1522769d99f89debdc714c51700068d771
Signed-off-by: Paul Vinciguerra <pvinci@vinciconsulting.com>
2020-04-28 15:43:28 +00:00
b5c0d35f94 vapi: packed enum type generation
Type: fix

if the ,api/.json specifies that a enum should be u8/u16 that the
generated c enum needs to be packed.

Signed-off-by: Neale Ranns <nranns@cisco.com>
Change-Id: Ia0497b45e4c510a5c63cd02e966769bf20686838
2020-04-24 07:22:32 +00:00
2c8e0023f9 vppinfra: remove the historical mheap memory allocator
The mheap allocator has been turned off for several releases. This
commit removes the cmake config parameter, parallel support for
dlmalloc and mheap, and the mheap allocator itself.

Type: refactor

Signed-off-by: Dave Barach <dave@barachs.net>
Change-Id: I104f88a1f06e47e90e5f7fb3e11cd1ca66467903
2020-02-11 23:57:18 +00:00
72e31bc2d9 stats: fix state counter removal
Avoid using vec_del1() for directory vector to keep indexes valid all
the time.

There are state counters for each slave in LACP bond mode which can be
dynamically created and removed. Vector index is used to access these
counters. But also vec_del1() is used to remove counter from vector.
This function changes the index of the last element, so after this we
are unable to access ex-last element using old index.

As a result it is not possible to add-del-add two interfaces to the LACP
bond:

DBGvpp# create bond mode lacp
BondEthernet0
DBGvpp# create packet-generator interface pg1
DBGvpp# create packet-generator interface pg2
DBGvpp# bond add BondEthernet0 pg1
DBGvpp# bond add BondEthernet0 pg2
DBGvpp# bond del pg1
DBGvpp# bond del pg2
DBGvpp# bond add BondEthernet0 pg1
DBGvpp# bond add BondEthernet0 pg2
bond add: /if/lacp/1/3/partner-state is already register

Type: fix

Signed-off-by: Vladimir Isaev <visaev@netgate.com>
Change-Id: I2c86e13905eefdef6233369cd4ab5c1b53d123bd
2020-02-05 15:34:49 +00:00
e090f4dbf5 papi: lazily initialize stats client
remove wait-loop on stats socket from test framework.

Type: refactor

Change-Id: I5bb95a7c597707a87f9d9a471215c4b4af1a2280
Signed-off-by: Paul Vinciguerra <pvinci@vinciconsulting.com>
2019-12-19 15:48:21 +00:00
dc20371f83 build: export vapi generation in vpp-dev
Adds the higher-level vapi generation to cmake/api.cmake and exposes
the necessary python scripts in vpp-dev, so that out-of-tree/downstream
plugins can also leverage the more convenient API.

Type: feature

Signed-off-by: Oliver Giles <oliver_g@radwin.com>
Change-Id: I8c40a14d27ba3cb972c6907632e03c0e7b0ce982
2019-12-17 18:05:15 +00:00
39d69112fc api: multiple connections per process
Type: feature

Signed-off-by: Dave Barach <dave@barachs.net>
Change-Id: I2272521d6e69edcd385ef684af6dd4eea5eaa953
2019-12-10 01:13:05 +00:00
fd574087e4 papi: add call stats
Type: feature
Change-Id: Ic6d44122d3e62e09402e3f1946f7e57e9b5e7c5f
Signed-off-by: Ole Troan <ot@cisco.com>
2019-12-05 14:56:23 +00:00
e2ccdf0316 papi: add a per-call _timeout option
add the ability to override the default timeout value on a per-call
 basis.
 Use:
   rv = self.vapi.papi.cli_inband(cmd='wait 10', _timeout=15)

Type: feature

Change-Id: Ia90a58586a1f63e02118599a2a4b7141e5a0b90d
Signed-off-by: Paul Vinciguerra <pvinci@vinciconsulting.com>
2019-12-03 09:28:18 +00:00
9fb6d40eb3 misc: add address sanitizer heap instrumentation
Introduce AddressSanitizer support: https://github.com/google/sanitizers/
This starts with heap instrumentation. vlib_buffer, bihash and stack
instrumentation should follow.

Type: feature

Change-Id: I7f20e235b2f79db72efd0e756f22c75f717a9884
Signed-off-by: Benoît Ganne <bganne@cisco.com>
2019-11-27 10:50:28 +00:00
99fbf0574f papi: fix typo in repr
Reported by Vratko's review.
(Thanks for the review)

Fixes: 14b0b4791c0b8c886e7b5c9ca667d060f0bada0b

Type: fix

Change-Id: I9c080c0c40060cc77977e76edae03d60eb393ce2
Signed-off-by: Paul Vinciguerra <pvinci@vinciconsulting.com>
2019-11-27 08:35:05 +00:00
da47f67be2 papi: fix papi default handling
Type: fix
Change-Id: I91063e2096fb09c34898a611184c8381fccdb333
Signed-off-by: Ole Troan <ot@cisco.com>
2019-11-24 18:56:18 +01:00
ba2c7fad1d papi: add missing base types to serializer
File "/vpp/src/vpp-api/python/vpp_papi/vpp_serializer.py", line 512, in __init__
    'Unknown message type {}'.format(f_type))
  vpp_papi.vpp_serializer.VPPSerializerValueError: Unknown message type i16

Type: fix

Change-Id: Ibf73dc8df90153db586afe614e47be49739bac2f
Signed-off-by: Paul Vinciguerra <pvinci@vinciconsulting.com>
2019-11-24 13:17:32 +00:00
14b0b4791c papi: add repr to packer types for troubleshooting
Type: feature

Change-Id: Id3cd89eca0deddb70f506239f9d0543fc28cf7f4
Signed-off-by: Paul Vinciguerra <pvinci@vinciconsulting.com>
2019-11-23 23:49:57 -05:00
418ebb711e papi: support default for type alias decaying to basetype
Add PAPI support for VppTypeAlias decaying to BaseType.
E.g vl_api_interface_index_t sw_if_index [default=0xffffffff]

Type: feature

Signed-off-by: Ole Troan <ot@cisco.com>
Change-Id: I2061392157c9c11fbb0ff9e5406ea65489b017e9
2019-11-22 14:05:24 +00:00
6af62565e3 papi: enhance MACAddress() equality
Allows for comparison without needing str(MACAddress())

 Traceback (most recent call last):
  File "/vpp/test/test_ip6.py", line 1074, in test_icmpv6_echo
    self.assertEqual(ether.dst, self.pg0.remote_mac)
 AssertionError: '02:01:00:00:ff:02' != MACAddress(02:01:00:00:ff:02)

Type: feature

Change-Id: Ife1cbfc74d477695d15b33a19da7dd2fa241a348
Signed-off-by: Paul Vinciguerra <pvinci@vinciconsulting.com>
2019-11-13 09:43:04 +00:00
c046d709e1 papi: add wrapper to validate crc manifest
If a client application is built against 19.08, it can dump the "manifest" of API signatures.
Either the all APIs (--dump) or the APIs it is interested in (--dumpfiltered).

When the developers of said client application wants to verify that it works with VPP 20.01.
It can connect to VPP and --validate the old mainfest file, and will be told a list of
messages (both request and reply) that has changed.

import argparse
from vpp_papi import VPP
import sys
import argparse

parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group()
group.add_argument("--dump", action="store_true")
group.add_argument("--dumpfiltered", action="store_true")
group.add_argument("--validate", action="store_true")
args = parser.parse_args()

vpp = VPP(use_socket=True)

vpp.connect(name='apimanifest')

if args.validate:
    # Verify manifest
    message_table = eval(sys.stdin.read())
    missing = vpp.validate_message_table(message_table)
    print ('Changed message signatures: {}'.format(missing))
elif args.dump:
    # Output manifest to stdout
    print('{}'.format(vpp.dump_message_table()))
elif args.dumpfiltered:
    # Output manifest to stdout
    filterlist = eval(sys.stdin.read())
    print('{}'.format(vpp.dump_message_table_filtered(filterlist)))

vpp.disconnect()

Type: feature
Change-Id: I7e708b36f599ed88e4864970c8593cc2fe5fbf61
Signed-off-by: Ole Troan <ot@cisco.com>
2019-11-12 17:59:18 +00:00
ead1e536d6 misc: Fix python scripts shebang line
Type: fix

Since CentOS 8, RPM build script doesn't accept '#!/usr/bin/env python'
as a valid shebang line.  It requires scripts to explicitly chose
between python2 or python3.

Change all to use python3 as suggested by Paul Vinciguerra.

Depends-On: https://gerrit.fd.io/r/23170

Signed-off-by: Renato Botelho do Couto <renato@netgate.com>
Change-Id: Ie72af9f60fd0609e07f05b70f8d96e738b2754d1
2019-11-05 21:08:59 +00:00
1b1ccadc90 vapi: switch to python3
Type: fix
Signed-off-by: Ole Troan <ot@cisco.com>
Change-Id: I78aac39b697e29bb454e5e95855e79ea3122b4c3
2019-10-28 09:07:14 +00:00
40dc4b35e3 papi: fix default handling
The BaseTypers object were reused, so a default for anyother mesage
would be inherited in new messages.

Type: fix
Fixes: 85465588b18fef9c4712f864f512e00741e2d4f2
Change-Id: Ie1efb85a76b088653eb9ea4b88540c98b6b0aad0
Signed-off-by: Ole Troan <ot@cisco.com>
2019-10-23 07:47:19 +00:00
2267429574 bier: tests support python3
Type: fix
Signed-off-by: Ole Troan <ot@cisco.com>
Change-Id: I3cf5295f1a85579a66ba38ca1f74678b45474959
2019-10-21 17:55:13 +00:00
64e978b1bf ipsec: make tests support python3
Type: fix
Signed-off-by: Ole Troan <ot@cisco.com>
Change-Id: I3255702e7c562c8d04a91a095e245756c6443a9e
2019-10-18 07:49:11 +00:00
8921dc6754 papi: fix socket sendall calls
No point in checking the return value,
as .sendall() raises on error
(and the previous check was missing "not").

Type: fix

Change-Id: I9e07709ddd7093f91ffef87808abbab264b8aa5a
Signed-off-by: Vratko Polak <vrpolak@cisco.com>
2019-10-14 18:49:22 +00:00
6df2c79541 papi: harden socket handling
In the previous implementation of socket transport for PAPI,
socket methods .send and .recv_into were used.
But they are not guaranteed to send/receive all the data
for the full message. The receive part contained a loop,
but it handled only the main message, not the header.

This patch replaces .send with .sendall
and uses newly defined _read_fixed method.

Also, removed Paul from maintainers,
as he is not active much, lately.

Type: fix

Change-Id: Iae1a68bf8f9e666856b7c7d62ebfe22defc5dfe1
Signed-off-by: Vratko Polak <vrpolak@cisco.com>
2019-10-11 18:48:21 +00:00
0938547eaa papi: introduce read_blocking
Previously, self.transport.q got the messages
(at least for socket transport), stored in the encoded (packed) form.
In order to avoid accessing internals for async reads,
a new method is introduced, to perform
blocking reads of decoded (unpacked) messages.

The method is also used in _call_vpp(),
so sync and async reads are kept compatible.

Type: feature

Change-Id: Id49792dfa57c00b1a14a198031c5398d09a9ba20
Signed-off-by: Vratko Polak <vrpolak@cisco.com>
2019-10-09 09:23:29 +00:00
5e2f84d2cf papi: truncate long logger messages
Dumping whole cli_inband output causes huge unformatted messages written
to logger, so truncate these to avoid that.

Type: fix

Change-Id: I59565a98e3595cbfe4971cc346e104cb198d8f24
Signed-off-by: Klement Sekera <ksekera@cisco.com>
2019-09-25 08:18:20 +00:00
75761b933f api: split vl_api_prefix into two
One type for address with prefix and one type for prefix.

Type: fix
Signed-off-by: Ole Troan <ot@cisco.com>
Change-Id: Icfec51d9b7d5cde1d69fbecdd97498688ab7b295
Signed-off-by: Ole Troan <ot@cisco.com>
Signed-off-by: Klement Sekera <ksekera@cisco.com>
Signed-off-by: Ole Troan <ot@cisco.com>
2019-09-19 14:24:54 +00:00
33a58171e5 api: autogenerate api trace print/endian
In addition to the external vppapitrace tool, VPP itself supports dumping of API trace files.
In two formats, "custom-dump" and "dump". "dump" gives a human friendly list,
and "custom-dump" is meant to give a list of commands that can be fed to VAT.
This patch only deals with "dump".
Prior to this fix, auto-generation was only done for the basic types.
This fix adds support for any type, including lists, and supports pretty-printing
of enums, strings, IP addresses, MAC addresses and so on.

Usage: api trace dump <api-trace-file>

For example

Change-Id: I4e485680e6dcfce7489299ae6cf31d835071ac40

---------- trace 48 -----------
vl_api_sw_interface_set_flags_t:
  _vl_msg_id: 75
  client_index: 0
  context: 10
  sw_if_index: 1
  flags: IF_STATUS_API_FLAG_ADMIN_UP
---------- trace 49 -----------
vl_api_sw_interface_add_del_address_t:
  _vl_msg_id: 88
  client_index: 0
  context: 11
  sw_if_index: 1
  is_add: 1
  del_all: 0
  prefix: 172.16.1.1/24
---------- trace 51 -----------
vl_api_cli_inband_t:
  _vl_msg_id: 819
  client_index: 0
  context: 13
  cmd: packet-generator capture pg0 pcap /tmp/vpp-unittest-TestMAP-YhcmDX/pg0_out.pcap disable
---------- trace 58 -----------
vl_api_ip_neighbor_add_del_t:
  _vl_msg_id: 199
  client_index: 0
  context: 20
  is_add: 1
  neighbor:
    sw_if_index: 2
    flags: IP_API_NEIGHBOR_FLAG_NONE
    mac_address: 0202.0000.ff02
    ip_address: fd01:2::2

Signed-off-by: Ole Troan <ot@cisco.com>
Change-Id: I5556d06008de2762e7c2d35a8b0963ae670b3db1
Type: fix
Signed-off-by: Ole Troan <ot@cisco.com>
Signed-off-by: Ole Troan <ot@cisco.com>
Signed-off-by: Ole Troan <ot@cisco.com>
Signed-off-by: Ole Troan <ot@cisco.com>
Signed-off-by: Ole Troan <ot@cisco.com>
Signed-off-by: Ole Troan <ot@cisco.com>
Signed-off-by: Ole Troan <ot@cisco.com>
Signed-off-by: Ole Troan <ot@cisco.com>
2019-09-16 12:23:27 +00:00
2f6e0c6002 papi: let async calls return context
Callback receives "reply" messages containing context,
but previously there was no easy way
to get the automatically generated context value
of the originally sent "command" message.

With this, the caller can store the contexts,
so the callback knows which command got replied to.

Type: feature

Change-Id: I58ca812d20b03916f74096c396126710115a747c
Signed-off-by: Vratko Polak <vrpolak@cisco.com>
2019-09-10 07:23:39 +00:00
daa4bff164 api: memclnt api use string type.
Type: fix
Signed-off-by: Ole Troan <ot@cisco.com>
Change-Id: Idad79286b7730c8e85202c4b8e675ea50f8bbc48
Signed-off-by: Ole Troan <ot@cisco.com>
2019-09-04 13:02:26 +00:00
e5ff5a36dd api: enforce vla is last and fixed string type
Enforce that variable length fields are the last element of API messages.

Add a 'fixed' version of string type, since dealing with
multiple variable length strings turned out too painful
for the C language bindings.

The string type is now:
{
  string name[64]; // NUL terminated C-string. Essentially decays to u8 name[64]
  string name[];   // Variable length string with embedded len field (vl_api_string_t)
};

The latter notation could be made available to other types as well.
e.g.
{
  vl_api_address_t addresses[];
}
instead of

{
  u32 n_addr;
  vl_api_address_t addresses[n_addr];
};

Type: fix
Change-Id: I18fa17ef47227633752ab50453e8d20a652a9f9b
Signed-off-by: Ole Troan <ot@cisco.com>
2019-09-03 20:04:13 +00:00
7adaa226ea api: revert use string type for strings in memclnt.api
This reverts commit 2959d42feb576c0e00c28c4e27658b25f6c783e9.
Lacks client side fixes.

Type: fix
Change-Id: Ib94b18e74325cede41ed1733e57896f17a952526
Signed-off-by: Ole Troan <ot@cisco.com>
2019-08-27 18:04:00 +00:00
2959d42feb api: use string type for strings in memclnt.api
Explicitly using string type in API allows for autogenerating tools to print
strings instead of hex-dumping byte strings.

Type: fix
Signed-off-by: Ole Troan <ot@cisco.com>
Signed-off-by: Klement Sekera <ksekera@cisco.com>
Change-Id: I573962d6b34d5d10aab9dc6a5fdf101c9b12a6a6
Signed-off-by: Ole Troan <ot@cisco.com>
2019-08-27 07:51:55 +00:00
531969ef61 stats: refactor header files
Performant stat segment scraping involves caching the results of
stat_segment_ls (...) and directly fishing counter data from the
shared-memory segment.

To do that, we need to publish several things previously hidden,
declared in stat_client.c:

o stat_client_main_t typedef
o stat_segment_access_t typedef
o stat_segment_access_start inline function
o stat_segment_access_end inline function

Type: refactor

Signed-off-by: Dave Barach <dave@barachs.net>
Change-Id: I3175e3d1f1fd8ea816336a584565179d1972115c
2019-08-15 10:14:52 +00:00