int main()

in bpf/xdp_rxq_info_user.c [450:599]


int main(int argc, char **argv)
{
	__u32 cfg_options= NO_TOUCH ; /* Default: Don't touch packet memory */
	struct bpf_prog_load_attr prog_load_attr = {
		.prog_type	= BPF_PROG_TYPE_XDP,
	};
	struct bpf_prog_info info = {};
	__u32 info_len = sizeof(info);
	int prog_fd, map_fd, opt, err;
	bool use_separators = true;
	struct config cfg = { 0 };
	struct bpf_object *obj;
	struct bpf_map *map;
	char filename[256];
	int longindex = 0;
	int interval = 2;
	__u32 key = 0;


	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]);
	prog_load_attr.file = filename;

	if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd))
		return EXIT_FAIL;

	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");
	if (!map || !stats_global_map || !rx_queue_index_map) {
		printf("finding a map in obj file failed\n");
		return EXIT_FAIL;
	}
	map_fd = bpf_map__fd(map);

	if (!prog_fd) {
		fprintf(stderr, "ERR: bpf_prog_load_xattr: %s\n", strerror(errno));
		return EXIT_FAIL;
	}

	/* Parse commands line args */
	while ((opt = getopt_long(argc, argv, "FhSrmzd:s:a:",
				  long_options, &longindex)) != -1) {
		switch (opt) {
		case 'd':
			if (strlen(optarg) >= IF_NAMESIZE) {
				fprintf(stderr, "ERR: --dev name too long\n");
				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\n",
					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;
		case 'r':
			cfg_options |= READ_MEM;
			break;
		case 'm':
			cfg_options |= SWAP_MAC;
			break;
		case 'F':
			xdp_flags &= ~XDP_FLAGS_UPDATE_IF_NOEXIST;
			break;
		case 'h':
		error:
		default:
			usage(argv);
			return EXIT_FAIL_OPTION;
		}
	}

	if (!(xdp_flags & XDP_FLAGS_SKB_MODE))
		xdp_flags |= XDP_FLAGS_DRV_MODE;

	/* Required option */
	if (ifindex == -1) {
		fprintf(stderr, "ERR: required option --dev missing\n");
		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\n",
				action_str);
			list_xdp_actions();
			return EXIT_FAIL_OPTION;
		}
	}
	cfg.action = action;

	/* XDP_TX requires changing MAC-addrs, else HW may drop */
	if (action == XDP_TX)
		cfg_options |= SWAP_MAC;
	cfg.options = cfg_options;

	/* Trick to pretty printf with thousands separators use %' */
	if (use_separators)
		setlocale(LC_NUMERIC, "en_US");

	/* User-side setup ifindex in config_map */
	err = bpf_map_update_elem(map_fd, &key, &cfg, 0);
	if (err) {
		fprintf(stderr, "Store config failed (err:%d)\n", err);
		exit(EXIT_FAIL_BPF);
	}

	/* Remove XDP program when program is interrupted or killed */
	signal(SIGINT, int_exit);
	signal(SIGTERM, int_exit);

	if (bpf_set_link_xdp_fd(ifindex, prog_fd, xdp_flags) < 0) {
		fprintf(stderr, "link set xdp fd failed\n");
		return EXIT_FAIL_XDP;
	}

	err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len);
	if (err) {
		printf("can't get prog info - %s\n", strerror(errno));
		return err;
	}
	prog_id = info.id;

	stats_poll(interval, action, cfg_options);
	return EXIT_OK;
}