2 * ctrl.c generic netlink controller
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.
9 * Authors: J Hadi Salim (hadi@cyberus.ca)
10 * Johannes Berg (johannes@sipsolutions.net)
17 #include <sys/socket.h>
18 #include <netinet/in.h>
19 #include <arpa/inet.h>
23 #include "genl_utils.h"
25 #define GENL_MAX_FAM_OPS 256
26 #define GENL_MAX_FAM_GRPS 256
28 static int usage(void)
30 fprintf(stderr
,"Usage: ctrl <CMD>\n" \
31 "CMD := get <PARMS> | list | monitor | policy <PARMS>\n" \
32 "PARMS := name <name> | id <id>\n" \
36 "\tctrl get name foobar\n" \
38 "\tctrl policy name foobar\n"
39 "\tctrl policy id 0xF\n");
43 static void print_ctrl_cmd_flags(FILE *fp
, __u32 fl
)
45 fprintf(fp
, "\n\t\tCapabilities (0x%x):\n ", fl
);
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");
64 static int print_ctrl_cmds(FILE *fp
, struct rtattr
*arg
, __u32 ctrl_ver
)
66 struct rtattr
*tb
[CTRL_ATTR_OP_MAX
+ 1];
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
);
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
);
85 static int print_ctrl_grp(FILE *fp
, struct rtattr
*arg
, __u32 ctrl_ver
)
87 struct rtattr
*tb
[CTRL_ATTR_MCAST_GRP_MAX
+ 1];
92 parse_rtattr_nested(tb
, CTRL_ATTR_MCAST_GRP_MAX
, arg
);
94 __u32
*id
= RTA_DATA(tb
[CTRL_ATTR_MCAST_GRP_ID
]);
95 fprintf(fp
, " ID-0x%x ",*id
);
98 char *name
= RTA_DATA(tb
[CTRL_ATTR_MCAST_GRP_NAME
]);
99 fprintf(fp
, " name: %s ", name
);
106 * The controller sends one nlmsg per family
108 static int print_ctrl(struct rtnl_ctrl_data
*ctrl
,
109 struct nlmsghdr
*n
, void *arg
)
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
;
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
);
124 if (ghdr
->cmd
!= CTRL_CMD_GETFAMILY
&&
125 ghdr
->cmd
!= CTRL_CMD_DELFAMILY
&&
126 ghdr
->cmd
!= CTRL_CMD_NEWFAMILY
&&
127 ghdr
->cmd
!= CTRL_CMD_NEWMCAST_GRP
&&
128 ghdr
->cmd
!= CTRL_CMD_DELMCAST_GRP
&&
129 ghdr
->cmd
!= CTRL_CMD_GETPOLICY
) {
130 fprintf(stderr
, "Unknown controller command %d\n", ghdr
->cmd
);
134 len
-= NLMSG_LENGTH(GENL_HDRLEN
);
137 fprintf(stderr
, "wrong controller message len %d\n", len
);
141 attrs
= (struct rtattr
*) ((char *) ghdr
+ GENL_HDRLEN
);
142 parse_rtattr_flags(tb
, CTRL_ATTR_MAX
, attrs
, len
, NLA_F_NESTED
);
144 if (tb
[CTRL_ATTR_FAMILY_NAME
]) {
145 char *name
= RTA_DATA(tb
[CTRL_ATTR_FAMILY_NAME
]);
146 fprintf(fp
, "\nName: %s\n",name
);
148 if (tb
[CTRL_ATTR_FAMILY_ID
]) {
149 __u16
*id
= RTA_DATA(tb
[CTRL_ATTR_FAMILY_ID
]);
150 fprintf(fp
, "\tID: 0x%x ",*id
);
152 if (tb
[CTRL_ATTR_VERSION
]) {
153 __u32
*v
= RTA_DATA(tb
[CTRL_ATTR_VERSION
]);
154 fprintf(fp
, " Version: 0x%x ",*v
);
157 if (tb
[CTRL_ATTR_HDRSIZE
]) {
158 __u32
*h
= RTA_DATA(tb
[CTRL_ATTR_HDRSIZE
]);
159 fprintf(fp
, " header size: %d ",*h
);
161 if (tb
[CTRL_ATTR_MAXATTR
]) {
162 __u32
*ma
= RTA_DATA(tb
[CTRL_ATTR_MAXATTR
]);
163 fprintf(fp
, " max attribs: %d ",*ma
);
165 if (tb
[CTRL_ATTR_OP_POLICY
]) {
166 const struct rtattr
*pos
;
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
);
173 parse_rtattr_flags(ptb
, CTRL_ATTR_POLICY_DUMP_MAX
,
174 pattrs
, plen
, NLA_F_NESTED
);
176 fprintf(fp
, " op %d policies:",
177 pos
->rta_type
& ~NLA_F_NESTED
);
179 if (ptb
[CTRL_ATTR_POLICY_DO
]) {
180 __u32
*v
= RTA_DATA(ptb
[CTRL_ATTR_POLICY_DO
]);
182 fprintf(fp
, " do=%d", *v
);
185 if (ptb
[CTRL_ATTR_POLICY_DUMP
]) {
186 __u32
*v
= RTA_DATA(ptb
[CTRL_ATTR_POLICY_DUMP
]);
188 fprintf(fp
, " dump=%d", *v
);
192 if (tb
[CTRL_ATTR_POLICY
])
193 nl_print_policy(tb
[CTRL_ATTR_POLICY
], fp
);
195 /* end of family definitions .. */
197 if (tb
[CTRL_ATTR_OPS
]) {
198 struct rtattr
*tb2
[GENL_MAX_FAM_OPS
];
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
++) {
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");
208 /* for next command */
213 /* end of family::cmds definitions .. */
217 if (tb
[CTRL_ATTR_MCAST_GROUPS
]) {
218 struct rtattr
*tb2
[GENL_MAX_FAM_GRPS
+ 1];
221 parse_rtattr_nested(tb2
, GENL_MAX_FAM_GRPS
,
222 tb
[CTRL_ATTR_MCAST_GROUPS
]);
223 fprintf(fp
, "\tmulticast groups:\n");
225 for (i
= 0; i
< GENL_MAX_FAM_GRPS
; 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");
235 /* end of family::groups definitions .. */
243 static int print_ctrl2(struct nlmsghdr
*n
, void *arg
)
245 return print_ctrl(NULL
, n
, arg
);
248 static int ctrl_list(int cmd
, int argc
, char **argv
)
250 struct rtnl_handle rth
;
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
,
263 struct nlmsghdr
*nlh
= &req
.n
;
264 struct nlmsghdr
*answer
= NULL
;
266 if (rtnl_open_byproto(&rth
, 0, NETLINK_GENERIC
) < 0) {
267 fprintf(stderr
, "Cannot open generic netlink socket\n");
271 if (cmd
== CTRL_CMD_GETFAMILY
|| cmd
== CTRL_CMD_GETPOLICY
) {
275 fprintf(stderr
, "Wrong number of params\n");
279 if (matches(*argv
, "name") == 0) {
281 strlcpy(d
, *argv
, sizeof(d
));
282 addattr_l(nlh
, 128, CTRL_ATTR_FAMILY_NAME
,
284 } else if (matches(*argv
, "id") == 0) {
287 if (get_u16(&id
, *argv
, 0)) {
288 fprintf(stderr
, "Illegal \"id\"\n");
292 addattr_l(nlh
, 128, CTRL_ATTR_FAMILY_ID
, &id
, 2);
295 fprintf(stderr
, "Wrong params\n");
300 if (cmd
== CTRL_CMD_GETFAMILY
) {
301 if (rtnl_talk(&rth
, nlh
, &answer
) < 0) {
302 fprintf(stderr
, "Error talking to the kernel\n");
306 if (print_ctrl2(answer
, (void *) stdout
) < 0) {
307 fprintf(stderr
, "Dump terminated\n");
313 if (cmd
== CTRL_CMD_UNSPEC
|| cmd
== CTRL_CMD_GETPOLICY
) {
314 nlh
->nlmsg_flags
= NLM_F_ROOT
|NLM_F_MATCH
|NLM_F_REQUEST
;
315 nlh
->nlmsg_seq
= rth
.dump
= ++rth
.seq
;
317 if (rtnl_send(&rth
, nlh
, nlh
->nlmsg_len
) < 0) {
318 perror("Failed to send dump request\n");
322 rtnl_dump_filter(&rth
, print_ctrl2
, stdout
);
333 static int ctrl_listen(int argc
, char **argv
)
335 struct rtnl_handle rth
;
337 if (rtnl_open_byproto(&rth
, nl_mgrp(GENL_ID_CTRL
), NETLINK_GENERIC
) < 0) {
338 fprintf(stderr
, "Canot open generic netlink socket\n");
342 if (rtnl_listen(&rth
, print_ctrl
, (void *) stdout
) < 0)
348 static int parse_ctrl(struct genl_util
*a
, int argc
, char **argv
)
352 fprintf(stderr
, "wrong controller params\n");
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);
364 if (matches(*argv
, "policy") == 0)
365 return ctrl_list(CTRL_CMD_GETPOLICY
, argc
-1, argv
+1);
366 if (matches(*argv
, "help") == 0)
369 fprintf(stderr
, "ctrl command \"%s\" is unknown, try \"ctrl help\".\n",
375 struct genl_util ctrl_genl_util
= {
377 .parse_genlopt
= parse_ctrl
,
378 .print_genlopt
= print_ctrl2
,