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