blob: e68f69ddaf001758187c29fead9b42a608e0b782 [file] [log] [blame]
Jakub Grajciare74c04f2021-01-04 11:28:33 +01001/*
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
35memif_connection_t intf0, intf1;
36int is_reverse;
37int epfd;
38
39int
40packet_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 */
56int
57on_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 */
91int
92on_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
109int
110verify_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
142done:
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
156int
157create_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
182void
183print_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
217int
218main (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
298error:
299 ret = -1;
300done:
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}