]> git.proxmox.com Git - mirror_iproute2.git/blame - genl/ctrl.c
Use libbsd for strlcpy if available
[mirror_iproute2.git] / genl / ctrl.c
CommitLineData
65018ae4
JHS
1/*
2 * ctrl.c generic netlink controller
3 *
4 * This program is free software; you can distribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
80c05b09
JB
9 * Authors: J Hadi Salim (hadi@cyberus.ca)
10 * Johannes Berg (johannes@sipsolutions.net)
65018ae4
JHS
11 */
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <unistd.h>
65018ae4
JHS
16#include <fcntl.h>
17#include <sys/socket.h>
18#include <netinet/in.h>
19#include <arpa/inet.h>
20#include <string.h>
508f3c23
LB
21#ifdef HAVE_LIBBSD
22#include <bsd/string.h>
23#endif
65018ae4
JHS
24
25#include "utils.h"
26#include "genl_utils.h"
27
26328fc3 28#define GENL_MAX_FAM_OPS 256
80c05b09
JB
29#define GENL_MAX_FAM_GRPS 256
30
65018ae4
JHS
31static int usage(void)
32{
33 fprintf(stderr,"Usage: ctrl <CMD>\n" \
34 "CMD := get <PARMS> | list | monitor\n" \
35 "PARMS := name <name> | id <id>\n" \
36 "Examples:\n" \
37 "\tctrl ls\n" \
38 "\tctrl monitor\n" \
39 "\tctrl get name foobar\n" \
40 "\tctrl get id 0xF\n");
41 return -1;
42}
43
44int genl_ctrl_resolve_family(const char *family)
45{
46 struct rtnl_handle rth;
65018ae4
JHS
47 int ret = 0;
48 struct {
49 struct nlmsghdr n;
d17b136f 50 struct genlmsghdr g;
65018ae4 51 char buf[4096];
d17b136f
PS
52 } req = {
53 .n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN),
54 .n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
55 .n.nlmsg_type = GENL_ID_CTRL,
56 .g.cmd = CTRL_CMD_GETFAMILY,
57 };
58 struct nlmsghdr *nlh = &req.n;
59 struct genlmsghdr *ghdr = &req.g;
86bf43c7 60 struct nlmsghdr *answer = NULL;
65018ae4
JHS
61
62 if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC) < 0) {
63 fprintf(stderr, "Cannot open generic netlink socket\n");
64 exit(1);
65 }
66
67 addattr_l(nlh, 128, CTRL_ATTR_FAMILY_NAME, family, strlen(family) + 1);
68
86bf43c7 69 if (rtnl_talk(&rth, nlh, &answer) < 0) {
65018ae4
JHS
70 fprintf(stderr, "Error talking to the kernel\n");
71 goto errout;
72 }
73
74 {
75 struct rtattr *tb[CTRL_ATTR_MAX + 1];
86bf43c7 76 int len = answer->nlmsg_len;
65018ae4
JHS
77 struct rtattr *attrs;
78
86bf43c7 79 if (answer->nlmsg_type != GENL_ID_CTRL) {
65018ae4 80 fprintf(stderr, "Not a controller message, nlmsg_len=%d "
86bf43c7 81 "nlmsg_type=0x%x\n", answer->nlmsg_len, answer->nlmsg_type);
65018ae4
JHS
82 goto errout;
83 }
84
85 if (ghdr->cmd != CTRL_CMD_NEWFAMILY) {
80c05b09 86 fprintf(stderr, "Unknown controller command %d\n", ghdr->cmd);
65018ae4
JHS
87 goto errout;
88 }
89
90 len -= NLMSG_LENGTH(GENL_HDRLEN);
91
92 if (len < 0) {
93 fprintf(stderr, "wrong controller message len %d\n", len);
86bf43c7 94 free(answer);
65018ae4
JHS
95 return -1;
96 }
97
86bf43c7 98 attrs = (struct rtattr *) ((char *) answer + NLMSG_LENGTH(GENL_HDRLEN));
65018ae4
JHS
99 parse_rtattr(tb, CTRL_ATTR_MAX, attrs, len);
100
101 if (tb[CTRL_ATTR_FAMILY_ID] == NULL) {
102 fprintf(stderr, "Missing family id TLV\n");
103 goto errout;
104 }
105
ff24746c 106 ret = rta_getattr_u16(tb[CTRL_ATTR_FAMILY_ID]);
65018ae4
JHS
107 }
108
109errout:
86bf43c7 110 free(answer);
65018ae4
JHS
111 rtnl_close(&rth);
112 return ret;
113}
114
d1f28cf1 115static void print_ctrl_cmd_flags(FILE *fp, __u32 fl)
26328fc3 116{
117 fprintf(fp, "\n\t\tCapabilities (0x%x):\n ", fl);
118 if (!fl) {
119 fprintf(fp, "\n");
120 return;
121 }
122 fprintf(fp, "\t\t ");
123
124 if (fl & GENL_ADMIN_PERM)
125 fprintf(fp, " requires admin permission;");
126 if (fl & GENL_CMD_CAP_DO)
127 fprintf(fp, " can doit;");
128 if (fl & GENL_CMD_CAP_DUMP)
129 fprintf(fp, " can dumpit;");
130 if (fl & GENL_CMD_CAP_HASPOL)
131 fprintf(fp, " has policy");
132
133 fprintf(fp, "\n");
134}
e9e9365b 135
26328fc3 136static int print_ctrl_cmds(FILE *fp, struct rtattr *arg, __u32 ctrl_ver)
137{
138 struct rtattr *tb[CTRL_ATTR_OP_MAX + 1];
139
140 if (arg == NULL)
141 return -1;
142
143 parse_rtattr_nested(tb, CTRL_ATTR_OP_MAX, arg);
144 if (tb[CTRL_ATTR_OP_ID]) {
145 __u32 *id = RTA_DATA(tb[CTRL_ATTR_OP_ID]);
146 fprintf(fp, " ID-0x%x ",*id);
147 }
148 /* we are only gonna do this for newer version of the controller */
149 if (tb[CTRL_ATTR_OP_FLAGS] && ctrl_ver >= 0x2) {
150 __u32 *fl = RTA_DATA(tb[CTRL_ATTR_OP_FLAGS]);
151 print_ctrl_cmd_flags(fp, *fl);
152 }
153 return 0;
154
155}
156
80c05b09
JB
157static int print_ctrl_grp(FILE *fp, struct rtattr *arg, __u32 ctrl_ver)
158{
159 struct rtattr *tb[CTRL_ATTR_MCAST_GRP_MAX + 1];
160
161 if (arg == NULL)
162 return -1;
163
164 parse_rtattr_nested(tb, CTRL_ATTR_MCAST_GRP_MAX, arg);
165 if (tb[2]) {
166 __u32 *id = RTA_DATA(tb[CTRL_ATTR_MCAST_GRP_ID]);
167 fprintf(fp, " ID-0x%x ",*id);
168 }
169 if (tb[1]) {
170 char *name = RTA_DATA(tb[CTRL_ATTR_MCAST_GRP_NAME]);
171 fprintf(fp, " name: %s ", name);
172 }
173 return 0;
174
175}
176
26328fc3 177/*
178 * The controller sends one nlmsg per family
179*/
cd554f2c 180static int print_ctrl(struct rtnl_ctrl_data *ctrl,
0628cddd 181 struct nlmsghdr *n, void *arg)
65018ae4
JHS
182{
183 struct rtattr *tb[CTRL_ATTR_MAX + 1];
184 struct genlmsghdr *ghdr = NLMSG_DATA(n);
185 int len = n->nlmsg_len;
186 struct rtattr *attrs;
187 FILE *fp = (FILE *) arg;
81c61790 188 __u32 ctrl_v = 0x1;
65018ae4
JHS
189
190 if (n->nlmsg_type != GENL_ID_CTRL) {
191 fprintf(stderr, "Not a controller message, nlmsg_len=%d "
192 "nlmsg_type=0x%x\n", n->nlmsg_len, n->nlmsg_type);
193 return 0;
194 }
195
196 if (ghdr->cmd != CTRL_CMD_GETFAMILY &&
197 ghdr->cmd != CTRL_CMD_DELFAMILY &&
80c05b09
JB
198 ghdr->cmd != CTRL_CMD_NEWFAMILY &&
199 ghdr->cmd != CTRL_CMD_NEWMCAST_GRP &&
200 ghdr->cmd != CTRL_CMD_DELMCAST_GRP) {
201 fprintf(stderr, "Unknown controller command %d\n", ghdr->cmd);
65018ae4
JHS
202 return 0;
203 }
204
205 len -= NLMSG_LENGTH(GENL_HDRLEN);
206
207 if (len < 0) {
208 fprintf(stderr, "wrong controller message len %d\n", len);
209 return -1;
210 }
211
212 attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN);
213 parse_rtattr(tb, CTRL_ATTR_MAX, attrs, len);
214
215 if (tb[CTRL_ATTR_FAMILY_NAME]) {
216 char *name = RTA_DATA(tb[CTRL_ATTR_FAMILY_NAME]);
26328fc3 217 fprintf(fp, "\nName: %s\n",name);
65018ae4
JHS
218 }
219 if (tb[CTRL_ATTR_FAMILY_ID]) {
220 __u16 *id = RTA_DATA(tb[CTRL_ATTR_FAMILY_ID]);
26328fc3 221 fprintf(fp, "\tID: 0x%x ",*id);
222 }
223 if (tb[CTRL_ATTR_VERSION]) {
224 __u32 *v = RTA_DATA(tb[CTRL_ATTR_VERSION]);
225 fprintf(fp, " Version: 0x%x ",*v);
226 ctrl_v = *v;
65018ae4 227 }
26328fc3 228 if (tb[CTRL_ATTR_HDRSIZE]) {
229 __u32 *h = RTA_DATA(tb[CTRL_ATTR_HDRSIZE]);
230 fprintf(fp, " header size: %d ",*h);
231 }
232 if (tb[CTRL_ATTR_MAXATTR]) {
233 __u32 *ma = RTA_DATA(tb[CTRL_ATTR_MAXATTR]);
234 fprintf(fp, " max attribs: %d ",*ma);
235 }
236 /* end of family definitions .. */
237 fprintf(fp,"\n");
238 if (tb[CTRL_ATTR_OPS]) {
239 struct rtattr *tb2[GENL_MAX_FAM_OPS];
240 int i=0;
241 parse_rtattr_nested(tb2, GENL_MAX_FAM_OPS, tb[CTRL_ATTR_OPS]);
242 fprintf(fp, "\tcommands supported: \n");
243 for (i = 0; i < GENL_MAX_FAM_OPS; i++) {
244 if (tb2[i]) {
245 fprintf(fp, "\t\t#%d: ", i);
246 if (0 > print_ctrl_cmds(fp, tb2[i], ctrl_v)) {
247 fprintf(fp, "Error printing command\n");
248 }
249 /* for next command */
250 fprintf(fp,"\n");
251 }
252 }
65018ae4 253
26328fc3 254 /* end of family::cmds definitions .. */
255 fprintf(fp,"\n");
256 }
80c05b09
JB
257
258 if (tb[CTRL_ATTR_MCAST_GROUPS]) {
259 struct rtattr *tb2[GENL_MAX_FAM_GRPS + 1];
260 int i;
261
262 parse_rtattr_nested(tb2, GENL_MAX_FAM_GRPS,
263 tb[CTRL_ATTR_MCAST_GROUPS]);
264 fprintf(fp, "\tmulticast groups:\n");
265
266 for (i = 0; i < GENL_MAX_FAM_GRPS; i++) {
267 if (tb2[i]) {
268 fprintf(fp, "\t\t#%d: ", i);
269 if (0 > print_ctrl_grp(fp, tb2[i], ctrl_v))
270 fprintf(fp, "Error printing group\n");
271 /* for next group */
272 fprintf(fp,"\n");
273 }
274 }
275
276 /* end of family::groups definitions .. */
277 fprintf(fp,"\n");
278 }
279
65018ae4
JHS
280 fflush(fp);
281 return 0;
282}
283
cd554f2c 284static int print_ctrl2(struct nlmsghdr *n, void *arg)
0628cddd 285{
cd554f2c 286 return print_ctrl(NULL, n, arg);
0628cddd
ND
287}
288
65018ae4
JHS
289static int ctrl_list(int cmd, int argc, char **argv)
290{
291 struct rtnl_handle rth;
65018ae4
JHS
292 int ret = -1;
293 char d[GENL_NAMSIZ];
294 struct {
295 struct nlmsghdr n;
d17b136f 296 struct genlmsghdr g;
65018ae4 297 char buf[4096];
d17b136f
PS
298 } req = {
299 .n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN),
300 .n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
301 .n.nlmsg_type = GENL_ID_CTRL,
302 .g.cmd = CTRL_CMD_GETFAMILY,
303 };
304 struct nlmsghdr *nlh = &req.n;
86bf43c7 305 struct nlmsghdr *answer = NULL;
65018ae4
JHS
306
307 if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC) < 0) {
308 fprintf(stderr, "Cannot open generic netlink socket\n");
309 exit(1);
310 }
311
312 if (cmd == CTRL_CMD_GETFAMILY) {
313 if (argc != 2) {
314 fprintf(stderr, "Wrong number of params\n");
315 return -1;
316 }
317
318 if (matches(*argv, "name") == 0) {
319 NEXT_ARG();
532b8874 320 strlcpy(d, *argv, sizeof(d));
65018ae4
JHS
321 addattr_l(nlh, 128, CTRL_ATTR_FAMILY_NAME,
322 d, strlen(d) + 1);
323 } else if (matches(*argv, "id") == 0) {
324 __u16 id;
325 NEXT_ARG();
326 if (get_u16(&id, *argv, 0)) {
327 fprintf(stderr, "Illegal \"id\"\n");
328 goto ctrl_done;
329 }
330
331 addattr_l(nlh, 128, CTRL_ATTR_FAMILY_ID, &id, 2);
332
333 } else {
334 fprintf(stderr, "Wrong params\n");
335 goto ctrl_done;
336 }
337
86bf43c7 338 if (rtnl_talk(&rth, nlh, &answer) < 0) {
65018ae4
JHS
339 fprintf(stderr, "Error talking to the kernel\n");
340 goto ctrl_done;
341 }
342
cd554f2c 343 if (print_ctrl2(answer, (void *) stdout) < 0) {
65018ae4
JHS
344 fprintf(stderr, "Dump terminated\n");
345 goto ctrl_done;
346 }
347
348 }
349
350 if (cmd == CTRL_CMD_UNSPEC) {
351 nlh->nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
352 nlh->nlmsg_seq = rth.dump = ++rth.seq;
353
6cf8398f 354 if (rtnl_send(&rth, nlh, nlh->nlmsg_len) < 0) {
65018ae4
JHS
355 perror("Failed to send dump request\n");
356 goto ctrl_done;
357 }
358
0628cddd 359 rtnl_dump_filter(&rth, print_ctrl2, stdout);
65018ae4
JHS
360
361 }
362
363 ret = 0;
364ctrl_done:
86bf43c7 365 free(answer);
65018ae4
JHS
366 rtnl_close(&rth);
367 return ret;
368}
369
370static int ctrl_listen(int argc, char **argv)
371{
372 struct rtnl_handle rth;
373
374 if (rtnl_open_byproto(&rth, nl_mgrp(GENL_ID_CTRL), NETLINK_GENERIC) < 0) {
375 fprintf(stderr, "Canot open generic netlink socket\n");
376 return -1;
377 }
378
379 if (rtnl_listen(&rth, print_ctrl, (void *) stdout) < 0)
380 return -1;
381
382 return 0;
383}
384
385static int parse_ctrl(struct genl_util *a, int argc, char **argv)
386{
387 argv++;
388 if (--argc <= 0) {
389 fprintf(stderr, "wrong controller params\n");
390 return -1;
391 }
392
393 if (matches(*argv, "monitor") == 0)
394 return ctrl_listen(argc-1, argv+1);
395 if (matches(*argv, "get") == 0)
396 return ctrl_list(CTRL_CMD_GETFAMILY, argc-1, argv+1);
397 if (matches(*argv, "list") == 0 ||
398 matches(*argv, "show") == 0 ||
399 matches(*argv, "lst") == 0)
400 return ctrl_list(CTRL_CMD_UNSPEC, argc-1, argv+1);
401 if (matches(*argv, "help") == 0)
402 return usage();
403
3669d218 404 fprintf(stderr, "ctrl command \"%s\" is unknown, try \"ctrl help\".\n",
65018ae4
JHS
405 *argv);
406
407 return -1;
408}
409
410struct genl_util ctrl_genl_util = {
411 .name = "ctrl",
412 .parse_genlopt = parse_ctrl,
0628cddd 413 .print_genlopt = print_ctrl2,
65018ae4 414};