162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <stdio.h>
362306a36Sopenharmony_ci#include <string.h>
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <ynl.h>
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <net/if.h>
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include "netdev-user.h"
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci/* netdev genetlink family code sample
1262306a36Sopenharmony_ci * This sample shows off basics of the netdev family but also notification
1362306a36Sopenharmony_ci * handling, hence the somewhat odd UI. We subscribe to notifications first
1462306a36Sopenharmony_ci * then wait for ifc selection, so the socket may already accumulate
1562306a36Sopenharmony_ci * notifications as we wait. This allows us to test that YNL can handle
1662306a36Sopenharmony_ci * requests and notifications getting interleaved.
1762306a36Sopenharmony_ci */
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic void netdev_print_device(struct netdev_dev_get_rsp *d, unsigned int op)
2062306a36Sopenharmony_ci{
2162306a36Sopenharmony_ci	char ifname[IF_NAMESIZE];
2262306a36Sopenharmony_ci	const char *name;
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	if (!d->_present.ifindex)
2562306a36Sopenharmony_ci		return;
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	name = if_indextoname(d->ifindex, ifname);
2862306a36Sopenharmony_ci	if (name)
2962306a36Sopenharmony_ci		printf("%8s", name);
3062306a36Sopenharmony_ci	printf("[%d]\t", d->ifindex);
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	if (!d->_present.xdp_features)
3362306a36Sopenharmony_ci		return;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	printf("%llx:", d->xdp_features);
3662306a36Sopenharmony_ci	for (int i = 0; d->xdp_features > 1U << i; i++) {
3762306a36Sopenharmony_ci		if (d->xdp_features & (1U << i))
3862306a36Sopenharmony_ci			printf(" %s", netdev_xdp_act_str(1 << i));
3962306a36Sopenharmony_ci	}
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	printf(" xdp-zc-max-segs=%u", d->xdp_zc_max_segs);
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	name = netdev_op_str(op);
4462306a36Sopenharmony_ci	if (name)
4562306a36Sopenharmony_ci		printf(" (ntf: %s)", name);
4662306a36Sopenharmony_ci	printf("\n");
4762306a36Sopenharmony_ci}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ciint main(int argc, char **argv)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	struct netdev_dev_get_list *devs;
5262306a36Sopenharmony_ci	struct ynl_ntf_base_type *ntf;
5362306a36Sopenharmony_ci	struct ynl_error yerr;
5462306a36Sopenharmony_ci	struct ynl_sock *ys;
5562306a36Sopenharmony_ci	int ifindex = 0;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	if (argc > 1)
5862306a36Sopenharmony_ci		ifindex = strtol(argv[1], NULL, 0);
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	ys = ynl_sock_create(&ynl_netdev_family, &yerr);
6162306a36Sopenharmony_ci	if (!ys) {
6262306a36Sopenharmony_ci		fprintf(stderr, "YNL: %s\n", yerr.msg);
6362306a36Sopenharmony_ci		return 1;
6462306a36Sopenharmony_ci	}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	if (ynl_subscribe(ys, "mgmt"))
6762306a36Sopenharmony_ci		goto err_close;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	printf("Select ifc ($ifindex; or 0 = dump; or -2 ntf check): ");
7062306a36Sopenharmony_ci	scanf("%d", &ifindex);
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	if (ifindex > 0) {
7362306a36Sopenharmony_ci		struct netdev_dev_get_req *req;
7462306a36Sopenharmony_ci		struct netdev_dev_get_rsp *d;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci		req = netdev_dev_get_req_alloc();
7762306a36Sopenharmony_ci		netdev_dev_get_req_set_ifindex(req, ifindex);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci		d = netdev_dev_get(ys, req);
8062306a36Sopenharmony_ci		netdev_dev_get_req_free(req);
8162306a36Sopenharmony_ci		if (!d)
8262306a36Sopenharmony_ci			goto err_close;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci		netdev_print_device(d, 0);
8562306a36Sopenharmony_ci		netdev_dev_get_rsp_free(d);
8662306a36Sopenharmony_ci	} else if (!ifindex) {
8762306a36Sopenharmony_ci		devs = netdev_dev_get_dump(ys);
8862306a36Sopenharmony_ci		if (!devs)
8962306a36Sopenharmony_ci			goto err_close;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci		ynl_dump_foreach(devs, d)
9262306a36Sopenharmony_ci			netdev_print_device(d, 0);
9362306a36Sopenharmony_ci		netdev_dev_get_list_free(devs);
9462306a36Sopenharmony_ci	} else if (ifindex == -2) {
9562306a36Sopenharmony_ci		ynl_ntf_check(ys);
9662306a36Sopenharmony_ci	}
9762306a36Sopenharmony_ci	while ((ntf = ynl_ntf_dequeue(ys))) {
9862306a36Sopenharmony_ci		netdev_print_device((struct netdev_dev_get_rsp *)&ntf->data,
9962306a36Sopenharmony_ci				    ntf->cmd);
10062306a36Sopenharmony_ci		ynl_ntf_free(ntf);
10162306a36Sopenharmony_ci	}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	ynl_sock_destroy(ys);
10462306a36Sopenharmony_ci	return 0;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cierr_close:
10762306a36Sopenharmony_ci	fprintf(stderr, "YNL: %s\n", ys->err.msg);
10862306a36Sopenharmony_ci	ynl_sock_destroy(ys);
10962306a36Sopenharmony_ci	return 2;
11062306a36Sopenharmony_ci}
111