summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorThomas Graf <tgraf@redhat.com>2012-06-01 09:48:08 (GMT)
committerThomas Graf <tgraf@redhat.com>2012-06-01 09:48:08 (GMT)
commitfaef2fa45f67da810415f4dd4f0ce62d70965ad4 (patch)
tree2d14c8d9788b4468cb3eb78debd377581f6aa920 /tests
parent3656b6f908f966f329fb727a805ee46934c360d0 (diff)
downloadlibnl-faef2fa45f67da810415f4dd4f0ce62d70965ad4.zip
libnl-faef2fa45f67da810415f4dd4f0ce62d70965ad4.tar.gz
libnl-faef2fa45f67da810415f4dd4f0ce62d70965ad4.tar.bz2
genl: Support registration of families without depending on caches
Introduces the functions genl_register_family() and genl_unregister_family() to register a Generic Netlink family which does not implement a cachable type. API users can direct received messages into genl_handle_msg() which will validate the messages and call the callback functions defined in the commands definition. See test/test-genl.c for an example on how to use it.
Diffstat (limited to 'tests')
-rw-r--r--tests/test-genl.c87
1 files changed, 83 insertions, 4 deletions
diff --git a/tests/test-genl.c b/tests/test-genl.c
index 2706a92..63862b3 100644
--- a/tests/test-genl.c
+++ b/tests/test-genl.c
@@ -1,4 +1,72 @@
#include <netlink/cli/utils.h>
+#include <linux/taskstats.h>
+
+static struct nla_policy attr_policy[TASKSTATS_TYPE_MAX+1] = {
+ [TASKSTATS_TYPE_PID] = { .type = NLA_U32 },
+ [TASKSTATS_TYPE_TGID] = { .type = NLA_U32 },
+ [TASKSTATS_TYPE_STATS] = { .minlen = sizeof(struct taskstats) },
+ [TASKSTATS_TYPE_AGGR_PID] = { .type = NLA_NESTED },
+ [TASKSTATS_TYPE_AGGR_TGID] = { .type = NLA_NESTED },
+};
+
+
+static int parse_cmd_new(struct nl_cache_ops *unused, struct genl_cmd *cmd,
+ struct genl_info *info, void *arg)
+{
+ struct nlattr *attrs[TASKSTATS_TYPE_MAX+1];
+ struct nlattr *nested;
+ int err;
+
+ if (info->attrs[TASKSTATS_TYPE_AGGR_PID])
+ nested = info->attrs[TASKSTATS_TYPE_AGGR_PID];
+ else if (info->attrs[TASKSTATS_TYPE_AGGR_TGID])
+ nested = info->attrs[TASKSTATS_TYPE_AGGR_TGID];
+ else {
+ fprintf(stderr, "Invalid taskstats message: Unable to find "
+ "nested attribute/\n");
+ return NL_SKIP;
+ }
+
+ err = nla_parse_nested(attrs, TASKSTATS_TYPE_MAX, nested, attr_policy);
+ if (err < 0) {
+ nl_perror(err, "Error while parsing generic netlink message");
+ return err;
+ }
+
+
+ if (attrs[TASKSTATS_TYPE_STATS]) {
+ struct taskstats *stats = nla_data(attrs[TASKSTATS_TYPE_STATS]);
+
+ printf("%s pid %u uid %u gid %u parent %u\n",
+ stats->ac_comm, stats->ac_pid, stats->ac_uid,
+ stats->ac_gid, stats->ac_ppid);
+ }
+
+ return 0;
+}
+
+static int parse_cb(struct nl_msg *msg, void *arg)
+{
+ return genl_handle_msg(msg, NULL);
+}
+
+static struct genl_cmd cmds[] = {
+ {
+ .c_id = TASKSTATS_CMD_NEW,
+ .c_name = "taskstats_new()",
+ .c_maxattr = TASKSTATS_TYPE_MAX,
+ .c_attr_policy = attr_policy,
+ .c_msg_parser = &parse_cmd_new,
+ },
+};
+
+#define ARRAY_SIZE(X) (sizeof(X) / sizeof((X)[0]))
+
+static struct genl_ops ops = {
+ .o_name = TASKSTATS_GENL_NAME,
+ .o_cmds = cmds,
+ .o_ncmds = ARRAY_SIZE(cmds),
+};
int main(int argc, char *argv[])
{
@@ -10,25 +78,36 @@ int main(int argc, char *argv[])
sock = nl_cli_alloc_socket();
nl_cli_connect(sock, NETLINK_GENERIC);
+ if ((err = genl_register_family(&ops)) < 0)
+ nl_cli_fatal(err, "Unable to register Generic Netlink family");
+
+ if ((err = genl_ops_resolve(sock, &ops)) < 0)
+ nl_cli_fatal(err, "Unable to resolve family name");
+
msg = nlmsg_alloc();
if (msg == NULL)
nl_cli_fatal(NLE_NOMEM, "Unable to allocate netlink message");
- hdr = genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, GENL_ID_CTRL,
- 0, 0, CTRL_CMD_GETFAMILY, 1);
+ hdr = genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, ops.o_id,
+ 0, 0, TASKSTATS_CMD_GET, TASKSTATS_GENL_VERSION);
if (hdr == NULL)
nl_cli_fatal(ENOMEM, "Unable to write genl header");
- if ((err = nla_put_u32(msg, CTRL_ATTR_FAMILY_ID, GENL_ID_CTRL)) < 0)
+ if ((err = nla_put_u32(msg, TASKSTATS_CMD_ATTR_PID, 1)) < 0)
nl_cli_fatal(err, "Unable to add attribute: %s", nl_geterror(err));
if ((err = nl_send_auto_complete(sock, msg)) < 0)
nl_cli_fatal(err, "Unable to send message: %s", nl_geterror(err));
+ nlmsg_free(msg);
+
+ if ((err = nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM,
+ parse_cb, NULL)) < 0)
+ nl_cli_fatal(err, "Unable to modify valid message callback");
+
if ((err = nl_recvmsgs_default(sock)) < 0)
nl_cli_fatal(err, "Unable to receive message: %s", nl_geterror(err));
- nlmsg_free(msg);
nl_close(sock);
nl_socket_free(sock);