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