Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (c) 2015-2018 Atomic Rules LLC
3 : : */
4 : :
5 : : #include <stdlib.h>
6 : : #include <unistd.h>
7 : : #include <sys/socket.h>
8 : : #include <arpa/inet.h>
9 : :
10 : : #include <rte_string_fns.h>
11 : : #include <rte_malloc.h>
12 : : #include <rte_byteorder.h>
13 : : #include <rte_thread.h>
14 : :
15 : : #include "ark_pktgen.h"
16 : : #include "ark_logs.h"
17 : :
18 : : #define ARK_MAX_STR_LEN 64
19 : : union OPTV {
20 : : int INT;
21 : : int BOOL;
22 : : uint64_t LONG;
23 : : char STR[ARK_MAX_STR_LEN];
24 : : };
25 : :
26 : : enum OPTYPE {
27 : : OTINT,
28 : : OTLONG,
29 : : OTBOOL,
30 : : OTSTRING
31 : : };
32 : :
33 : : struct OPTIONS {
34 : : char opt[ARK_MAX_STR_LEN];
35 : : enum OPTYPE t;
36 : : union OPTV v;
37 : : };
38 : :
39 : : static struct OPTIONS toptions[] = {
40 : : {{"configure"}, OTBOOL, {1} },
41 : : {{"dg-mode"}, OTBOOL, {1} },
42 : : {{"run"}, OTBOOL, {0} },
43 : : {{"pause"}, OTBOOL, {0} },
44 : : {{"reset"}, OTBOOL, {0} },
45 : : {{"dump"}, OTBOOL, {0} },
46 : : {{"gen_forever"}, OTBOOL, {0} },
47 : : {{"en_slaved_start"}, OTBOOL, {0} },
48 : : {{"vary_length"}, OTBOOL, {0} },
49 : : {{"incr_payload"}, OTBOOL, {0} },
50 : : {{"incr_first_byte"}, OTBOOL, {0} },
51 : : {{"ins_seq_num"}, OTBOOL, {0} },
52 : : {{"ins_time_stamp"}, OTBOOL, {1} },
53 : : {{"ins_udp_hdr"}, OTBOOL, {0} },
54 : : {{"num_pkts"}, OTLONG, .v.LONG = 100000000},
55 : : {{"payload_byte"}, OTINT, {0x55} },
56 : : {{"pkt_spacing"}, OTINT, {130} },
57 : : {{"pkt_size_min"}, OTINT, {2006} },
58 : : {{"pkt_size_max"}, OTINT, {1514} },
59 : : {{"pkt_size_incr"}, OTINT, {1} },
60 : : {{"eth_type"}, OTINT, {0x0800} },
61 : : {{"src_mac_addr"}, OTLONG, .v.LONG = 0xdC3cF6425060L},
62 : : {{"dst_mac_addr"}, OTLONG, .v.LONG = 0x112233445566L},
63 : : {{"hdr_dW0"}, OTINT, {0x0016e319} },
64 : : {{"hdr_dW1"}, OTINT, {0x27150004} },
65 : : {{"hdr_dW2"}, OTINT, {0x76967bda} },
66 : : {{"hdr_dW3"}, OTINT, {0x08004500} },
67 : : {{"hdr_dW4"}, OTINT, {0x005276ed} },
68 : : {{"hdr_dW5"}, OTINT, {0x40004006} },
69 : : {{"hdr_dW6"}, OTINT, {0x56cfc0a8} },
70 : : {{"start_offset"}, OTINT, {0} },
71 : : {{"bytes_per_cycle"}, OTINT, {10} },
72 : : {{"shaping"}, OTBOOL, {0} },
73 : : {{"dst_ip"}, OTSTRING, .v.STR = "169.254.10.240"},
74 : : {{"dst_port"}, OTINT, {65536} },
75 : : {{"src_port"}, OTINT, {65536} },
76 : : };
77 : :
78 : : ark_pkt_gen_t
79 : 0 : ark_pktgen_init(void *adr, int ord, int l2_mode)
80 : : {
81 : : struct ark_pkt_gen_inst *inst =
82 : 0 : rte_malloc("ark_pkt_gen_inst_pmd",
83 : : sizeof(struct ark_pkt_gen_inst), 0);
84 [ # # ]: 0 : if (inst == NULL) {
85 : 0 : ARK_PMD_LOG(ERR, "Failed to malloc ark_pkt_gen_inst.\n");
86 : 0 : return inst;
87 : : }
88 : 0 : inst->regs = (struct ark_pkt_gen_regs *)adr;
89 : 0 : inst->ordinal = ord;
90 : 0 : inst->l2_mode = l2_mode;
91 : 0 : return inst;
92 : : }
93 : :
94 : : void
95 : 0 : ark_pktgen_uninit(ark_pkt_gen_t handle)
96 : : {
97 : 0 : rte_free(handle);
98 : 0 : }
99 : :
100 : : void
101 : 0 : ark_pktgen_run(ark_pkt_gen_t handle)
102 : : {
103 : : struct ark_pkt_gen_inst *inst = (struct ark_pkt_gen_inst *)handle;
104 : :
105 : 0 : inst->regs->pkt_start_stop = 1;
106 : 0 : }
107 : :
108 : : uint32_t
109 : 0 : ark_pktgen_paused(ark_pkt_gen_t handle)
110 : : {
111 : : struct ark_pkt_gen_inst *inst = (struct ark_pkt_gen_inst *)handle;
112 : 0 : uint32_t r = inst->regs->pkt_start_stop;
113 : :
114 [ # # # # ]: 0 : return (((r >> 24) & 1) == 1) || (((r >> 16) & 1) == 1) || (r == 0);
115 : : }
116 : :
117 : : void
118 : 0 : ark_pktgen_pause(ark_pkt_gen_t handle)
119 : : {
120 : : struct ark_pkt_gen_inst *inst = (struct ark_pkt_gen_inst *)handle;
121 : : int cnt = 0;
122 : :
123 : 0 : inst->regs->pkt_start_stop = 0;
124 : :
125 [ # # ]: 0 : while (!ark_pktgen_paused(handle)) {
126 : 0 : usleep(1000);
127 [ # # ]: 0 : if (cnt++ > 100) {
128 : 0 : ARK_PMD_LOG(NOTICE, "Pktgen %d failed to pause.\n",
129 : : inst->ordinal);
130 : 0 : break;
131 : : }
132 : : }
133 : 0 : ARK_PMD_LOG(DEBUG, "Pktgen %d paused.\n", inst->ordinal);
134 : 0 : }
135 : :
136 : : void
137 : 0 : ark_pktgen_reset(ark_pkt_gen_t handle)
138 : : {
139 : : struct ark_pkt_gen_inst *inst = (struct ark_pkt_gen_inst *)handle;
140 : :
141 [ # # # # ]: 0 : if (!ark_pktgen_is_running(handle) &&
142 : 0 : !ark_pktgen_paused(handle)) {
143 : 0 : ARK_PMD_LOG(DEBUG, "Pktgen %d is not running"
144 : : " and is not paused. No need to reset.\n",
145 : : inst->ordinal);
146 : 0 : return;
147 : : }
148 : :
149 [ # # # # ]: 0 : if (ark_pktgen_is_running(handle) &&
150 : 0 : !ark_pktgen_paused(handle)) {
151 : 0 : ARK_PMD_LOG(DEBUG,
152 : : "Pktgen %d is not paused. Pausing first.\n",
153 : : inst->ordinal);
154 : 0 : ark_pktgen_pause(handle);
155 : : }
156 : :
157 : 0 : ARK_PMD_LOG(DEBUG, "Resetting pktgen %d.\n", inst->ordinal);
158 : 0 : inst->regs->pkt_start_stop = (1 << 8);
159 : : }
160 : :
161 : : uint32_t
162 : 0 : ark_pktgen_tx_done(ark_pkt_gen_t handle)
163 : : {
164 : : struct ark_pkt_gen_inst *inst = (struct ark_pkt_gen_inst *)handle;
165 : 0 : uint32_t r = inst->regs->pkt_start_stop;
166 : :
167 : 0 : return (((r >> 24) & 1) == 1);
168 : : }
169 : :
170 : : uint32_t
171 : 0 : ark_pktgen_is_running(ark_pkt_gen_t handle)
172 : : {
173 : : struct ark_pkt_gen_inst *inst = (struct ark_pkt_gen_inst *)handle;
174 : 0 : uint32_t r = inst->regs->pkt_start_stop;
175 : :
176 : 0 : return ((r & 1) == 1);
177 : : }
178 : :
179 : : uint32_t
180 : 0 : ark_pktgen_is_gen_forever(ark_pkt_gen_t handle)
181 : : {
182 : : struct ark_pkt_gen_inst *inst = (struct ark_pkt_gen_inst *)handle;
183 : 0 : uint32_t r = inst->regs->pkt_ctrl;
184 : :
185 : 0 : return (((r >> 24) & 1) == 1);
186 : : }
187 : :
188 : : void
189 : 0 : ark_pktgen_wait_done(ark_pkt_gen_t handle)
190 : : {
191 : : struct ark_pkt_gen_inst *inst = (struct ark_pkt_gen_inst *)handle;
192 : : int wait_cycle = 10;
193 : :
194 [ # # ]: 0 : if (ark_pktgen_is_gen_forever(handle))
195 : 0 : ARK_PMD_LOG(NOTICE, "Pktgen wait_done will not terminate"
196 : : " because gen_forever=1\n");
197 : :
198 [ # # # # ]: 0 : while (!ark_pktgen_tx_done(handle) && (wait_cycle > 0)) {
199 : 0 : usleep(1000);
200 : 0 : wait_cycle--;
201 : 0 : ARK_PMD_LOG(DEBUG,
202 : : "Waiting for pktgen %d to finish sending...\n",
203 : : inst->ordinal);
204 : : }
205 : 0 : ARK_PMD_LOG(DEBUG, "Pktgen %d done.\n", inst->ordinal);
206 : 0 : }
207 : :
208 : : uint32_t
209 : 0 : ark_pktgen_get_pkts_sent(ark_pkt_gen_t handle)
210 : : {
211 : : struct ark_pkt_gen_inst *inst = (struct ark_pkt_gen_inst *)handle;
212 : 0 : return inst->regs->pkts_sent;
213 : : }
214 : :
215 : : void
216 : 0 : ark_pktgen_set_payload_byte(ark_pkt_gen_t handle, uint32_t b)
217 : : {
218 : : struct ark_pkt_gen_inst *inst = (struct ark_pkt_gen_inst *)handle;
219 : 0 : inst->regs->pkt_payload = b;
220 : 0 : }
221 : :
222 : : void
223 : 0 : ark_pktgen_set_pkt_spacing(ark_pkt_gen_t handle, uint32_t x)
224 : : {
225 : : struct ark_pkt_gen_inst *inst = (struct ark_pkt_gen_inst *)handle;
226 : 0 : inst->regs->pkt_spacing = x;
227 : 0 : }
228 : :
229 : : void
230 : 0 : ark_pktgen_set_pkt_size_min(ark_pkt_gen_t handle, uint32_t x)
231 : : {
232 : : struct ark_pkt_gen_inst *inst = (struct ark_pkt_gen_inst *)handle;
233 : 0 : inst->regs->pkt_size_min = x;
234 : 0 : }
235 : :
236 : : void
237 : 0 : ark_pktgen_set_pkt_size_max(ark_pkt_gen_t handle, uint32_t x)
238 : : {
239 : : struct ark_pkt_gen_inst *inst = (struct ark_pkt_gen_inst *)handle;
240 : 0 : inst->regs->pkt_size_max = x;
241 : 0 : }
242 : :
243 : : void
244 : 0 : ark_pktgen_set_pkt_size_incr(ark_pkt_gen_t handle, uint32_t x)
245 : : {
246 : : struct ark_pkt_gen_inst *inst = (struct ark_pkt_gen_inst *)handle;
247 : 0 : inst->regs->pkt_size_incr = x;
248 : 0 : }
249 : :
250 : : void
251 : 0 : ark_pktgen_set_num_pkts(ark_pkt_gen_t handle, uint32_t x)
252 : : {
253 : : struct ark_pkt_gen_inst *inst = (struct ark_pkt_gen_inst *)handle;
254 : 0 : inst->regs->num_pkts = x;
255 : 0 : }
256 : :
257 : : void
258 : 0 : ark_pktgen_set_src_mac_addr(ark_pkt_gen_t handle, uint64_t mac_addr)
259 : : {
260 : : struct ark_pkt_gen_inst *inst = (struct ark_pkt_gen_inst *)handle;
261 : 0 : inst->regs->src_mac_addr_h = (mac_addr >> 32) & 0xffff;
262 : 0 : inst->regs->src_mac_addr_l = mac_addr & 0xffffffff;
263 : 0 : }
264 : :
265 : : void
266 : 0 : ark_pktgen_set_dst_mac_addr(ark_pkt_gen_t handle, uint64_t mac_addr)
267 : : {
268 : : struct ark_pkt_gen_inst *inst = (struct ark_pkt_gen_inst *)handle;
269 : 0 : inst->regs->dst_mac_addr_h = (mac_addr >> 32) & 0xffff;
270 : 0 : inst->regs->dst_mac_addr_l = mac_addr & 0xffffffff;
271 : 0 : }
272 : :
273 : : void
274 : 0 : ark_pktgen_set_eth_type(ark_pkt_gen_t handle, uint32_t x)
275 : : {
276 : : struct ark_pkt_gen_inst *inst = (struct ark_pkt_gen_inst *)handle;
277 : 0 : inst->regs->eth_type = x;
278 : 0 : }
279 : :
280 : : void
281 : 0 : ark_pktgen_set_hdr_dW(ark_pkt_gen_t handle, uint32_t *hdr)
282 : : {
283 : : uint32_t i;
284 : : struct ark_pkt_gen_inst *inst = (struct ark_pkt_gen_inst *)handle;
285 : :
286 [ # # ]: 0 : for (i = 0; i < 7; i++)
287 : 0 : inst->regs->hdr_dw[i] = hdr[i];
288 : 0 : }
289 : :
290 : : void
291 : 0 : ark_pktgen_set_start_offset(ark_pkt_gen_t handle, uint32_t x)
292 : : {
293 : : struct ark_pkt_gen_inst *inst = (struct ark_pkt_gen_inst *)handle;
294 : :
295 : 0 : inst->regs->start_offset = x;
296 : 0 : }
297 : :
298 : : static struct OPTIONS *
299 : 0 : options(const char *id)
300 : : {
301 : : unsigned int i;
302 : :
303 [ # # ]: 0 : for (i = 0; i < sizeof(toptions) / sizeof(struct OPTIONS); i++) {
304 [ # # ]: 0 : if (strcmp(id, toptions[i].opt) == 0)
305 : 0 : return &toptions[i];
306 : : }
307 : :
308 : 0 : ARK_PMD_LOG(ERR,
309 : : "Pktgen: Could not find requested option!, "
310 : : "option = %s\n",
311 : : id
312 : : );
313 : 0 : return NULL;
314 : : }
315 : :
316 : : static int pmd_set_arg(char *arg, char *val);
317 : : static int
318 : 0 : pmd_set_arg(char *arg, char *val)
319 : : {
320 : 0 : struct OPTIONS *o = options(arg);
321 : :
322 [ # # ]: 0 : if (o) {
323 [ # # # # ]: 0 : switch (o->t) {
324 : : case OTINT:
325 : : case OTBOOL:
326 : 0 : o->v.INT = atoi(val);
327 : 0 : break;
328 : : case OTLONG:
329 : 0 : o->v.INT = atoll(val);
330 : 0 : break;
331 : 0 : case OTSTRING:
332 : 0 : strlcpy(o->v.STR, val, ARK_MAX_STR_LEN);
333 : : break;
334 : : }
335 : 0 : return 1;
336 : : }
337 : : return 0;
338 : : }
339 : :
340 : : /******
341 : : * Arg format = "opt0=v,opt_n=v ..."
342 : : ******/
343 : : void
344 : 0 : ark_pktgen_parse(char *args)
345 : : {
346 : : char *argv, *v;
347 : 0 : const char toks[] = " =\n\t\v\f \r";
348 : 0 : argv = strtok(args, toks);
349 : 0 : v = strtok(NULL, toks);
350 [ # # ]: 0 : while (argv && v) {
351 : 0 : pmd_set_arg(argv, v);
352 : 0 : argv = strtok(NULL, toks);
353 : 0 : v = strtok(NULL, toks);
354 : : }
355 : 0 : }
356 : :
357 : : static int32_t parse_ipv4_string(char const *ip_address);
358 : : static int32_t
359 : 0 : parse_ipv4_string(char const *ip_address)
360 : : {
361 : : struct in_addr addr;
362 : :
363 [ # # ]: 0 : if (inet_pton(AF_INET, ip_address, &addr) != 1)
364 : : return 0;
365 [ # # ]: 0 : return rte_be_to_cpu_32(addr.s_addr);
366 : : }
367 : :
368 : : static void
369 : 0 : ark_pktgen_set_pkt_ctrl(ark_pkt_gen_t handle,
370 : : uint32_t gen_forever,
371 : : uint32_t en_slaved_start,
372 : : uint32_t vary_length,
373 : : uint32_t incr_payload,
374 : : uint32_t incr_first_byte,
375 : : uint32_t ins_seq_num,
376 : : uint32_t ins_udp_hdr,
377 : : uint32_t ins_time_stamp)
378 : : {
379 : : uint32_t r;
380 : : struct ark_pkt_gen_inst *inst = (struct ark_pkt_gen_inst *)handle;
381 : :
382 [ # # ]: 0 : if (!inst->l2_mode)
383 : : ins_udp_hdr = 0;
384 : :
385 : 0 : r = ((gen_forever << 24) |
386 : 0 : (en_slaved_start << 20) |
387 : 0 : (vary_length << 16) |
388 : 0 : (incr_payload << 12) |
389 : 0 : (incr_first_byte << 8) |
390 : 0 : (ins_time_stamp << 5) |
391 : 0 : (ins_seq_num << 4) |
392 : : ins_udp_hdr);
393 : :
394 : 0 : inst->regs->bytes_per_cycle = options("bytes_per_cycle")->v.INT;
395 [ # # ]: 0 : if (options("shaping")->v.BOOL)
396 : 0 : r = r | (1 << 28); /* enable shaping */
397 : :
398 : 0 : inst->regs->pkt_ctrl = r;
399 : 0 : }
400 : :
401 : : void
402 : 0 : ark_pktgen_setup(ark_pkt_gen_t handle)
403 : : {
404 : : uint32_t hdr[7];
405 : 0 : int32_t dst_ip = parse_ipv4_string(options("dst_ip")->v.STR);
406 : :
407 [ # # ]: 0 : if (!options("pause")->v.BOOL &&
408 [ # # ]: 0 : (!options("reset")->v.BOOL &&
409 [ # # ]: 0 : (options("configure")->v.BOOL))) {
410 : 0 : ark_pktgen_set_payload_byte(handle,
411 : 0 : options("payload_byte")->v.INT);
412 : 0 : ark_pktgen_set_src_mac_addr(handle,
413 : 0 : options("src_mac_addr")->v.INT);
414 : 0 : ark_pktgen_set_dst_mac_addr(handle,
415 : 0 : options("dst_mac_addr")->v.LONG);
416 : 0 : ark_pktgen_set_eth_type(handle,
417 : 0 : options("eth_type")->v.INT);
418 : :
419 [ # # ]: 0 : if (options("dg-mode")->v.BOOL) {
420 : 0 : hdr[0] = options("hdr_dW0")->v.INT;
421 : 0 : hdr[1] = options("hdr_dW1")->v.INT;
422 : 0 : hdr[2] = options("hdr_dW2")->v.INT;
423 : 0 : hdr[3] = options("hdr_dW3")->v.INT;
424 : 0 : hdr[4] = options("hdr_dW4")->v.INT;
425 : 0 : hdr[5] = options("hdr_dW5")->v.INT;
426 : 0 : hdr[6] = options("hdr_dW6")->v.INT;
427 : : } else {
428 : 0 : hdr[0] = dst_ip;
429 : 0 : hdr[1] = options("dst_port")->v.INT;
430 : 0 : hdr[2] = options("src_port")->v.INT;
431 : 0 : hdr[3] = 0;
432 : 0 : hdr[4] = 0;
433 : 0 : hdr[5] = 0;
434 : 0 : hdr[6] = 0;
435 : : }
436 : 0 : ark_pktgen_set_hdr_dW(handle, hdr);
437 : 0 : ark_pktgen_set_num_pkts(handle,
438 : 0 : options("num_pkts")->v.INT);
439 : 0 : ark_pktgen_set_pkt_size_min(handle,
440 : 0 : options("pkt_size_min")->v.INT);
441 : 0 : ark_pktgen_set_pkt_size_max(handle,
442 : 0 : options("pkt_size_max")->v.INT);
443 : 0 : ark_pktgen_set_pkt_size_incr(handle,
444 : 0 : options("pkt_size_incr")->v.INT);
445 : 0 : ark_pktgen_set_pkt_spacing(handle,
446 : 0 : options("pkt_spacing")->v.INT);
447 : 0 : ark_pktgen_set_start_offset(handle,
448 : 0 : options("start_offset")->v.INT);
449 : 0 : ark_pktgen_set_pkt_ctrl(handle,
450 : 0 : options("gen_forever")->v.BOOL,
451 : 0 : options("en_slaved_start")->v.BOOL,
452 : 0 : options("vary_length")->v.BOOL,
453 : 0 : options("incr_payload")->v.BOOL,
454 : 0 : options("incr_first_byte")->v.BOOL,
455 : 0 : options("ins_seq_num")->v.INT,
456 : 0 : options("ins_udp_hdr")->v.BOOL,
457 : 0 : options("ins_time_stamp")->v.INT);
458 : : }
459 : :
460 [ # # ]: 0 : if (options("pause")->v.BOOL)
461 : 0 : ark_pktgen_pause(handle);
462 : :
463 [ # # ]: 0 : if (options("reset")->v.BOOL)
464 : 0 : ark_pktgen_reset(handle);
465 [ # # ]: 0 : if (options("run")->v.BOOL) {
466 : 0 : ARK_PMD_LOG(DEBUG, "Starting packet generator on port %d\n",
467 : : options("port")->v.INT);
468 : 0 : ark_pktgen_run(handle);
469 : : }
470 : 0 : }
471 : :
472 : : uint32_t
473 : 0 : ark_pktgen_delay_start(void *arg)
474 : : {
475 : : struct ark_pkt_gen_inst *inst = (struct ark_pkt_gen_inst *)arg;
476 : :
477 : : /* This function is used exclusively for regression testing, We
478 : : * perform a blind sleep here to ensure that the external test
479 : : * application has time to setup the test before we generate packets
480 : : */
481 : 0 : rte_thread_detach(rte_thread_self());
482 : 0 : usleep(100000);
483 : 0 : ark_pktgen_run(inst);
484 : 0 : return 0;
485 : : }
|