Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  vsock_test_zerocopy.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/* MSG_ZEROCOPY feature tests for vsock
 *
 * Copyright (C) 2023 SberDevices.
 *
 * Author: Arseniy Krasnov <avkrasnov@salutedevices.com>
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#include <poll.h>
#include <linux/errqueue.h>
#include <linux/kernel.h>
#include <errno.h>

#include "control.h"
#include "vsock_test_zerocopy.h"
#include "msg_zerocopy_common.h"

#ifndef PAGE_SIZE
#define PAGE_SIZE  4096
#endif

#define VSOCK_TEST_DATA_MAX_IOV 3

struct vsock_test_data {
 /* This test case if for SOCK_STREAM only. */
 bool stream_only;
 /* Data must be zerocopied. This field is checked against
 * field 'ee_code' of the 'struct sock_extended_err', which
 * contains bit to detect that zerocopy transmission was
 * fallbacked to copy mode.
 */

 bool zerocopied;
 /* Enable SO_ZEROCOPY option on the socket. Without enabled
 * SO_ZEROCOPY, every MSG_ZEROCOPY transmission will behave
 * like without MSG_ZEROCOPY flag.
 */

 bool so_zerocopy;
 /* 'errno' after 'sendmsg()' call. */
 int sendmsg_errno;
 /* Number of valid elements in 'vecs'. */
 int vecs_cnt;
 struct iovec vecs[VSOCK_TEST_DATA_MAX_IOV];
};

static struct vsock_test_data test_data_array[] = {
 /* Last element has non-page aligned size. */
 {
  .zerocopied = true,
  .so_zerocopy = true,
  .sendmsg_errno = 0,
  .vecs_cnt = 3,
  {
   { NULL, PAGE_SIZE },
   { NULL, PAGE_SIZE },
   { NULL, 200 }
  }
 },
 /* All elements have page aligned base and size. */
 {
  .zerocopied = true,
  .so_zerocopy = true,
  .sendmsg_errno = 0,
  .vecs_cnt = 3,
  {
   { NULL, PAGE_SIZE },
   { NULL, PAGE_SIZE * 2 },
   { NULL, PAGE_SIZE * 3 }
  }
 },
 /* All elements have page aligned base and size. But
 * data length is bigger than 64Kb.
 */

 {
  .zerocopied = true,
  .so_zerocopy = true,
  .sendmsg_errno = 0,
  .vecs_cnt = 3,
  {
   { NULL, PAGE_SIZE * 16 },
   { NULL, PAGE_SIZE * 16 },
   { NULL, PAGE_SIZE * 16 }
  }
 },
 /* Middle element has both non-page aligned base and size. */
 {
  .zerocopied = true,
  .so_zerocopy = true,
  .sendmsg_errno = 0,
  .vecs_cnt = 3,
  {
   { NULL, PAGE_SIZE },
   { (void *)1, 100 },
   { NULL, PAGE_SIZE }
  }
 },
 /* Middle element is unmapped. */
 {
  .zerocopied = false,
  .so_zerocopy = true,
  .sendmsg_errno = ENOMEM,
  .vecs_cnt = 3,
  {
   { NULL, PAGE_SIZE },
   { MAP_FAILED, PAGE_SIZE },
   { NULL, PAGE_SIZE }
  }
 },
 /* Valid data, but SO_ZEROCOPY is off. This
 * will trigger fallback to copy.
 */

 {
  .zerocopied = false,
  .so_zerocopy = false,
  .sendmsg_errno = 0,
  .vecs_cnt = 1,
  {
   { NULL, PAGE_SIZE }
  }
 },
 /* Valid data, but message is bigger than peer's
 * buffer, so this will trigger fallback to copy.
 * This test is for SOCK_STREAM only, because
 * for SOCK_SEQPACKET, 'sendmsg()' returns EMSGSIZE.
 */

 {
  .stream_only = true,
  .zerocopied = false,
  .so_zerocopy = true,
  .sendmsg_errno = 0,
  .vecs_cnt = 1,
  {
   { NULL, 100 * PAGE_SIZE }
  }
 },
};

#define POLL_TIMEOUT_MS  100

static void test_client(const struct test_opts *opts,
   const struct vsock_test_data *test_data,
   bool sock_seqpacket)
{
 struct pollfd fds = { 0 };
 struct msghdr msg = { 0 };
 ssize_t sendmsg_res;
 struct iovec *iovec;
 int fd;

 if (sock_seqpacket)
  fd = vsock_seqpacket_connect(opts->peer_cid, opts->peer_port);
 else
  fd = vsock_stream_connect(opts->peer_cid, opts->peer_port);

 if (fd < 0) {
  perror("connect");
  exit(EXIT_FAILURE);
 }

 if (test_data->so_zerocopy)
  enable_so_zerocopy_check(fd);

 iovec = alloc_test_iovec(test_data->vecs, test_data->vecs_cnt);

 msg.msg_iov = iovec;
 msg.msg_iovlen = test_data->vecs_cnt;

 errno = 0;

 sendmsg_res = sendmsg(fd, &msg, MSG_ZEROCOPY);
 if (errno != test_data->sendmsg_errno) {
  fprintf(stderr, "expected 'errno' == %i, got %i\n",
   test_data->sendmsg_errno, errno);
  exit(EXIT_FAILURE);
 }

 if (!errno) {
  if (sendmsg_res != iovec_bytes(iovec, test_data->vecs_cnt)) {
   fprintf(stderr, "expected 'sendmsg()' == %li, got %li\n",
    iovec_bytes(iovec, test_data->vecs_cnt),
    sendmsg_res);
   exit(EXIT_FAILURE);
  }
 }

 fds.fd = fd;
 fds.events = 0;

 if (poll(&fds, 1, POLL_TIMEOUT_MS) < 0) {
  perror("poll");
  exit(EXIT_FAILURE);
 }

 if (fds.revents & POLLERR) {
  vsock_recv_completion(fd, &test_data->zerocopied);
 } else if (test_data->so_zerocopy && !test_data->sendmsg_errno) {
  /* If we don't have data in the error queue, but
 * SO_ZEROCOPY was enabled and 'sendmsg()' was
 * successful - this is an error.
 */

  fprintf(stderr, "POLLERR expected\n");
  exit(EXIT_FAILURE);
 }

 if (!test_data->sendmsg_errno)
  control_writeulong(iovec_hash_djb2(iovec, test_data->vecs_cnt));
 else
  control_writeulong(0);

 control_writeln("DONE");
 free_test_iovec(test_data->vecs, iovec, test_data->vecs_cnt);
 close(fd);
}

void test_stream_msgzcopy_client(const struct test_opts *opts)
{
 int i;

 for (i = 0; i < ARRAY_SIZE(test_data_array); i++)
  test_client(opts, &test_data_array[i], false);
}

void test_seqpacket_msgzcopy_client(const struct test_opts *opts)
{
 int i;

 for (i = 0; i < ARRAY_SIZE(test_data_array); i++) {
  if (test_data_array[i].stream_only)
   continue;

  test_client(opts, &test_data_array[i], true);
 }
}

static void test_server(const struct test_opts *opts,
   const struct vsock_test_data *test_data,
   bool sock_seqpacket)
{
 unsigned long remote_hash;
 unsigned long local_hash;
 ssize_t total_bytes_rec;
 unsigned char *data;
 size_t data_len;
 int fd;

 if (sock_seqpacket)
  fd = vsock_seqpacket_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
 else
  fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL);

 if (fd < 0) {
  perror("accept");
  exit(EXIT_FAILURE);
 }

 data_len = iovec_bytes(test_data->vecs, test_data->vecs_cnt);

 data = malloc(data_len);
 if (!data) {
  perror("malloc");
  exit(EXIT_FAILURE);
 }

 total_bytes_rec = 0;

 while (total_bytes_rec != data_len) {
  ssize_t bytes_rec;

  bytes_rec = read(fd, data + total_bytes_rec,
     data_len - total_bytes_rec);
  if (bytes_rec <= 0)
   break;

  total_bytes_rec += bytes_rec;
 }

 if (test_data->sendmsg_errno == 0)
  local_hash = hash_djb2(data, data_len);
 else
  local_hash = 0;

 free(data);

 /* Waiting for some result. */
 remote_hash = control_readulong();
 if (remote_hash != local_hash) {
  fprintf(stderr, "hash mismatch\n");
  exit(EXIT_FAILURE);
 }

 control_expectln("DONE");
 close(fd);
}

void test_stream_msgzcopy_server(const struct test_opts *opts)
{
 int i;

 for (i = 0; i < ARRAY_SIZE(test_data_array); i++)
  test_server(opts, &test_data_array[i], false);
}

void test_seqpacket_msgzcopy_server(const struct test_opts *opts)
{
 int i;

 for (i = 0; i < ARRAY_SIZE(test_data_array); i++) {
  if (test_data_array[i].stream_only)
   continue;

  test_server(opts, &test_data_array[i], true);
 }
}

void test_stream_msgzcopy_empty_errq_client(const struct test_opts *opts)
{
 struct msghdr msg = { 0 };
 char cmsg_data[128];
 ssize_t res;
 int fd;

 fd = vsock_stream_connect(opts->peer_cid, opts->peer_port);
 if (fd < 0) {
  perror("connect");
  exit(EXIT_FAILURE);
 }

 msg.msg_control = cmsg_data;
 msg.msg_controllen = sizeof(cmsg_data);

 res = recvmsg(fd, &msg, MSG_ERRQUEUE);
 if (res != -1) {
  fprintf(stderr, "expected 'recvmsg(2)' failure, got %zi\n",
   res);
  exit(EXIT_FAILURE);
 }

 control_writeln("DONE");
 close(fd);
}

void test_stream_msgzcopy_empty_errq_server(const struct test_opts *opts)
{
 int fd;

 fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
 if (fd < 0) {
  perror("accept");
  exit(EXIT_FAILURE);
 }

 control_expectln("DONE");
 close(fd);
}

Messung V0.5
C=99 H=97 G=97

¤ Dauer der Verarbeitung: 0.4 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge