iproute2/devlink/mnlg.c
<<
>>
Prefs
   1/*
   2 *   mnlg.c     Generic Netlink helpers for libmnl
   3 *
   4 *              This program is free software; you can redistribute 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:     Jiri Pirko <jiri@mellanox.com>
  10 */
  11
  12#include <stdlib.h>
  13#include <stdbool.h>
  14#include <string.h>
  15#include <errno.h>
  16#include <unistd.h>
  17#include <libmnl/libmnl.h>
  18#include <linux/genetlink.h>
  19
  20#include "libnetlink.h"
  21#include "mnl_utils.h"
  22#include "utils.h"
  23#include "mnlg.h"
  24
  25struct mnlg_socket {
  26        struct mnl_socket *nl;
  27        char *buf;
  28        uint32_t id;
  29        uint8_t version;
  30        unsigned int seq;
  31};
  32
  33int mnlg_socket_send(struct mnlu_gen_socket *nlg, const struct nlmsghdr *nlh)
  34{
  35        return mnl_socket_sendto(nlg->nl, nlh, nlh->nlmsg_len);
  36}
  37
  38struct group_info {
  39        bool found;
  40        uint32_t id;
  41        const char *name;
  42};
  43
  44static int parse_mc_grps_cb(const struct nlattr *attr, void *data)
  45{
  46        const struct nlattr **tb = data;
  47        int type = mnl_attr_get_type(attr);
  48
  49        if (mnl_attr_type_valid(attr, CTRL_ATTR_MCAST_GRP_MAX) < 0)
  50                return MNL_CB_OK;
  51
  52        switch (type) {
  53        case CTRL_ATTR_MCAST_GRP_ID:
  54                if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
  55                        return MNL_CB_ERROR;
  56                break;
  57        case CTRL_ATTR_MCAST_GRP_NAME:
  58                if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
  59                        return MNL_CB_ERROR;
  60                break;
  61        }
  62        tb[type] = attr;
  63        return MNL_CB_OK;
  64}
  65
  66static void parse_genl_mc_grps(struct nlattr *nested,
  67                               struct group_info *group_info)
  68{
  69        struct nlattr *pos;
  70        const char *name;
  71
  72        mnl_attr_for_each_nested(pos, nested) {
  73                struct nlattr *tb[CTRL_ATTR_MCAST_GRP_MAX + 1] = {};
  74
  75                mnl_attr_parse_nested(pos, parse_mc_grps_cb, tb);
  76                if (!tb[CTRL_ATTR_MCAST_GRP_NAME] ||
  77                    !tb[CTRL_ATTR_MCAST_GRP_ID])
  78                        continue;
  79
  80                name = mnl_attr_get_str(tb[CTRL_ATTR_MCAST_GRP_NAME]);
  81                if (strcmp(name, group_info->name) != 0)
  82                        continue;
  83
  84                group_info->id = mnl_attr_get_u32(tb[CTRL_ATTR_MCAST_GRP_ID]);
  85                group_info->found = true;
  86        }
  87}
  88
  89static int get_group_id_attr_cb(const struct nlattr *attr, void *data)
  90{
  91        const struct nlattr **tb = data;
  92        int type = mnl_attr_get_type(attr);
  93
  94        if (mnl_attr_type_valid(attr, CTRL_ATTR_MAX) < 0)
  95                return MNL_CB_ERROR;
  96
  97        if (type == CTRL_ATTR_MCAST_GROUPS &&
  98            mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
  99                return MNL_CB_ERROR;
 100        tb[type] = attr;
 101        return MNL_CB_OK;
 102}
 103
 104static int get_group_id_cb(const struct nlmsghdr *nlh, void *data)
 105{
 106        struct group_info *group_info = data;
 107        struct nlattr *tb[CTRL_ATTR_MAX + 1] = {};
 108        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
 109
 110        mnl_attr_parse(nlh, sizeof(*genl), get_group_id_attr_cb, tb);
 111        if (!tb[CTRL_ATTR_MCAST_GROUPS])
 112                return MNL_CB_ERROR;
 113        parse_genl_mc_grps(tb[CTRL_ATTR_MCAST_GROUPS], group_info);
 114        return MNL_CB_OK;
 115}
 116
 117int mnlg_socket_group_add(struct mnlu_gen_socket *nlg, const char *group_name)
 118{
 119        struct nlmsghdr *nlh;
 120        struct group_info group_info;
 121        int err;
 122
 123        nlh = _mnlu_gen_socket_cmd_prepare(nlg, CTRL_CMD_GETFAMILY,
 124                                           NLM_F_REQUEST | NLM_F_ACK,
 125                                           GENL_ID_CTRL, 1);
 126
 127        mnl_attr_put_u16(nlh, CTRL_ATTR_FAMILY_ID, nlg->family);
 128
 129        err = mnlg_socket_send(nlg, nlh);
 130        if (err < 0)
 131                return err;
 132
 133        group_info.found = false;
 134        group_info.name = group_name;
 135        err = mnlu_gen_socket_recv_run(nlg, get_group_id_cb, &group_info);
 136        if (err < 0)
 137                return err;
 138
 139        if (!group_info.found) {
 140                errno = ENOENT;
 141                return -1;
 142        }
 143
 144        err = mnl_socket_setsockopt(nlg->nl, NETLINK_ADD_MEMBERSHIP,
 145                                    &group_info.id, sizeof(group_info.id));
 146        if (err < 0)
 147                return err;
 148
 149        return 0;
 150}
 151
 152int mnlg_socket_get_fd(struct mnlu_gen_socket *nlg)
 153{
 154        return mnl_socket_get_fd(nlg->nl);
 155}
 156