@@ -1232,6 +1232,171 @@ static void test_double_bind_connect_client(const struct test_opts *opts)
12321232 }
12331233}
12341234
1235+ #define RCVLOWAT_CREDIT_UPD_BUF_SIZE (1024 * 128)
1236+ /* This define is the same as in 'include/linux/virtio_vsock.h':
1237+ * it is used to decide when to send credit update message during
1238+ * reading from rx queue of a socket. Value and its usage in
1239+ * kernel is important for this test.
1240+ */
1241+ #define VIRTIO_VSOCK_MAX_PKT_BUF_SIZE (1024 * 64)
1242+
1243+ static void test_stream_rcvlowat_def_cred_upd_client (const struct test_opts * opts )
1244+ {
1245+ size_t buf_size ;
1246+ void * buf ;
1247+ int fd ;
1248+
1249+ fd = vsock_stream_connect (opts -> peer_cid , 1234 );
1250+ if (fd < 0 ) {
1251+ perror ("connect" );
1252+ exit (EXIT_FAILURE );
1253+ }
1254+
1255+ /* Send 1 byte more than peer's buffer size. */
1256+ buf_size = RCVLOWAT_CREDIT_UPD_BUF_SIZE + 1 ;
1257+
1258+ buf = malloc (buf_size );
1259+ if (!buf ) {
1260+ perror ("malloc" );
1261+ exit (EXIT_FAILURE );
1262+ }
1263+
1264+ /* Wait until peer sets needed buffer size. */
1265+ recv_byte (fd , 1 , 0 );
1266+
1267+ if (send (fd , buf , buf_size , 0 ) != buf_size ) {
1268+ perror ("send failed" );
1269+ exit (EXIT_FAILURE );
1270+ }
1271+
1272+ free (buf );
1273+ close (fd );
1274+ }
1275+
1276+ static void test_stream_credit_update_test (const struct test_opts * opts ,
1277+ bool low_rx_bytes_test )
1278+ {
1279+ size_t recv_buf_size ;
1280+ struct pollfd fds ;
1281+ size_t buf_size ;
1282+ void * buf ;
1283+ int fd ;
1284+
1285+ fd = vsock_stream_accept (VMADDR_CID_ANY , 1234 , NULL );
1286+ if (fd < 0 ) {
1287+ perror ("accept" );
1288+ exit (EXIT_FAILURE );
1289+ }
1290+
1291+ buf_size = RCVLOWAT_CREDIT_UPD_BUF_SIZE ;
1292+
1293+ if (setsockopt (fd , AF_VSOCK , SO_VM_SOCKETS_BUFFER_SIZE ,
1294+ & buf_size , sizeof (buf_size ))) {
1295+ perror ("setsockopt(SO_VM_SOCKETS_BUFFER_SIZE)" );
1296+ exit (EXIT_FAILURE );
1297+ }
1298+
1299+ if (low_rx_bytes_test ) {
1300+ /* Set new SO_RCVLOWAT here. This enables sending credit
1301+ * update when number of bytes if our rx queue become <
1302+ * SO_RCVLOWAT value.
1303+ */
1304+ recv_buf_size = 1 + VIRTIO_VSOCK_MAX_PKT_BUF_SIZE ;
1305+
1306+ if (setsockopt (fd , SOL_SOCKET , SO_RCVLOWAT ,
1307+ & recv_buf_size , sizeof (recv_buf_size ))) {
1308+ perror ("setsockopt(SO_RCVLOWAT)" );
1309+ exit (EXIT_FAILURE );
1310+ }
1311+ }
1312+
1313+ /* Send one dummy byte here, because 'setsockopt()' above also
1314+ * sends special packet which tells sender to update our buffer
1315+ * size. This 'send_byte()' will serialize such packet with data
1316+ * reads in a loop below. Sender starts transmission only when
1317+ * it receives this single byte.
1318+ */
1319+ send_byte (fd , 1 , 0 );
1320+
1321+ buf = malloc (buf_size );
1322+ if (!buf ) {
1323+ perror ("malloc" );
1324+ exit (EXIT_FAILURE );
1325+ }
1326+
1327+ /* Wait until there will be 128KB of data in rx queue. */
1328+ while (1 ) {
1329+ ssize_t res ;
1330+
1331+ res = recv (fd , buf , buf_size , MSG_PEEK );
1332+ if (res == buf_size )
1333+ break ;
1334+
1335+ if (res <= 0 ) {
1336+ fprintf (stderr , "unexpected 'recv()' return: %zi\n" , res );
1337+ exit (EXIT_FAILURE );
1338+ }
1339+ }
1340+
1341+ /* There is 128KB of data in the socket's rx queue, dequeue first
1342+ * 64KB, credit update is sent if 'low_rx_bytes_test' == true.
1343+ * Otherwise, credit update is sent in 'if (!low_rx_bytes_test)'.
1344+ */
1345+ recv_buf_size = VIRTIO_VSOCK_MAX_PKT_BUF_SIZE ;
1346+ recv_buf (fd , buf , recv_buf_size , 0 , recv_buf_size );
1347+
1348+ if (!low_rx_bytes_test ) {
1349+ recv_buf_size ++ ;
1350+
1351+ /* Updating SO_RCVLOWAT will send credit update. */
1352+ if (setsockopt (fd , SOL_SOCKET , SO_RCVLOWAT ,
1353+ & recv_buf_size , sizeof (recv_buf_size ))) {
1354+ perror ("setsockopt(SO_RCVLOWAT)" );
1355+ exit (EXIT_FAILURE );
1356+ }
1357+ }
1358+
1359+ fds .fd = fd ;
1360+ fds .events = POLLIN | POLLRDNORM | POLLERR |
1361+ POLLRDHUP | POLLHUP ;
1362+
1363+ /* This 'poll()' will return once we receive last byte
1364+ * sent by client.
1365+ */
1366+ if (poll (& fds , 1 , -1 ) < 0 ) {
1367+ perror ("poll" );
1368+ exit (EXIT_FAILURE );
1369+ }
1370+
1371+ if (fds .revents & POLLERR ) {
1372+ fprintf (stderr , "'poll()' error\n" );
1373+ exit (EXIT_FAILURE );
1374+ }
1375+
1376+ if (fds .revents & (POLLIN | POLLRDNORM )) {
1377+ recv_buf (fd , buf , recv_buf_size , MSG_DONTWAIT , recv_buf_size );
1378+ } else {
1379+ /* These flags must be set, as there is at
1380+ * least 64KB of data ready to read.
1381+ */
1382+ fprintf (stderr , "POLLIN | POLLRDNORM expected\n" );
1383+ exit (EXIT_FAILURE );
1384+ }
1385+
1386+ free (buf );
1387+ close (fd );
1388+ }
1389+
1390+ static void test_stream_cred_upd_on_low_rx_bytes (const struct test_opts * opts )
1391+ {
1392+ test_stream_credit_update_test (opts , true);
1393+ }
1394+
1395+ static void test_stream_cred_upd_on_set_rcvlowat (const struct test_opts * opts )
1396+ {
1397+ test_stream_credit_update_test (opts , false);
1398+ }
1399+
12351400static struct test_case test_cases [] = {
12361401 {
12371402 .name = "SOCK_STREAM connection reset" ,
@@ -1342,6 +1507,16 @@ static struct test_case test_cases[] = {
13421507 .run_client = test_double_bind_connect_client ,
13431508 .run_server = test_double_bind_connect_server ,
13441509 },
1510+ {
1511+ .name = "SOCK_STREAM virtio credit update + SO_RCVLOWAT" ,
1512+ .run_client = test_stream_rcvlowat_def_cred_upd_client ,
1513+ .run_server = test_stream_cred_upd_on_set_rcvlowat ,
1514+ },
1515+ {
1516+ .name = "SOCK_STREAM virtio credit update + low rx_bytes" ,
1517+ .run_client = test_stream_rcvlowat_def_cred_upd_client ,
1518+ .run_server = test_stream_cred_upd_on_low_rx_bytes ,
1519+ },
13451520 {},
13461521};
13471522
0 commit comments