xref: /aosp_15_r20/external/libnl/tests/test-cache-mngr.c (revision 4dc78e53d49367fa8e61b07018507c90983a077d)
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 
3 #include "nl-default.h"
4 
5 #include <signal.h>
6 #include <sys/time.h>
7 #include <time.h>
8 
9 #include <linux/netlink.h>
10 
11 #include <netlink/netlink.h>
12 #include <netlink/cache.h>
13 #include <netlink/cli/utils.h>
14 
15 static int quit = 0;
16 static int change = 1;
17 static int print_ts = 0;
18 
19 static struct nl_dump_params params = {
20 	.dp_type = NL_DUMP_LINE,
21 };
22 
23 
print_timestamp(FILE * fp)24 static void print_timestamp(FILE *fp)
25 {
26 	struct timeval tv;
27 	char tshort[40];
28 	struct tm *tm;
29 	struct tm tm_buf;
30 
31 	gettimeofday(&tv, NULL);
32 	tm = localtime_r(&tv.tv_sec, &tm_buf);
33 
34 	strftime(tshort, sizeof(tshort), "%Y-%m-%dT%H:%M:%S", tm);
35 	fprintf(fp, "[%s.%06ld] ", tshort, tv.tv_usec);
36 }
37 
change_cb(struct nl_cache * cache,struct nl_object * obj,int action,void * data)38 static void change_cb(struct nl_cache *cache, struct nl_object *obj,
39 		      int action, void *data)
40 {
41 	if (print_ts)
42 		print_timestamp(stdout);
43 
44 	if (action == NL_ACT_NEW)
45 		printf("NEW ");
46 	else if (action == NL_ACT_DEL)
47 		printf("DEL ");
48 	else if (action == NL_ACT_CHANGE)
49 		printf("CHANGE ");
50 
51 	nl_object_dump(obj, &params);
52 	fflush(stdout);
53 
54 	change = 1;
55 }
56 
sigint(int arg)57 static void sigint(int arg)
58 {
59 	quit = 1;
60 }
61 
print_usage(FILE * stream,const char * name)62 static void print_usage(FILE* stream, const char *name)
63 {
64 	fprintf(stream,
65 		"Usage: %s [OPTIONS]... <cache name>... \n"
66 		"\n"
67 		"OPTIONS\n"
68 		" -f, --format=TYPE      Output format { brief | details | stats }\n"
69 		"                        Default: brief\n"
70 		" -d, --dump             Dump cache content after a change.\n"
71 		" -i, --interval=TIME    Dump cache content after TIME seconds when there is no\n"
72 		"                        change; 0 to disable. Default: 1\n"
73 		" -I, --iter             Iterate over all address families when updating caches.\n"
74 		" -t, --tshort           Print a short timestamp before change messages.\n"
75 		" -h, --help             Show this help text.\n"
76 		, name);
77 }
78 
main(int argc,char * argv[])79 int main(int argc, char *argv[])
80 {
81 	bool dump_on_change = false, dump_on_timeout = true, iter = false;
82 	struct nl_cache_mngr *mngr;
83 	int timeout = 1000, err;
84 
85 	for (;;) {
86 		static struct option long_opts[] = {
87 			{ "format", required_argument, 0, 'f' },
88 			{ "dump", no_argument, 0, 'd' },
89 			{ "interval", required_argument, 0, 'i' },
90 			{ "iter", no_argument, 0, 'I' },
91 			{ "tshort", no_argument, 0, 't' },
92 			{ "help", 0, 0, 'h' },
93 			{ 0, 0, 0, 0 }
94 		};
95 		int c;
96 
97 		c = getopt_long(argc, argv, "hf:di:It", long_opts, NULL);
98 		if (c == -1)
99 			break;
100 
101 		switch (c) {
102 			char *endptr;
103 			long interval;
104 
105 		case 'f':
106 			params.dp_type = nl_cli_parse_dumptype(optarg);
107 			break;
108 
109 		case 'd':
110 			dump_on_change = true;
111 			break;
112 
113 		case 'i':
114 			errno = 0;
115 			interval = strtol(optarg, &endptr, 0);
116 			if (interval < 0 || errno || *endptr) {
117 				nl_cli_fatal(EINVAL, "Invalid interval \"%s\".\n",
118 					     optarg);
119 				exit(1);
120 			}
121 			if (!interval) {
122 				dump_on_timeout = false;
123 			} else {
124 				timeout = interval * 1000;
125 			}
126 
127 			break;
128 
129 		case 'I':
130 			iter = true;
131 			break;
132 
133 		case 't':
134 			print_ts = true;
135 			break;
136 
137 		case 'h':
138 			print_usage(stdout, argv[0]);
139 			exit(0);
140 
141 		case '?':
142 			print_usage(stderr, argv[0]);
143 			exit(1);
144 		}
145 	}
146 
147 	err = nl_cache_mngr_alloc(NULL, NETLINK_ROUTE, NL_AUTO_PROVIDE, &mngr);
148 	if (err < 0)
149 		nl_cli_fatal(err, "Unable to allocate cache manager: %s",
150 			     nl_geterror(err));
151 
152 	while (optind < argc) {
153 		struct nl_cache *cache;
154 
155 		err = nl_cache_alloc_name(argv[optind], &cache);
156 		if (err < 0)
157 			nl_cli_fatal(err, "Couldn't add cache %s: %s\n",
158 				     argv[optind], nl_geterror(err));
159 
160 		if (iter)
161 			nl_cache_set_flags(cache, NL_CACHE_AF_ITER);
162 
163 		err = nl_cache_mngr_add_cache(mngr, cache, &change_cb, NULL);
164 		if (err < 0)
165 			nl_cli_fatal(err, "Unable to add cache %s: %s",
166 				     argv[optind], nl_geterror(err));
167 
168 		optind++;
169 	}
170 
171 	params.dp_fd = stdout;
172 	signal(SIGINT, sigint);
173 
174 	while (!quit) {
175 		err = nl_cache_mngr_poll(mngr, timeout);
176 		if (err < 0 && err != -NLE_INTR)
177 			nl_cli_fatal(err, "Polling failed: %s", nl_geterror(err));
178 
179 		if (dump_on_timeout || (dump_on_change && change)) {
180 			nl_cache_mngr_info(mngr, &params);
181 			fflush(stdout);
182 			change = 0;
183 		}
184 	}
185 
186 	nl_cache_mngr_free(mngr);
187 
188 	return 0;
189 }
190