hsa: custom proto vfts for vcl tests
[vpp.git] / src / plugins / hs_apps / vcl / vcl_test_protos.c
1 /*
2  * Copyright (c) 2021 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <hs_apps/vcl/vcl_test.h>
17
18 static int
19 vt_tcp_connect (vcl_test_session_t *ts, vppcom_endpt_t *endpt)
20 {
21   uint32_t flags, flen;
22   int rv;
23
24   ts->fd = vppcom_session_create (VPPCOM_PROTO_TCP, 0 /* is_nonblocking */);
25   if (ts->fd < 0)
26     {
27       vterr ("vppcom_session_create()", ts->fd);
28       return ts->fd;
29     }
30
31   /* Connect is blocking */
32   rv = vppcom_session_connect (ts->fd, endpt);
33   if (rv < 0)
34     {
35       vterr ("vppcom_session_connect()", rv);
36       return rv;
37     }
38
39   ts->read = vcl_test_read;
40   ts->write = vcl_test_write;
41   flags = O_NONBLOCK;
42   flen = sizeof (flags);
43   vppcom_session_attr (ts->fd, VPPCOM_ATTR_SET_FLAGS, &flags, &flen);
44   vtinf ("Test session %d (fd %d) connected.", ts->session_index, ts->fd);
45
46   return 0;
47 }
48
49 static int
50 vt_tcp_listen (vcl_test_session_t *ts, vppcom_endpt_t *endpt)
51 {
52   int rv;
53
54   ts->fd = vppcom_session_create (VPPCOM_PROTO_TCP, 0 /* is_nonblocking */);
55   if (ts->fd < 0)
56     {
57       vterr ("vppcom_session_create()", ts->fd);
58       return ts->fd;
59     }
60
61   rv = vppcom_session_bind (ts->fd, endpt);
62   if (rv < 0)
63     {
64       vterr ("vppcom_session_bind()", rv);
65       return rv;
66     }
67
68   rv = vppcom_session_listen (ts->fd, 10);
69   if (rv < 0)
70     {
71       vterr ("vppcom_session_listen()", rv);
72       return rv;
73     }
74
75   return 0;
76 }
77
78 static int
79 vt_tcp_accept (int listen_fd, vcl_test_session_t *ts)
80 {
81   int client_fd;
82
83   client_fd = vppcom_session_accept (listen_fd, &ts->endpt, 0);
84   if (client_fd < 0)
85     {
86       vterr ("vppcom_session_accept()", client_fd);
87       return client_fd;
88     }
89   ts->fd = client_fd;
90   ts->is_open = 1;
91   ts->read = vcl_test_read;
92   ts->write = vcl_test_write;
93
94   return 0;
95 }
96
97 static const vcl_test_proto_vft_t vcl_test_tcp = {
98   .open = vt_tcp_connect,
99   .listen = vt_tcp_listen,
100   .accept = vt_tcp_accept,
101 };
102
103 VCL_TEST_REGISTER_PROTO (VPPCOM_PROTO_TCP, vcl_test_tcp);
104
105 static int
106 vt_udp_connect (vcl_test_session_t *ts, vppcom_endpt_t *endpt)
107 {
108   uint32_t flags, flen;
109   int rv;
110
111   ts->fd = vppcom_session_create (VPPCOM_PROTO_UDP, 0 /* is_nonblocking */);
112   if (ts->fd < 0)
113     {
114       vterr ("vppcom_session_create()", ts->fd);
115       return ts->fd;
116     }
117
118   /* Connect is blocking */
119   rv = vppcom_session_connect (ts->fd, endpt);
120   if (rv < 0)
121     {
122       vterr ("vppcom_session_connect()", rv);
123       return rv;
124     }
125
126   ts->read = vcl_test_read;
127   ts->write = vcl_test_write;
128   flags = O_NONBLOCK;
129   flen = sizeof (flags);
130   vppcom_session_attr (ts->fd, VPPCOM_ATTR_SET_FLAGS, &flags, &flen);
131   vtinf ("Test session %d (fd %d) connected.", ts->session_index, ts->fd);
132
133   return 0;
134 }
135
136 static int
137 vt_udp_listen (vcl_test_session_t *ts, vppcom_endpt_t *endpt)
138 {
139   int rv;
140
141   ts->fd = vppcom_session_create (VPPCOM_PROTO_UDP, 0 /* is_nonblocking */);
142   if (ts->fd < 0)
143     {
144       vterr ("vppcom_session_create()", ts->fd);
145       return ts->fd;
146     }
147
148   vppcom_session_attr (ts->fd, VPPCOM_ATTR_SET_CONNECTED, 0, 0);
149
150   /* Listen is implicit */
151   rv = vppcom_session_bind (ts->fd, endpt);
152   if (rv < 0)
153     {
154       vterr ("vppcom_session_bind()", rv);
155       return rv;
156     }
157
158   return 0;
159 }
160
161 static int
162 vt_udp_accept (int listen_fd, vcl_test_session_t *ts)
163 {
164   int client_fd;
165
166   client_fd = vppcom_session_accept (listen_fd, &ts->endpt, 0);
167   if (client_fd < 0)
168     {
169       vterr ("vppcom_session_accept()", client_fd);
170       return client_fd;
171     }
172   ts->fd = client_fd;
173   ts->is_open = 1;
174   ts->read = vcl_test_read;
175   ts->write = vcl_test_write;
176
177   return 0;
178 }
179
180 static const vcl_test_proto_vft_t vcl_test_udp = {
181   .open = vt_udp_connect,
182   .listen = vt_udp_listen,
183   .accept = vt_udp_accept,
184 };
185
186 VCL_TEST_REGISTER_PROTO (VPPCOM_PROTO_UDP, vcl_test_udp);
187
188 /*
189  * TLS server cert and keys to be used for testing only
190  */
191 static char vcl_test_crt_rsa[] =
192   "-----BEGIN CERTIFICATE-----\r\n"
193   "MIID5zCCAs+gAwIBAgIJALeMYCEHrTtJMA0GCSqGSIb3DQEBCwUAMIGJMQswCQYD\r\n"
194   "VQQGEwJVUzELMAkGA1UECAwCQ0ExETAPBgNVBAcMCFNhbiBKb3NlMQ4wDAYDVQQK\r\n"
195   "DAVDaXNjbzEOMAwGA1UECwwFZmQuaW8xFjAUBgNVBAMMDXRlc3R0bHMuZmQuaW8x\r\n"
196   "IjAgBgkqhkiG9w0BCQEWE3ZwcC1kZXZAbGlzdHMuZmQuaW8wHhcNMTgwMzA1MjEx\r\n"
197   "NTEyWhcNMjgwMzAyMjExNTEyWjCBiTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNB\r\n"
198   "MREwDwYDVQQHDAhTYW4gSm9zZTEOMAwGA1UECgwFQ2lzY28xDjAMBgNVBAsMBWZk\r\n"
199   "LmlvMRYwFAYDVQQDDA10ZXN0dGxzLmZkLmlvMSIwIAYJKoZIhvcNAQkBFhN2cHAt\r\n"
200   "ZGV2QGxpc3RzLmZkLmlvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\r\n"
201   "4C1k8a1DuStgggqT4o09fP9sJ2dC54bxhS/Xk2VEfaIZ222WSo4X/syRVfVy9Yah\r\n"
202   "cpI1zJ/RDxaZSFhgA+nPZBrFMsrULkrdAOpOVj8eDEp9JuWdO2ODSoFnCvLxcYWB\r\n"
203   "Yc5kHryJpEaGJl1sFQSesnzMFty/59ta0stk0Fp8r5NhIjWvSovGzPo6Bhz+VS2c\r\n"
204   "ebIZh4x1t2hHaFcgm0qJoJ6DceReWCW8w+yOVovTolGGq+bpb2Hn7MnRSZ2K2NdL\r\n"
205   "+aLXpkZbS/AODP1FF2vTO1mYL290LO7/51vJmPXNKSDYMy5EvILr5/VqtjsFCwRL\r\n"
206   "Q4jcM/+GeHSAFWx4qIv0BwIDAQABo1AwTjAdBgNVHQ4EFgQUWa1SOB37xmT53tZQ\r\n"
207   "aXuLLhRI7U8wHwYDVR0jBBgwFoAUWa1SOB37xmT53tZQaXuLLhRI7U8wDAYDVR0T\r\n"
208   "BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAoUht13W4ya27NVzQuCMvqPWL3VM4\r\n"
209   "3xbPFk02FaGz/WupPu276zGlzJAZrbuDcQowwwU1Ni1Yygxl96s1c2M5rHDTrOKG\r\n"
210   "rK0hbkSFBo+i6I8u4HiiQ4rYmG0Hv6+sXn3of0HsbtDPGgWZoipPWDljPYEURu3e\r\n"
211   "3HRe/Dtsj9CakBoSDzs8ndWaBR+f4sM9Tk1cjD46Gq2T/qpSPXqKxEUXlzhdCAn4\r\n"
212   "twub17Bq2kykHpppCwPg5M+v30tHG/R2Go15MeFWbEJthFk3TZMjKL7UFs7fH+x2\r\n"
213   "wSonXb++jY+KmCb93C+soABBizE57g/KmiR2IxQ/LMjDik01RSUIaM0lLA==\r\n"
214   "-----END CERTIFICATE-----\r\n";
215 static uint32_t vcl_test_crt_rsa_len = sizeof (vcl_test_crt_rsa);
216
217 static char vcl_test_key_rsa[] =
218   "-----BEGIN PRIVATE KEY-----\r\n"
219   "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDgLWTxrUO5K2CC\r\n"
220   "CpPijT18/2wnZ0LnhvGFL9eTZUR9ohnbbZZKjhf+zJFV9XL1hqFykjXMn9EPFplI\r\n"
221   "WGAD6c9kGsUyytQuSt0A6k5WPx4MSn0m5Z07Y4NKgWcK8vFxhYFhzmQevImkRoYm\r\n"
222   "XWwVBJ6yfMwW3L/n21rSy2TQWnyvk2EiNa9Ki8bM+joGHP5VLZx5shmHjHW3aEdo\r\n"
223   "VyCbSomgnoNx5F5YJbzD7I5Wi9OiUYar5ulvYefsydFJnYrY10v5otemRltL8A4M\r\n"
224   "/UUXa9M7WZgvb3Qs7v/nW8mY9c0pINgzLkS8guvn9Wq2OwULBEtDiNwz/4Z4dIAV\r\n"
225   "bHioi/QHAgMBAAECggEBAMzGipP8+oT166U+NlJXRFifFVN1DvdhG9PWnOxGL+c3\r\n"
226   "ILmBBC08WQzmHshPemBvR6DZkA1H23cV5JTiLWrFtC00CvhXsLRMrE5+uWotI6yE\r\n"
227   "iofybMroHvD6/X5R510UX9hQ6MHu5ShLR5VZ9zXHz5MpTmB/60jG5dLx+jgcwBK8\r\n"
228   "LuGv2YB/WCUwT9QJ3YU2eaingnXtz/MrFbkbltrqlnBdlD+kTtw6Yac9y1XuuQXc\r\n"
229   "BPeulLNDuPolJVWbUvDBZrpt2dXTgz8ws1sv+wCNE0xwQJsqW4Nx3QkpibUL9RUr\r\n"
230   "CVbKlNfa9lopT6nGKlgX69R/uH35yh9AOsfasro6w0ECgYEA82UJ8u/+ORah+0sF\r\n"
231   "Q0FfW5MTdi7OAUHOz16pUsGlaEv0ERrjZxmAkHA/VRwpvDBpx4alCv0Hc39PFLIk\r\n"
232   "nhSsM2BEuBkTAs6/GaoNAiBtQVE/hN7awNRWVmlieS0go3Y3dzaE9IUMyj8sPOFT\r\n"
233   "5JdJ6BM69PHKCkY3dKdnnfpFEuECgYEA68mRpteunF1mdZgXs+WrN+uLlRrQR20F\r\n"
234   "ZyMYiUCH2Dtn26EzA2moy7FipIIrQcX/j+KhYNGM3e7MU4LymIO29E18mn8JODnH\r\n"
235   "sQOXzBTsf8A4yIVMkcuQD3bfb0JiUGYUPOidTp2N7IJA7+6Yc3vQOyb74lnKnJoO\r\n"
236   "gougPT2wS+cCgYAn7muzb6xFsXDhyW0Tm6YJYBfRS9yAWEuVufINobeBZPSl2cN1\r\n"
237   "Jrnw+HlrfTNbrJWuJmjtZJXUXQ6cVp2rUbjutNyRV4vG6iRwEXYQ40EJdkr1gZpi\r\n"
238   "CHQhuShuuPih2MNAy7EEbM+sXrDjTBR3bFqzuHPzu7dp+BshCFX3lRfAAQKBgGQt\r\n"
239   "K5i7IhCFDjb/+3IPLgOAK7mZvsvZ4eXD33TQ2eZgtut1PXtBtNl17/b85uv293Fm\r\n"
240   "VDISVcsk3eLNS8zIiT6afUoWlxAwXEs0v5WRfjl4radkGvgGiJpJYvyeM67877RB\r\n"
241   "EDSKc/X8ESLfOB44iGvZUEMG6zJFscx9DgN25iQZAoGAbyd+JEWwdVH9/K3IH1t2\r\n"
242   "PBkZX17kNWv+iVM1WyFjbe++vfKZCrOJiyiqhDeEqgrP3AuNMlaaduC3VRC3G5oV\r\n"
243   "Mj1tlhDWQ/qhvKdCKNdIVQYDE75nw+FRWV8yYkHAnXYW3tNoweDIwixE0hkPR1bc\r\n"
244   "oEjPLVNtx8SOj/M4rhaPT3I=\r\n"
245   "-----END PRIVATE KEY-----\r\n";
246 static uint32_t vcl_test_key_rsa_len = sizeof (vcl_test_key_rsa);
247
248 static int
249 vt_add_cert_key_pair ()
250 {
251   vcl_test_main_t *vt = &vcl_test_main;
252   vppcom_cert_key_pair_t ckpair;
253   int ckp_index;
254
255   vtinf ("Adding tls certs ...");
256
257   ckpair.cert = vcl_test_crt_rsa;
258   ckpair.key = vcl_test_key_rsa;
259   ckpair.cert_len = vcl_test_crt_rsa_len;
260   ckpair.key_len = vcl_test_key_rsa_len;
261   ckp_index = vppcom_add_cert_key_pair (&ckpair);
262   if (ckp_index < 0)
263     {
264       vterr ("vppcom_add_cert_key_pair()", ckp_index);
265       return ckp_index;
266     }
267
268   vt->ckpair_index = ckp_index;
269   return 0;
270 }
271
272 static int
273 vt_tls_init (vcl_test_cfg_t *cfg)
274 {
275   return vt_add_cert_key_pair ();
276 }
277
278 static int
279 vt_tls_connect (vcl_test_session_t *ts, vppcom_endpt_t *endpt)
280 {
281   vcl_test_main_t *vt = &vcl_test_main;
282   uint32_t flags, flen;
283   int rv;
284
285   ts->fd = vppcom_session_create (VPPCOM_PROTO_TLS, 0 /* is_nonblocking */);
286   if (ts->fd < 0)
287     {
288       vterr ("vppcom_session_create()", ts->fd);
289       return ts->fd;
290     }
291
292   uint32_t ckp_len = sizeof (vt->ckpair_index);
293   vppcom_session_attr (ts->fd, VPPCOM_ATTR_SET_CKPAIR, &vt->ckpair_index,
294                        &ckp_len);
295
296   /* Connect is blocking */
297   rv = vppcom_session_connect (ts->fd, endpt);
298   if (rv < 0)
299     {
300       vterr ("vppcom_session_connect()", rv);
301       return rv;
302     }
303
304   ts->read = vcl_test_read;
305   ts->write = vcl_test_write;
306   flags = O_NONBLOCK;
307   flen = sizeof (flags);
308   vppcom_session_attr (ts->fd, VPPCOM_ATTR_SET_FLAGS, &flags, &flen);
309   vtinf ("Test session %d (fd %d) connected.", ts->session_index, ts->fd);
310
311   return 0;
312 }
313
314 static int
315 vt_tls_listen (vcl_test_session_t *ts, vppcom_endpt_t *endpt)
316 {
317   vcl_test_main_t *vt = &vcl_test_main;
318   uint32_t ckp_len;
319   int rv;
320
321   ts->fd = vppcom_session_create (VPPCOM_PROTO_TLS, 0 /* is_nonblocking */);
322   if (ts->fd < 0)
323     {
324       vterr ("vppcom_session_create()", ts->fd);
325       return ts->fd;
326     }
327
328   ckp_len = sizeof (vt->ckpair_index);
329   vppcom_session_attr (ts->fd, VPPCOM_ATTR_SET_CKPAIR, &vt->ckpair_index,
330                        &ckp_len);
331
332   rv = vppcom_session_bind (ts->fd, endpt);
333   if (rv < 0)
334     {
335       vterr ("vppcom_session_bind()", rv);
336       return rv;
337     }
338
339   rv = vppcom_session_listen (ts->fd, 10);
340   if (rv < 0)
341     {
342       vterr ("vppcom_session_listen()", rv);
343       return rv;
344     }
345
346   return 0;
347 }
348
349 static int
350 vt_tls_accept (int listen_fd, vcl_test_session_t *ts)
351 {
352   int client_fd;
353
354   client_fd = vppcom_session_accept (listen_fd, &ts->endpt, 0);
355   if (client_fd < 0)
356     {
357       vterr ("vppcom_session_accept()", client_fd);
358       return client_fd;
359     }
360   ts->fd = client_fd;
361   ts->is_open = 1;
362   ts->read = vcl_test_read;
363   ts->write = vcl_test_write;
364
365   return 0;
366 }
367
368 static const vcl_test_proto_vft_t vcl_test_tls = {
369   .init = vt_tls_init,
370   .open = vt_tls_connect,
371   .listen = vt_tls_listen,
372   .accept = vt_tls_accept,
373 };
374
375 VCL_TEST_REGISTER_PROTO (VPPCOM_PROTO_TLS, vcl_test_tls);
376
377 static int
378 vt_dtls_init (vcl_test_cfg_t *cfg)
379 {
380   return vt_add_cert_key_pair ();
381 }
382
383 static int
384 vt_dtls_connect (vcl_test_session_t *ts, vppcom_endpt_t *endpt)
385 {
386   vcl_test_main_t *vt = &vcl_test_main;
387   uint32_t flags, flen;
388   int rv;
389
390   ts->fd = vppcom_session_create (VPPCOM_PROTO_DTLS, 0 /* is_nonblocking */);
391   if (ts->fd < 0)
392     {
393       vterr ("vppcom_session_create()", ts->fd);
394       return ts->fd;
395     }
396
397   uint32_t ckp_len = sizeof (vt->ckpair_index);
398   vppcom_session_attr (ts->fd, VPPCOM_ATTR_SET_CKPAIR, &vt->ckpair_index,
399                        &ckp_len);
400
401   /* Connect is blocking */
402   rv = vppcom_session_connect (ts->fd, endpt);
403   if (rv < 0)
404     {
405       vterr ("vppcom_session_connect()", rv);
406       return rv;
407     }
408
409   ts->read = vcl_test_read;
410   ts->write = vcl_test_write;
411   flags = O_NONBLOCK;
412   flen = sizeof (flags);
413   vppcom_session_attr (ts->fd, VPPCOM_ATTR_SET_FLAGS, &flags, &flen);
414   vtinf ("Test session %d (fd %d) connected.", ts->session_index, ts->fd);
415
416   return 0;
417 }
418
419 static int
420 vt_dtls_listen (vcl_test_session_t *ts, vppcom_endpt_t *endpt)
421 {
422   vcl_test_main_t *vt = &vcl_test_main;
423   uint32_t ckp_len;
424   int rv;
425
426   ts->fd = vppcom_session_create (VPPCOM_PROTO_DTLS, 0 /* is_nonblocking */);
427   if (ts->fd < 0)
428     {
429       vterr ("vppcom_session_create()", ts->fd);
430       return ts->fd;
431     }
432
433   ckp_len = sizeof (vt->ckpair_index);
434   vppcom_session_attr (ts->fd, VPPCOM_ATTR_SET_CKPAIR, &vt->ckpair_index,
435                        &ckp_len);
436
437   rv = vppcom_session_bind (ts->fd, endpt);
438   if (rv < 0)
439     {
440       vterr ("vppcom_session_bind()", rv);
441       return rv;
442     }
443
444   rv = vppcom_session_listen (ts->fd, 10);
445   if (rv < 0)
446     {
447       vterr ("vppcom_session_listen()", rv);
448       return rv;
449     }
450
451   return 0;
452 }
453
454 static int
455 vt_dtls_accept (int listen_fd, vcl_test_session_t *ts)
456 {
457   int client_fd;
458
459   client_fd = vppcom_session_accept (listen_fd, &ts->endpt, 0);
460   if (client_fd < 0)
461     {
462       vterr ("vppcom_session_accept()", client_fd);
463       return client_fd;
464     }
465   ts->fd = client_fd;
466   ts->is_open = 1;
467   ts->read = vcl_test_read;
468   ts->write = vcl_test_write;
469
470   return 0;
471 }
472
473 static const vcl_test_proto_vft_t vcl_test_dtls = {
474   .init = vt_dtls_init,
475   .open = vt_dtls_connect,
476   .listen = vt_dtls_listen,
477   .accept = vt_dtls_accept,
478 };
479
480 VCL_TEST_REGISTER_PROTO (VPPCOM_PROTO_DTLS, vcl_test_dtls);
481
482 static int
483 vt_quic_init (vcl_test_cfg_t *cfg)
484 {
485   vcl_test_main_t *vt = &vcl_test_main;
486
487   if (cfg)
488     vt->cfg = *cfg;
489
490   return vt_add_cert_key_pair ();
491 }
492
493 static int
494 vt_quic_maybe_init_wrk (vcl_test_main_t *vt, vcl_test_wrk_t *wrk,
495                         vppcom_endpt_t *endpt)
496 {
497   uint32_t size, i, flags, flen;
498   vcl_test_session_t *tq;
499   int rv;
500
501   /* Test already initialized */
502   if (wrk->n_qsessions == vt->cfg.num_test_qsessions)
503     return 0;
504
505   /* Make sure pool is large enough */
506   if (!wrk->qsessions)
507     {
508       wrk->qsessions =
509         calloc (vt->cfg.num_test_qsessions, sizeof (vcl_test_session_t));
510     }
511   else
512     {
513       size = vt->cfg.num_test_qsessions * sizeof (vcl_test_session_t);
514       wrk->qsessions = realloc (wrk->qsessions, size);
515     }
516
517   if (!wrk->qsessions)
518     {
519       vterr ("failed to alloc Qsessions", -errno);
520       return errno;
521     }
522
523   for (i = 0; i < vt->cfg.num_test_qsessions; i++)
524     {
525       tq = &wrk->qsessions[i];
526       tq->fd =
527         vppcom_session_create (VPPCOM_PROTO_QUIC, 0 /* is_nonblocking */);
528       tq->session_index = i;
529       if (tq->fd < 0)
530         {
531           vterr ("vppcom_session_create()", tq->fd);
532           return tq->fd;
533         }
534
535       /* Connect is blocking */
536       rv = vppcom_session_connect (tq->fd, endpt);
537       if (rv < 0)
538         {
539           vterr ("vppcom_session_connect()", rv);
540           return rv;
541         }
542       flags = O_NONBLOCK;
543       flen = sizeof (flags);
544       vppcom_session_attr (tq->fd, VPPCOM_ATTR_SET_FLAGS, &flags, &flen);
545       vtinf ("Test Qsession %d (fd %d) connected.", i, tq->fd);
546     }
547   wrk->n_qsessions = vt->cfg.num_test_qsessions;
548
549   return 0;
550 }
551
552 static int
553 vt_quic_connect (vcl_test_session_t *ts, vppcom_endpt_t *endpt)
554 {
555   vcl_test_main_t *vt = &vcl_test_main;
556   vcl_test_session_t *tq;
557   vcl_test_wrk_t *wrk;
558   uint32_t wrk_index;
559   int rv;
560
561   wrk_index = vcl_test_worker_index ();
562   wrk = &vt->wrk[wrk_index];
563
564   /* Make sure qsessions are initialized */
565   vt_quic_maybe_init_wrk (vt, wrk, endpt);
566
567   ts->fd = vppcom_session_create (VPPCOM_PROTO_QUIC, 1 /* is_nonblocking */);
568   if (ts->fd < 0)
569     {
570       vterr ("vppcom_session_create()", ts->fd);
571       return ts->fd;
572     }
573
574   /* Choose qession to use for stream */
575   tq = &wrk->qsessions[ts->session_index / vt->cfg.num_test_sessions_perq];
576
577   rv = vppcom_session_stream_connect (ts->fd, tq->fd);
578   if (rv < 0)
579     {
580       vterr ("vppcom_session_stream_connect()", rv);
581       return rv;
582     }
583
584   vtinf ("Test session %d (fd %d) connected.", ts->session_index, ts->fd);
585
586   return 0;
587 }
588
589 static int
590 vt_quic_listen (vcl_test_session_t *ts, vppcom_endpt_t *endpt)
591 {
592   vcl_test_main_t *vt = &vcl_test_main;
593   uint32_t ckp_len;
594   int rv;
595
596   ts->fd = vppcom_session_create (VPPCOM_PROTO_QUIC, 0 /* is_nonblocking */);
597   if (ts->fd < 0)
598     {
599       vterr ("vppcom_session_create()", ts->fd);
600       return ts->fd;
601     }
602
603   ckp_len = sizeof (vt->ckpair_index);
604   vppcom_session_attr (ts->fd, VPPCOM_ATTR_SET_CKPAIR, &vt->ckpair_index,
605                        &ckp_len);
606
607   rv = vppcom_session_bind (ts->fd, endpt);
608   if (rv < 0)
609     {
610       vterr ("vppcom_session_bind()", rv);
611       return rv;
612     }
613
614   rv = vppcom_session_listen (ts->fd, 10);
615   if (rv < 0)
616     {
617       vterr ("vppcom_session_listen()", rv);
618       return rv;
619     }
620
621   return 0;
622 }
623
624 static int
625 vt_quic_accept (int listen_fd, vcl_test_session_t *ts)
626 {
627   int client_fd;
628
629   client_fd = vppcom_session_accept (listen_fd, &ts->endpt, 0);
630   if (client_fd < 0)
631     {
632       vterr ("vppcom_session_accept()", client_fd);
633       return client_fd;
634     }
635   ts->fd = client_fd;
636   ts->is_open = 1;
637   ts->read = vcl_test_read;
638   ts->write = vcl_test_write;
639
640   return 0;
641 }
642
643 static int
644 vt_quic_close (vcl_test_session_t *ts)
645 {
646   int listener_fd = vppcom_session_listener (ts->fd);
647
648   if ((vppcom_session_n_accepted (listener_fd) == 0) &
649       vppcom_session_is_connectable_listener (listener_fd))
650     {
651       vtinf ("Connected Listener fd %x has no more sessions", listener_fd);
652       vppcom_session_close (listener_fd);
653     }
654
655   return 0;
656 }
657
658 static const vcl_test_proto_vft_t vcl_test_quic = {
659   .init = vt_quic_init,
660   .open = vt_quic_connect,
661   .listen = vt_quic_listen,
662   .accept = vt_quic_accept,
663   .close = vt_quic_close,
664 };
665
666 VCL_TEST_REGISTER_PROTO (VPPCOM_PROTO_QUIC, vcl_test_quic);
667
668 /*
669  * fd.io coding-style-patch-verification: ON
670  *
671  * Local Variables:
672  * eval: (c-set-style "gnu")
673  * End:
674  */