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