iproute2/genl/ctrl.c
<<
>>
Prefs
   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
  28static int usage(void)
  29{
  30        fprintf(stderr,"Usage: ctrl <CMD>\n" \
  31                       "CMD   := get <PARMS> | list | monitor | policy <PARMS>\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                       "\tctrl policy name foobar\n"
  39                       "\tctrl policy id 0xF\n");
  40        return -1;
  41}
  42
  43static void print_ctrl_cmd_flags(FILE *fp, __u32 fl)
  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}
  63
  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
  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
 105/*
 106 * The controller sends one nlmsg per family
 107*/
 108static int print_ctrl(struct rtnl_ctrl_data *ctrl,
 109                      struct nlmsghdr *n, void *arg)
 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;
 116        __u32 ctrl_v = 0x1;
 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 &&
 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);
 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);
 142        parse_rtattr_flags(tb, CTRL_ATTR_MAX, attrs, len, NLA_F_NESTED);
 143
 144        if (tb[CTRL_ATTR_FAMILY_NAME]) {
 145                char *name = RTA_DATA(tb[CTRL_ATTR_FAMILY_NAME]);
 146                fprintf(fp, "\nName: %s\n",name);
 147        }
 148        if (tb[CTRL_ATTR_FAMILY_ID]) {
 149                __u16 *id = RTA_DATA(tb[CTRL_ATTR_FAMILY_ID]);
 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;
 156        }
 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        }
 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        }
 192        if (tb[CTRL_ATTR_POLICY])
 193                nl_print_policy(tb[CTRL_ATTR_POLICY], fp);
 194
 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                }
 212
 213                /* end of family::cmds definitions .. */
 214                fprintf(fp,"\n");
 215        }
 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
 239        fflush(fp);
 240        return 0;
 241}
 242
 243static int print_ctrl2(struct nlmsghdr *n, void *arg)
 244{
 245        return print_ctrl(NULL, n, arg);
 246}
 247
 248static int ctrl_list(int cmd, int argc, char **argv)
 249{
 250        struct rtnl_handle rth;
 251        int ret = -1;
 252        char d[GENL_NAMSIZ];
 253        struct {
 254                struct nlmsghdr         n;
 255                struct genlmsghdr       g;
 256                char                    buf[4096];
 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;
 264        struct nlmsghdr *answer = NULL;
 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
 271        if (cmd == CTRL_CMD_GETFAMILY || cmd == CTRL_CMD_GETPOLICY) {
 272                req.g.cmd = cmd;
 273
 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();
 281                        strlcpy(d, *argv, sizeof(d));
 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                }
 298        }
 299
 300        if (cmd == CTRL_CMD_GETFAMILY) {
 301                if (rtnl_talk(&rth, nlh, &answer) < 0) {
 302                        fprintf(stderr, "Error talking to the kernel\n");
 303                        goto ctrl_done;
 304                }
 305
 306                if (print_ctrl2(answer, (void *) stdout) < 0) {
 307                        fprintf(stderr, "Dump terminated\n");
 308                        goto ctrl_done;
 309                }
 310
 311        }
 312
 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;
 316
 317                if (rtnl_send(&rth, nlh, nlh->nlmsg_len) < 0) {
 318                        perror("Failed to send dump request\n");
 319                        goto ctrl_done;
 320                }
 321
 322                rtnl_dump_filter(&rth, print_ctrl2, stdout);
 323
 324        }
 325
 326        ret = 0;
 327ctrl_done:
 328        free(answer);
 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);
 364        if (matches(*argv, "policy") == 0)
 365                return ctrl_list(CTRL_CMD_GETPOLICY, argc-1, argv+1);
 366        if (matches(*argv, "help") == 0)
 367                return usage();
 368
 369        fprintf(stderr, "ctrl command \"%s\" is unknown, try \"ctrl help\".\n",
 370                *argv);
 371
 372        return -1;
 373}
 374
 375struct genl_util ctrl_genl_util = {
 376        .name = "ctrl",
 377        .parse_genlopt = parse_ctrl,
 378        .print_genlopt = print_ctrl2,
 379};
 380