Blame view

samples/bpf/xdp_rxq_info_user.c 14 KB
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  /* SPDX-License-Identifier: GPL-2.0
   * Copyright (c) 2017 Jesper Dangaard Brouer, Red Hat Inc.
   */
  static const char *__doc__ = " XDP RX-queue info extract example
  
  "
  	"Monitor how many packets per sec (pps) are received
  "
  	"per NIC RX queue index and which CPU processed the packet
  "
  	;
  
  #include <errno.h>
  #include <signal.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <stdbool.h>
  #include <string.h>
  #include <unistd.h>
  #include <locale.h>
  #include <sys/resource.h>
  #include <getopt.h>
  #include <net/if.h>
  #include <time.h>
  
  #include <arpa/inet.h>
  #include <linux/if_link.h>
7cf245a37   Toke Høiland-Jørgensen   samples/bpf: Use ...
28
29
  #include <bpf/bpf.h>
  #include <bpf/libbpf.h>
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
30
31
32
33
34
  #include "bpf_util.h"
  
  static int ifindex = -1;
  static char ifname_buf[IF_NAMESIZE];
  static char *ifname;
3b7a8ec2d   Maciej Fijalkowski   samples/bpf: Chec...
35
  static __u32 prog_id;
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
36

743e568c1   Maciej Fijalkowski   samples/bpf: Add ...
37
  static __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
38

be5bca44a   Jakub Kicinski   samples: bpf: con...
39
40
  static struct bpf_map *stats_global_map;
  static struct bpf_map *rx_queue_index_map;
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
  /* Exit return codes */
  #define EXIT_OK		0
  #define EXIT_FAIL		1
  #define EXIT_FAIL_OPTION	2
  #define EXIT_FAIL_XDP		3
  #define EXIT_FAIL_BPF		4
  #define EXIT_FAIL_MEM		5
  
  static const struct option long_options[] = {
  	{"help",	no_argument,		NULL, 'h' },
  	{"dev",		required_argument,	NULL, 'd' },
  	{"skb-mode",	no_argument,		NULL, 'S' },
  	{"sec",		required_argument,	NULL, 's' },
  	{"no-separators", no_argument,		NULL, 'z' },
  	{"action",	required_argument,	NULL, 'a' },
afbe3c27d   Daniel T. Lee   samples: bpf: Upd...
56
57
  	{"readmem",	no_argument,		NULL, 'r' },
  	{"swapmac",	no_argument,		NULL, 'm' },
743e568c1   Maciej Fijalkowski   samples/bpf: Add ...
58
  	{"force",	no_argument,		NULL, 'F' },
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
59
60
61
62
63
  	{0, 0, NULL,  0 }
  };
  
  static void int_exit(int sig)
  {
3b7a8ec2d   Maciej Fijalkowski   samples/bpf: Chec...
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
  	__u32 curr_prog_id = 0;
  
  	if (ifindex > -1) {
  		if (bpf_get_link_xdp_id(ifindex, &curr_prog_id, xdp_flags)) {
  			printf("bpf_get_link_xdp_id failed
  ");
  			exit(EXIT_FAIL);
  		}
  		if (prog_id == curr_prog_id) {
  			fprintf(stderr,
  				"Interrupted: Removing XDP program on ifindex:%d device:%s
  ",
  				ifindex, ifname);
  			bpf_set_link_xdp_fd(ifindex, -1, xdp_flags);
  		} else if (!curr_prog_id) {
  			printf("couldn't find a prog id on a given iface
  ");
  		} else {
  			printf("program on interface changed, not removing
  ");
  		}
  	}
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
86
87
88
89
90
91
  	exit(EXIT_OK);
  }
  
  struct config {
  	__u32 action;
  	int ifindex;
0d25c43ab   Jesper Dangaard Brouer   samples/bpf: exte...
92
93
94
95
96
  	__u32 options;
  };
  enum cfg_options_flags {
  	NO_TOUCH = 0x0U,
  	READ_MEM = 0x1U,
509fda105   Jesper Dangaard Brouer   samples/bpf: xdp_...
97
  	SWAP_MAC = 0x2U,
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
  };
  #define XDP_ACTION_MAX (XDP_TX + 1)
  #define XDP_ACTION_MAX_STRLEN 11
  static const char *xdp_action_names[XDP_ACTION_MAX] = {
  	[XDP_ABORTED]	= "XDP_ABORTED",
  	[XDP_DROP]	= "XDP_DROP",
  	[XDP_PASS]	= "XDP_PASS",
  	[XDP_TX]	= "XDP_TX",
  };
  
  static const char *action2str(int action)
  {
  	if (action < XDP_ACTION_MAX)
  		return xdp_action_names[action];
  	return NULL;
  }
  
  static int parse_xdp_action(char *action_str)
  {
  	size_t maxlen;
  	__u64 action = -1;
  	int i;
  
  	for (i = 0; i < XDP_ACTION_MAX; i++) {
  		maxlen = XDP_ACTION_MAX_STRLEN;
  		if (strncmp(xdp_action_names[i], action_str, maxlen) == 0) {
  			action = i;
  			break;
  		}
  	}
  	return action;
  }
  
  static void list_xdp_actions(void)
  {
  	int i;
  
  	printf("Available XDP --action <options>
  ");
  	for (i = 0; i < XDP_ACTION_MAX; i++)
  		printf("\t%s
  ", xdp_action_names[i]);
  	printf("
  ");
  }
0d25c43ab   Jesper Dangaard Brouer   samples/bpf: exte...
143
144
145
146
  static char* options2str(enum cfg_options_flags flag)
  {
  	if (flag == NO_TOUCH)
  		return "no_touch";
509fda105   Jesper Dangaard Brouer   samples/bpf: xdp_...
147
148
  	if (flag & SWAP_MAC)
  		return "swapmac";
0d25c43ab   Jesper Dangaard Brouer   samples/bpf: exte...
149
150
151
152
153
  	if (flag & READ_MEM)
  		return "read";
  	fprintf(stderr, "ERR: Unknown config option flags");
  	exit(EXIT_FAIL);
  }
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
  static void usage(char *argv[])
  {
  	int i;
  
  	printf("
  DOCUMENTATION:
  %s
  ", __doc__);
  	printf(" Usage: %s (options-see-below)
  ", argv[0]);
  	printf(" Listing options:
  ");
  	for (i = 0; long_options[i].name != 0; i++) {
  		printf(" --%-12s", long_options[i].name);
  		if (long_options[i].flag != NULL)
  			printf(" flag (internal value:%d)",
  				*long_options[i].flag);
  		else
  			printf(" short-option: -%c",
  				long_options[i].val);
  		printf("
  ");
  	}
  	printf("
  ");
  	list_xdp_actions();
  }
  
  #define NANOSEC_PER_SEC 1000000000 /* 10^9 */
  static __u64 gettime(void)
  {
  	struct timespec t;
  	int res;
  
  	res = clock_gettime(CLOCK_MONOTONIC, &t);
  	if (res < 0) {
  		fprintf(stderr, "Error with gettimeofday! (%i)
  ", res);
  		exit(EXIT_FAIL);
  	}
  	return (__u64) t.tv_sec * NANOSEC_PER_SEC + t.tv_nsec;
  }
  
  /* Common stats data record shared with _kern.c */
  struct datarec {
  	__u64 processed;
  	__u64 issue;
  };
  struct record {
  	__u64 timestamp;
  	struct datarec total;
  	struct datarec *cpu;
  };
  struct stats_record {
  	struct record stats;
  	struct record *rxq;
  };
  
  static struct datarec *alloc_record_per_cpu(void)
  {
  	unsigned int nr_cpus = bpf_num_possible_cpus();
  	struct datarec *array;
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
216

6903cdae9   Gaurav Singh   bpf, xdp, samples...
217
  	array = calloc(nr_cpus, sizeof(struct datarec));
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
218
219
220
221
222
223
224
225
226
227
  	if (!array) {
  		fprintf(stderr, "Mem alloc error (nr_cpus:%u)
  ", nr_cpus);
  		exit(EXIT_FAIL_MEM);
  	}
  	return array;
  }
  
  static struct record *alloc_record_per_rxq(void)
  {
be5bca44a   Jakub Kicinski   samples: bpf: con...
228
  	unsigned int nr_rxqs = bpf_map__def(rx_queue_index_map)->max_entries;
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
229
  	struct record *array;
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
230

6903cdae9   Gaurav Singh   bpf, xdp, samples...
231
  	array = calloc(nr_rxqs, sizeof(struct record));
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
232
233
234
235
236
237
238
239
240
241
  	if (!array) {
  		fprintf(stderr, "Mem alloc error (nr_rxqs:%u)
  ", nr_rxqs);
  		exit(EXIT_FAIL_MEM);
  	}
  	return array;
  }
  
  static struct stats_record *alloc_stats_record(void)
  {
be5bca44a   Jakub Kicinski   samples: bpf: con...
242
  	unsigned int nr_rxqs = bpf_map__def(rx_queue_index_map)->max_entries;
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
243
244
  	struct stats_record *rec;
  	int i;
6903cdae9   Gaurav Singh   bpf, xdp, samples...
245
  	rec = calloc(1, sizeof(struct stats_record));
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
  	if (!rec) {
  		fprintf(stderr, "Mem alloc error
  ");
  		exit(EXIT_FAIL_MEM);
  	}
  	rec->rxq = alloc_record_per_rxq();
  	for (i = 0; i < nr_rxqs; i++)
  		rec->rxq[i].cpu = alloc_record_per_cpu();
  
  	rec->stats.cpu = alloc_record_per_cpu();
  	return rec;
  }
  
  static void free_stats_record(struct stats_record *r)
  {
be5bca44a   Jakub Kicinski   samples: bpf: con...
261
  	unsigned int nr_rxqs = bpf_map__def(rx_queue_index_map)->max_entries;
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
  	int i;
  
  	for (i = 0; i < nr_rxqs; i++)
  		free(r->rxq[i].cpu);
  
  	free(r->rxq);
  	free(r->stats.cpu);
  	free(r);
  }
  
  static bool map_collect_percpu(int fd, __u32 key, struct record *rec)
  {
  	/* For percpu maps, userspace gets a value per possible CPU */
  	unsigned int nr_cpus = bpf_num_possible_cpus();
  	struct datarec values[nr_cpus];
  	__u64 sum_processed = 0;
  	__u64 sum_issue = 0;
  	int i;
  
  	if ((bpf_map_lookup_elem(fd, &key, values)) != 0) {
  		fprintf(stderr,
  			"ERR: bpf_map_lookup_elem failed key:0x%X
  ", key);
  		return false;
  	}
  	/* Get time as close as possible to reading map contents */
  	rec->timestamp = gettime();
  
  	/* Record and sum values from each CPU */
  	for (i = 0; i < nr_cpus; i++) {
  		rec->cpu[i].processed = values[i].processed;
  		sum_processed        += values[i].processed;
  		rec->cpu[i].issue = values[i].issue;
  		sum_issue        += values[i].issue;
  	}
  	rec->total.processed = sum_processed;
  	rec->total.issue     = sum_issue;
  	return true;
  }
  
  static void stats_collect(struct stats_record *rec)
  {
  	int fd, i, max_rxqs;
be5bca44a   Jakub Kicinski   samples: bpf: con...
305
  	fd = bpf_map__fd(stats_global_map);
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
306
  	map_collect_percpu(fd, 0, &rec->stats);
be5bca44a   Jakub Kicinski   samples: bpf: con...
307
308
  	fd = bpf_map__fd(rx_queue_index_map);
  	max_rxqs = bpf_map__def(rx_queue_index_map)->max_entries;
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
  	for (i = 0; i < max_rxqs; i++)
  		map_collect_percpu(fd, i, &rec->rxq[i]);
  }
  
  static double calc_period(struct record *r, struct record *p)
  {
  	double period_ = 0;
  	__u64 period = 0;
  
  	period = r->timestamp - p->timestamp;
  	if (period > 0)
  		period_ = ((double) period / NANOSEC_PER_SEC);
  
  	return period_;
  }
  
  static __u64 calc_pps(struct datarec *r, struct datarec *p, double period_)
  {
  	__u64 packets = 0;
  	__u64 pps = 0;
  
  	if (period_ > 0) {
  		packets = r->processed - p->processed;
  		pps = packets / period_;
  	}
  	return pps;
  }
  
  static __u64 calc_errs_pps(struct datarec *r,
  			    struct datarec *p, double period_)
  {
  	__u64 packets = 0;
  	__u64 pps = 0;
  
  	if (period_ > 0) {
  		packets = r->issue - p->issue;
  		pps = packets / period_;
  	}
  	return pps;
  }
  
  static void stats_print(struct stats_record *stats_rec,
  			struct stats_record *stats_prev,
0d25c43ab   Jesper Dangaard Brouer   samples/bpf: exte...
352
  			int action, __u32 cfg_opt)
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
353
  {
be5bca44a   Jakub Kicinski   samples: bpf: con...
354
  	unsigned int nr_rxqs = bpf_map__def(rx_queue_index_map)->max_entries;
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
355
  	unsigned int nr_cpus = bpf_num_possible_cpus();
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
356
357
358
359
360
361
362
  	double pps = 0, err = 0;
  	struct record *rec, *prev;
  	double t;
  	int rxq;
  	int i;
  
  	/* Header */
0d25c43ab   Jesper Dangaard Brouer   samples/bpf: exte...
363
364
365
366
  	printf("
  Running XDP on dev:%s (ifindex:%d) action:%s options:%s
  ",
  	       ifname, ifindex, action2str(action), options2str(cfg_opt));
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
  
  	/* stats_global_map */
  	{
  		char *fmt_rx = "%-15s %-7d %'-11.0f %'-10.0f %s
  ";
  		char *fm2_rx = "%-15s %-7s %'-11.0f
  ";
  		char *errstr = "";
  
  		printf("%-15s %-7s %-11s %-11s
  ",
  		       "XDP stats", "CPU", "pps", "issue-pps");
  
  		rec  =  &stats_rec->stats;
  		prev = &stats_prev->stats;
  		t = calc_period(rec, prev);
  		for (i = 0; i < nr_cpus; i++) {
  			struct datarec *r = &rec->cpu[i];
  			struct datarec *p = &prev->cpu[i];
  
  			pps = calc_pps     (r, p, t);
  			err = calc_errs_pps(r, p, t);
  			if (err > 0)
  				errstr = "invalid-ifindex";
  			if (pps > 0)
  				printf(fmt_rx, "XDP-RX CPU",
  					i, pps, err, errstr);
  		}
  		pps  = calc_pps     (&rec->total, &prev->total, t);
  		err  = calc_errs_pps(&rec->total, &prev->total, t);
  		printf(fm2_rx, "XDP-RX CPU", "total", pps, err);
  	}
  
  	/* rx_queue_index_map */
  	printf("
  %-15s %-7s %-11s %-11s
  ",
  	       "RXQ stats", "RXQ:CPU", "pps", "issue-pps");
  
  	for (rxq = 0; rxq < nr_rxqs; rxq++) {
  		char *fmt_rx = "%-15s %3d:%-3d %'-11.0f %'-10.0f %s
  ";
  		char *fm2_rx = "%-15s %3d:%-3s %'-11.0f
  ";
  		char *errstr = "";
  		int rxq_ = rxq;
  
  		/* Last RXQ in map catch overflows */
  		if (rxq_ == nr_rxqs - 1)
  			rxq_ = -1;
  
  		rec  =  &stats_rec->rxq[rxq];
  		prev = &stats_prev->rxq[rxq];
  		t = calc_period(rec, prev);
  		for (i = 0; i < nr_cpus; i++) {
  			struct datarec *r = &rec->cpu[i];
  			struct datarec *p = &prev->cpu[i];
  
  			pps = calc_pps     (r, p, t);
  			err = calc_errs_pps(r, p, t);
  			if (err > 0) {
  				if (rxq_ == -1)
  					errstr = "map-overflow-RXQ";
  				else
  					errstr = "err";
  			}
  			if (pps > 0)
  				printf(fmt_rx, "rx_queue_index",
  				       rxq_, i, pps, err, errstr);
  		}
  		pps  = calc_pps     (&rec->total, &prev->total, t);
  		err  = calc_errs_pps(&rec->total, &prev->total, t);
  		if (pps || err)
  			printf(fm2_rx, "rx_queue_index", rxq_, "sum", pps, err);
  	}
  }
  
  
  /* Pointer swap trick */
  static inline void swap(struct stats_record **a, struct stats_record **b)
  {
  	struct stats_record *tmp;
  
  	tmp = *a;
  	*a = *b;
  	*b = tmp;
  }
0d25c43ab   Jesper Dangaard Brouer   samples/bpf: exte...
454
  static void stats_poll(int interval, int action, __u32 cfg_opt)
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
455
456
457
458
459
460
461
462
463
464
  {
  	struct stats_record *record, *prev;
  
  	record = alloc_stats_record();
  	prev   = alloc_stats_record();
  	stats_collect(record);
  
  	while (1) {
  		swap(&prev, &record);
  		stats_collect(record);
0d25c43ab   Jesper Dangaard Brouer   samples/bpf: exte...
465
  		stats_print(record, prev, action, cfg_opt);
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
466
467
468
469
470
471
472
473
474
475
  		sleep(interval);
  	}
  
  	free_stats_record(record);
  	free_stats_record(prev);
  }
  
  
  int main(int argc, char **argv)
  {
0d25c43ab   Jesper Dangaard Brouer   samples/bpf: exte...
476
  	__u32 cfg_options= NO_TOUCH ; /* Default: Don't touch packet memory */
c66dca98a   Toke Høiland-Jørgensen   samples/bpf: Set ...
477
  	struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
be5bca44a   Jakub Kicinski   samples: bpf: con...
478
479
480
  	struct bpf_prog_load_attr prog_load_attr = {
  		.prog_type	= BPF_PROG_TYPE_XDP,
  	};
3b7a8ec2d   Maciej Fijalkowski   samples/bpf: Chec...
481
482
  	struct bpf_prog_info info = {};
  	__u32 info_len = sizeof(info);
be5bca44a   Jakub Kicinski   samples: bpf: con...
483
  	int prog_fd, map_fd, opt, err;
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
484
485
  	bool use_separators = true;
  	struct config cfg = { 0 };
be5bca44a   Jakub Kicinski   samples: bpf: con...
486
487
  	struct bpf_object *obj;
  	struct bpf_map *map;
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
488
489
490
491
  	char filename[256];
  	int longindex = 0;
  	int interval = 2;
  	__u32 key = 0;
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
492

0d25c43ab   Jesper Dangaard Brouer   samples/bpf: exte...
493

0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
494
495
496
497
498
  	char action_str_buf[XDP_ACTION_MAX_STRLEN + 1 /* for \0 */] = { 0 };
  	int action = XDP_PASS; /* Default action */
  	char *action_str = NULL;
  
  	snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
be5bca44a   Jakub Kicinski   samples: bpf: con...
499
  	prog_load_attr.file = filename;
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
500
501
502
503
504
  
  	if (setrlimit(RLIMIT_MEMLOCK, &r)) {
  		perror("setrlimit(RLIMIT_MEMLOCK)");
  		return 1;
  	}
be5bca44a   Jakub Kicinski   samples: bpf: con...
505
506
  	if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd))
  		return EXIT_FAIL;
edbca120a   Jesper Dangaard Brouer   samples/bpf: Fix ...
507
508
509
  	map =  bpf_object__find_map_by_name(obj, "config_map");
  	stats_global_map = bpf_object__find_map_by_name(obj, "stats_global_map");
  	rx_queue_index_map = bpf_object__find_map_by_name(obj, "rx_queue_index_map");
be5bca44a   Jakub Kicinski   samples: bpf: con...
510
511
512
  	if (!map || !stats_global_map || !rx_queue_index_map) {
  		printf("finding a map in obj file failed
  ");
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
513
514
  		return EXIT_FAIL;
  	}
be5bca44a   Jakub Kicinski   samples: bpf: con...
515
  	map_fd = bpf_map__fd(map);
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
516

be5bca44a   Jakub Kicinski   samples: bpf: con...
517
  	if (!prog_fd) {
afbe3c27d   Daniel T. Lee   samples: bpf: Upd...
518
519
  		fprintf(stderr, "ERR: bpf_prog_load_xattr: %s
  ", strerror(errno));
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
520
521
522
523
  		return EXIT_FAIL;
  	}
  
  	/* Parse commands line args */
743e568c1   Maciej Fijalkowski   samples/bpf: Add ...
524
  	while ((opt = getopt_long(argc, argv, "FhSrmzd:s:a:",
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
  				  long_options, &longindex)) != -1) {
  		switch (opt) {
  		case 'd':
  			if (strlen(optarg) >= IF_NAMESIZE) {
  				fprintf(stderr, "ERR: --dev name too long
  ");
  				goto error;
  			}
  			ifname = (char *)&ifname_buf;
  			strncpy(ifname, optarg, IF_NAMESIZE);
  			ifindex = if_nametoindex(ifname);
  			if (ifindex == 0) {
  				fprintf(stderr,
  					"ERR: --dev name unknown err(%d):%s
  ",
  					errno, strerror(errno));
  				goto error;
  			}
  			break;
  		case 's':
  			interval = atoi(optarg);
  			break;
  		case 'S':
  			xdp_flags |= XDP_FLAGS_SKB_MODE;
  			break;
  		case 'z':
  			use_separators = false;
  			break;
  		case 'a':
  			action_str = (char *)&action_str_buf;
  			strncpy(action_str, optarg, XDP_ACTION_MAX_STRLEN);
  			break;
0d25c43ab   Jesper Dangaard Brouer   samples/bpf: exte...
557
558
559
  		case 'r':
  			cfg_options |= READ_MEM;
  			break;
509fda105   Jesper Dangaard Brouer   samples/bpf: xdp_...
560
561
562
  		case 'm':
  			cfg_options |= SWAP_MAC;
  			break;
743e568c1   Maciej Fijalkowski   samples/bpf: Add ...
563
564
565
  		case 'F':
  			xdp_flags &= ~XDP_FLAGS_UPDATE_IF_NOEXIST;
  			break;
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
566
567
568
569
570
571
572
  		case 'h':
  		error:
  		default:
  			usage(argv);
  			return EXIT_FAIL_OPTION;
  		}
  	}
d50ecc46d   Toke Høiland-Jørgensen   samples/bpf: Atta...
573
574
575
  
  	if (!(xdp_flags & XDP_FLAGS_SKB_MODE))
  		xdp_flags |= XDP_FLAGS_DRV_MODE;
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
  	/* Required option */
  	if (ifindex == -1) {
  		fprintf(stderr, "ERR: required option --dev missing
  ");
  		usage(argv);
  		return EXIT_FAIL_OPTION;
  	}
  	cfg.ifindex = ifindex;
  
  	/* Parse action string */
  	if (action_str) {
  		action = parse_xdp_action(action_str);
  		if (action < 0) {
  			fprintf(stderr, "ERR: Invalid XDP --action: %s
  ",
  				action_str);
  			list_xdp_actions();
  			return EXIT_FAIL_OPTION;
  		}
  	}
  	cfg.action = action;
509fda105   Jesper Dangaard Brouer   samples/bpf: xdp_...
597
598
599
600
  
  	/* XDP_TX requires changing MAC-addrs, else HW may drop */
  	if (action == XDP_TX)
  		cfg_options |= SWAP_MAC;
0d25c43ab   Jesper Dangaard Brouer   samples/bpf: exte...
601
  	cfg.options = cfg_options;
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
602
603
604
605
606
607
  
  	/* Trick to pretty printf with thousands separators use %' */
  	if (use_separators)
  		setlocale(LC_NUMERIC, "en_US");
  
  	/* User-side setup ifindex in config_map */
be5bca44a   Jakub Kicinski   samples: bpf: con...
608
  	err = bpf_map_update_elem(map_fd, &key, &cfg, 0);
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
609
610
611
612
613
  	if (err) {
  		fprintf(stderr, "Store config failed (err:%d)
  ", err);
  		exit(EXIT_FAIL_BPF);
  	}
817b89beb   Jesper Dangaard Brouer   samples/bpf: all ...
614
  	/* Remove XDP program when program is interrupted or killed */
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
615
  	signal(SIGINT, int_exit);
817b89beb   Jesper Dangaard Brouer   samples/bpf: all ...
616
  	signal(SIGTERM, int_exit);
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
617

be5bca44a   Jakub Kicinski   samples: bpf: con...
618
  	if (bpf_set_link_xdp_fd(ifindex, prog_fd, xdp_flags) < 0) {
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
619
620
621
622
  		fprintf(stderr, "link set xdp fd failed
  ");
  		return EXIT_FAIL_XDP;
  	}
3b7a8ec2d   Maciej Fijalkowski   samples/bpf: Chec...
623
624
625
626
627
628
629
  	err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len);
  	if (err) {
  		printf("can't get prog info - %s
  ", strerror(errno));
  		return err;
  	}
  	prog_id = info.id;
0d25c43ab   Jesper Dangaard Brouer   samples/bpf: exte...
630
  	stats_poll(interval, action, cfg_options);
0fca931a6   Jesper Dangaard Brouer   samples/bpf: prog...
631
632
  	return EXIT_OK;
  }