misc: VPP 22.06.1 Release Notes
[vpp.git] / extras / libmemif / examples / loopback / main.c
1 /*
2  *------------------------------------------------------------------
3  * Copyright (c) 2020 Cisco and/or its affiliates.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *------------------------------------------------------------------
16  */
17
18 #include <stdlib.h>
19 #include <sys/types.h>
20 #include <inttypes.h>
21 #include <string.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <unistd.h>
26 #include <getopt.h>
27
28 #include <libmemif.h>
29 #include <common.h>
30
31 #define APP_NAME "loopback_example"
32 #define IF0_NAME "lo0"
33 #define IF1_NAME "lo1"
34
35 memif_connection_t intf0, intf1;
36 int is_reverse;
37 int epfd;
38
39 int
40 packet_generator (memif_connection_t *c, uint16_t num_pkts)
41 {
42   int i, bi = 0;
43   memif_buffer_t *mb;
44
45   for (i = 0; (i < num_pkts) && (bi < c->tx_buf_num); i++)
46     {
47       mb = &c->tx_bufs[bi++];
48       memset (mb->data, 1, mb->len);
49     }
50
51   return 0;
52 }
53
54 /* informs user about connected status. private_ctx is used by user to identify
55  * connection */
56 int
57 on_connect (memif_conn_handle_t conn, void *private_ctx)
58 {
59   INFO ("memif connected!");
60   int err;
61
62   memif_connection_t *c = (memif_connection_t *) private_ctx;
63
64   c->is_connected = 1;
65   alloc_memif_buffers (c);
66
67   err = memif_refill_queue (conn, 0, -1, 0);
68   if (err != MEMIF_ERR_SUCCESS)
69     {
70       INFO ("memif_refill_queue: %s", memif_strerror (err));
71       return err;
72     }
73
74   print_memif_details (c);
75
76   /* Once both interfaces are connected send a test packet, master -> slave.
77    * Slave will use zero-copy method to reply the same pakcet back.
78    * (Configured by assigning responder_zero_copy as on_interrupt callback.)
79    */
80   if ((intf0.is_connected == 1) && (intf1.is_connected == 1))
81     {
82       send_packets (is_reverse ? &intf1 : &intf0, 0, packet_generator, 1,
83                     2048);
84     }
85
86   return 0;
87 }
88
89 /* informs user about disconnected status. private_ctx is used by user to
90  * identify connection */
91 int
92 on_disconnect (memif_conn_handle_t conn, void *private_ctx)
93 {
94   INFO ("memif disconnected!");
95
96   memif_connection_t *c = (memif_connection_t *) private_ctx;
97
98   c->is_connected = 0;
99   free_memif_buffers (c);
100
101   /* stop event polling thread */
102   int err = memif_cancel_poll_event (memif_get_socket_handle (conn));
103   if (err != MEMIF_ERR_SUCCESS)
104     INFO ("We are doomed...");
105
106   return 0;
107 }
108
109 int
110 verify_packet (memif_conn_handle_t conn, void *private_ctx, uint16_t qid)
111 {
112   memif_connection_t *c = (memif_connection_t *) private_ctx;
113   int err;
114   void *want;
115
116   err = memif_rx_burst (conn, qid, c->rx_bufs, MAX_MEMIF_BUFS, &c->rx_buf_num);
117   if (err != MEMIF_ERR_SUCCESS)
118     {
119       INFO ("meif_rx_burst: %s", memif_strerror (err));
120       return err;
121     }
122
123   want = malloc (c->rx_bufs[0].len);
124   if (want == NULL)
125     {
126       INFO ("Out of memory");
127       goto done;
128     }
129
130   memset (want, 1, c->rx_bufs[0].len);
131
132   err = memcmp (c->rx_bufs[0].data, want, c->rx_bufs[0].len);
133   if (err != 0)
134     {
135       INFO ("Received malformed data. ret: %d", err);
136     }
137   else
138     {
139       INFO ("Received correct data.");
140     }
141
142 done:
143   err = memif_refill_queue (conn, qid, c->rx_buf_num, 0);
144   if (err != MEMIF_ERR_SUCCESS)
145     INFO ("memif_refill_queue: %s", memif_strerror (err));
146
147   /* stop polling and exit the program */
148   INFO ("Stopping the program");
149   err = memif_cancel_poll_event (memif_get_socket_handle (conn));
150   if (err != MEMIF_ERR_SUCCESS)
151     INFO ("We are doomed...");
152
153   return err;
154 }
155
156 int
157 create_memif_interface (memif_socket_handle_t memif_socket,
158                         const char *if_name, int id, uint8_t is_master,
159                         memif_connection_t *ctx)
160 {
161   memif_conn_args_t memif_conn_args = { 0 };
162   int err;
163
164   memif_conn_args.socket = memif_socket;
165   memif_conn_args.interface_id = id;
166   strncpy (memif_conn_args.interface_name, if_name,
167            sizeof (memif_conn_args.interface_name));
168   memif_conn_args.is_master = is_master;
169
170   err = memif_create (&ctx->conn, &memif_conn_args, on_connect, on_disconnect,
171                       is_master ? verify_packet : responder_zero_copy,
172                       (void *) ctx);
173   if (err != MEMIF_ERR_SUCCESS)
174     {
175       INFO ("memif_create_socket: %s", memif_strerror (err));
176       return err;
177     }
178
179   return 0;
180 }
181
182 void
183 print_help ()
184 {
185   printf ("LIBMEMIF EXAMPLE APP: %s", APP_NAME);
186 #ifdef ICMP_DBG
187   printf (" (debug)");
188 #endif
189   printf ("\n");
190   printf ("==============================\n");
191   printf ("libmemif version: %s", LIBMEMIF_VERSION);
192 #ifdef MEMIF_DBG
193   printf (" (debug)");
194 #endif
195   printf ("\n");
196
197   printf ("memif version: %s\n", memif_get_version_str ());
198   printf ("==============================\n");
199   printf ("In this example, two memif endpoints are connected to create a "
200           "loopback.\n");
201   printf ("Once connected, a test packet is sent out the memif master "
202           "interface to\n");
203   printf (
204     "the memif slave interface, which replies with the same packet in a\n");
205   printf ("zero-copy way.\n");
206   printf (
207     "In reverse mode, the packet is sent from the slave interface and is\n");
208   printf ("looped back by the master interface.\n");
209   printf ("==============================\n");
210   printf ("Usage: loopback [OPTIONS]\n\n");
211   printf ("Options:\n");
212   printf ("\t-r\tReverse mode, verification packet is sent by slave.\n");
213   printf ("\t-?\tShow help and exit.\n");
214   printf ("\t-v\tShow libmemif and memif version information and exit.\n");
215 }
216
217 int
218 main (int argc, char *argv[])
219 {
220   memif_socket_args_t memif_socket_args = { 0 };
221   memif_socket_handle_t memif_socket;
222   int opt, err, ret = 0;
223   is_reverse = 0;
224
225   while ((opt = getopt (argc, argv, "r?v")) != -1)
226     {
227       switch (opt)
228         {
229         case 'r':
230           is_reverse = 1;
231           break;
232         case '?':
233           print_help ();
234           return 0;
235         case 'v':
236           print_version ();
237           return 0;
238         }
239     }
240
241   /** Create memif socket
242    *
243    * Interfaces are internally stored in a database referenced by memif socket.
244    */
245   /* Abstract socket supported */
246   memif_socket_args.path[0] = '@';
247   strncpy (memif_socket_args.path + 1, APP_NAME, strlen (APP_NAME));
248   /* Set application name */
249   strncpy (memif_socket_args.app_name, APP_NAME, strlen (APP_NAME));
250
251   err = memif_create_socket (&memif_socket, &memif_socket_args, NULL);
252   if (err != MEMIF_ERR_SUCCESS)
253     {
254       INFO ("memif_create_socket: %s", memif_strerror (err));
255       goto error;
256     }
257
258   /** Create memif interfaces
259    *
260    * Both interaces are assigned the same socket and same id to create a
261    * loopback.
262    */
263
264   /* prepare the private data */
265   memset (&intf0, 0, sizeof (intf0));
266   memset (&intf1, 0, sizeof (intf1));
267   if (is_reverse)
268     {
269       intf0.packet_handler = basic_packet_handler;
270     }
271   else
272     {
273       intf1.packet_handler = basic_packet_handler;
274     }
275
276   err =
277     create_memif_interface (memif_socket, IF0_NAME, 0, /* master */ 1, &intf0);
278   if (err != 0)
279     {
280       goto error;
281     }
282
283   err =
284     create_memif_interface (memif_socket, IF1_NAME, 0, /* slave */ 0, &intf1);
285   if (err != 0)
286     {
287       goto error;
288     }
289
290   do
291     {
292       err = memif_poll_event (memif_socket, -1);
293     }
294   while (err == MEMIF_ERR_SUCCESS);
295
296   return 0;
297
298 error:
299   ret = -1;
300 done:
301   free_memif_buffers (&intf0);
302   free_memif_buffers (&intf1);
303   memif_delete (&intf0.conn);
304   memif_delete (&intf1.conn);
305   memif_delete_socket (&memif_socket);
306   return ret;
307 }