aeaeaca613318ac5bde6f341bb3490b3ee1ea661
[cascardo/ovs.git] / tests / dpdk / ring_client.c
1 /*
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  */
34
35 #include <getopt.h>
36
37 #include <config.h>
38 #include <rte_config.h>
39 #include <rte_mbuf.h>
40 #include <rte_ether.h>
41 #include <rte_string_fns.h>
42 #include <rte_ip.h>
43 #include <rte_byteorder.h>
44
45 /* Number of packets to attempt to read from queue. */
46 #define PKT_READ_SIZE  ((uint16_t)32)
47
48 /* Define common names for structures shared between ovs_dpdk and client. */
49 #define MP_CLIENT_RXQ_NAME "dpdkr%u_tx"
50 #define MP_CLIENT_TXQ_NAME "dpdkr%u_rx"
51
52 #define RTE_LOGTYPE_APP RTE_LOGTYPE_USER1
53
54 #define BASE_10 10
55
56 /* Our client id number - tells us which rx queue to read, and tx
57  * queue to write to.
58  */
59 static uint8_t client_id = 0;
60
61 /*
62  * Given the rx queue name template above, get the queue name.
63  */
64 static inline const char *
65 get_rx_queue_name(unsigned id)
66 {
67     /* Buffer for return value. Size calculated by %u being replaced
68      * by maximum 3 digits (plus an extra byte for safety).
69      */
70     static char buffer[sizeof(MP_CLIENT_RXQ_NAME) + 2];
71
72     snprintf(buffer, sizeof(buffer) - 1, MP_CLIENT_RXQ_NAME, id);
73     return buffer;
74 }
75
76 /*
77  * Given the tx queue name template above, get the queue name.
78  */
79 static inline const char *
80 get_tx_queue_name(unsigned id)
81 {
82     /* Buffer for return value. Size calculated by %u being replaced
83      * by maximum 3 digits (plus an extra byte for safety).
84      */
85     static char buffer[sizeof(MP_CLIENT_TXQ_NAME) + 2];
86
87     snprintf(buffer, sizeof(buffer) - 1, MP_CLIENT_TXQ_NAME, id);
88     return buffer;
89 }
90
91 /*
92  * Print a usage message.
93  */
94 static void
95 usage(const char *progname)
96 {
97     printf("\nUsage: %s [EAL args] -- -n <client_id>\n", progname);
98 }
99
100 /*
101  * Convert the client id number from a string to an int.
102  */
103 static int
104 parse_client_num(const char *client)
105 {
106     char *end = NULL;
107     unsigned long temp = 0;
108
109     if (client == NULL || *client == '\0') {
110         return -1;
111     }
112
113     temp = strtoul(client, &end, BASE_10);
114     /* If valid string argument is provided, terminating '/0' character
115      * is stored in 'end'. */
116     if (end == NULL || *end != '\0') {
117         return -1;
118     }
119
120     client_id = (uint8_t)temp;
121     return 0;
122 }
123
124 /*
125  * Parse the application arguments to the client app.
126  */
127 static int
128 parse_app_args(int argc, char *argv[])
129 {
130     int option_index = 0, opt = 0;
131     char **argvopt = argv;
132     const char *progname = NULL;
133     static struct option lgopts[] = {
134         {NULL, 0, NULL, 0 }
135     };
136     progname = argv[0];
137
138     while ((opt = getopt_long(argc, argvopt, "n:", lgopts,
139         &option_index)) != EOF) {
140         switch (opt) {
141             case 'n':
142                 if (parse_client_num(optarg) != 0) {
143                     usage(progname);
144                     return -1;
145                 }
146                 break;
147             default:
148                 usage(progname);
149                 return -1;
150         }
151     }
152
153     return 0;
154 }
155
156 /*
157  * Application main function - loops through
158  * receiving and processing packets. Never returns
159  */
160 int
161 main(int argc, char *argv[])
162 {
163     struct rte_ring *rx_ring = NULL;
164     struct rte_ring *tx_ring = NULL;
165     int retval = 0;
166     void *pkts[PKT_READ_SIZE];
167     int rslt = 0;
168
169     if ((retval = rte_eal_init(argc, argv)) < 0) {
170         return -1;
171     }
172
173     argc -= retval;
174     argv += retval;
175
176     if (parse_app_args(argc, argv) < 0) {
177         rte_exit(EXIT_FAILURE, "Invalid command-line arguments\n");
178     }
179
180     rx_ring = rte_ring_lookup(get_rx_queue_name(client_id));
181     if (rx_ring == NULL) {
182         rte_exit(EXIT_FAILURE,
183             "Cannot get RX ring - is server process running?\n");
184     }
185
186     tx_ring = rte_ring_lookup(get_tx_queue_name(client_id));
187     if (tx_ring == NULL) {
188         rte_exit(EXIT_FAILURE,
189             "Cannot get TX ring - is server process running?\n");
190     }
191
192     RTE_LOG(INFO, APP, "Finished Process Init.\n");
193
194     printf("\nClient process %d handling packets\n", client_id);
195     printf("[Press Ctrl-C to quit ...]\n");
196
197     for (;;) {
198         unsigned rx_pkts = PKT_READ_SIZE;
199
200         /* Try dequeuing max possible packets first, if that fails, get the
201          * most we can. Loop body should only execute once, maximum.
202          */
203         while (unlikely(rte_ring_dequeue_bulk(rx_ring, pkts, rx_pkts) != 0) &&
204             rx_pkts > 0) {
205             rx_pkts = (uint16_t)RTE_MIN(rte_ring_count(rx_ring), PKT_READ_SIZE);
206         }
207
208         if (rx_pkts > 0) {
209             /* blocking enqueue */
210             do {
211                 rslt = rte_ring_enqueue_bulk(tx_ring, pkts, rx_pkts);
212             } while (rslt == -ENOBUFS);
213         }
214     }
215 }