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