/* * lib/route/cls/cgroup.c Control Groups Classifier * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation version 2.1 * of the License. * * Copyright (c) 2009 Thomas Graf <tgraf@suug.ch> */ /** * @ingroup cls_api * @defgroup cgroup Control Groups Classifier * * @{ */ #include <netlink-local.h> #include <netlink-tc.h> #include <netlink/netlink.h> #include <netlink/attr.h> #include <netlink/utils.h> #include <netlink/route/classifier.h> #include <netlink/route/classifier-modules.h> #include <netlink/route/cls/cgroup.h> #include <netlink/route/cls/ematch.h> /** @cond SKIP */ #define CGROUP_ATTR_EMATCH 0x001 /** @endcond */ static struct nla_policy cgroup_policy[TCA_CGROUP_MAX+1] = { [TCA_CGROUP_EMATCHES] = { .type = NLA_NESTED }, }; static void cgroup_free_data(struct rtnl_cls *cls) { struct rtnl_cgroup *cg = rtnl_cls_data(cls); rtnl_ematch_tree_free(cg->cg_ematch); } static int cgroup_msg_parser(struct rtnl_cls *cls) { struct rtnl_cgroup *cg = rtnl_cls_data(cls); struct nlattr *tb[TCA_CGROUP_MAX + 1]; int err; err = tca_parse(tb, TCA_CGROUP_MAX, (struct rtnl_tca *) cls, cgroup_policy); if (err < 0) return err; if (tb[TCA_CGROUP_EMATCHES]) { if ((err = rtnl_ematch_parse(tb[TCA_CGROUP_EMATCHES], &cg->cg_ematch)) < 0) return err; cg->cg_mask |= CGROUP_ATTR_EMATCH; } #if 0 TODO: TCA_CGROUP_ACT, TCA_CGROUP_POLICE, #endif return 0; } static void cgroup_dump_line(struct rtnl_cls *cls, struct nl_dump_params *p) { struct rtnl_cgroup *cg = rtnl_cls_data(cls); if (cg->cg_mask & CGROUP_ATTR_EMATCH) nl_dump(p, " ematch"); else nl_dump(p, " match-all"); } static void cgroup_dump_details(struct rtnl_cls *cls, struct nl_dump_params *p) { struct rtnl_cgroup *cg = rtnl_cls_data(cls); if (cg->cg_mask & CGROUP_ATTR_EMATCH) { nl_dump(p, "\n"); nl_dump_line(p, " ematch "); rtnl_ematch_tree_dump(cg->cg_ematch, p); } } /** * @name Attribute Modifications * @{ */ int rtnl_cgroup_set_ematch(struct rtnl_cls *cls, struct rtnl_ematch_tree *tree) { struct rtnl_cgroup *cg = rtnl_cls_data(cls); if (cg->cg_ematch) { rtnl_ematch_tree_free(cg->cg_ematch); cg->cg_mask &= ~CGROUP_ATTR_EMATCH; } cg->cg_ematch = tree; if (tree) cg->cg_mask |= CGROUP_ATTR_EMATCH; return 0; } struct rtnl_ematch_tree *rtnl_cgroup_get_ematch(struct rtnl_cls *cls) { struct rtnl_cgroup *cg = rtnl_cls_data(cls); return cg->cg_ematch; } static struct rtnl_cls_ops cgroup_ops = { .co_kind = "cgroup", .co_size = sizeof(struct rtnl_cgroup), .co_msg_parser = cgroup_msg_parser, .co_free_data = cgroup_free_data, .co_dump = { [NL_DUMP_LINE] = cgroup_dump_line, [NL_DUMP_DETAILS] = cgroup_dump_details, }, }; static void __init cgroup_init(void) { rtnl_cls_register(&cgroup_ops); } static void __exit cgroup_exit(void) { rtnl_cls_unregister(&cgroup_ops); } /** @} */