/* * 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-2010 Thomas Graf */ /** * @ingroup cls_api * @defgroup cgroup Control Groups Classifier * * @{ */ #include #include #include #include #include #include #include #include #include /** @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 int cgroup_clone(struct rtnl_cls *_dst, struct rtnl_cls *_src) { return -NLE_OPNOTSUPP; } static void cgroup_free_data(struct rtnl_cls *cls) { struct rtnl_cgroup *c = rtnl_cls_data(cls); rtnl_ematch_tree_free(c->cg_ematch); } static int cgroup_msg_parser(struct rtnl_cls *cls) { struct rtnl_cgroup *c = rtnl_cls_data(cls); struct nlattr *tb[TCA_CGROUP_MAX + 1]; int err; err = tca_parse(tb, TCA_CGROUP_MAX, (struct rtnl_tc *) cls, cgroup_policy); if (err < 0) return err; if (tb[TCA_CGROUP_EMATCHES]) { if ((err = rtnl_ematch_parse_attr(tb[TCA_CGROUP_EMATCHES], &c->cg_ematch)) < 0) return err; c->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 *c = rtnl_cls_data(cls); if (c->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 *c = rtnl_cls_data(cls); if (c->cg_mask & CGROUP_ATTR_EMATCH) { nl_dump_line(p, " ematch "); rtnl_ematch_tree_dump(c->cg_ematch, p); } else nl_dump(p, "no options.\n"); } static int cgroup_get_opts(struct rtnl_cls *cls, struct nl_msg *msg) { struct rtnl_cgroup *c = rtnl_cls_data(cls); if (!(cls->ce_mask & TCA_ATTR_HANDLE)) return -NLE_MISSING_ATTR; if (c->cg_mask & CGROUP_ATTR_EMATCH) return rtnl_ematch_fill_attr(msg, TCA_CGROUP_EMATCHES, c->cg_ematch); return 0; } /** * @name Attribute Modifications * @{ */ void rtnl_cgroup_set_ematch(struct rtnl_cls *cls, struct rtnl_ematch_tree *tree) { struct rtnl_cgroup *c = rtnl_cls_data(cls); if (c->cg_ematch) { rtnl_ematch_tree_free(c->cg_ematch); c->cg_mask &= ~CGROUP_ATTR_EMATCH; } c->cg_ematch = tree; if (tree) c->cg_mask |= CGROUP_ATTR_EMATCH; } struct rtnl_ematch_tree *rtnl_cgroup_get_ematch(struct rtnl_cls *cls) { return ((struct rtnl_cgroup *) rtnl_cls_data(cls))->cg_ematch; } /** @} */ static struct rtnl_cls_ops cgroup_ops = { .co_kind = "cgroup", .co_size = sizeof(struct rtnl_cgroup), .co_clone = cgroup_clone, .co_msg_parser = cgroup_msg_parser, .co_free_data = cgroup_free_data, .co_get_opts = cgroup_get_opts, .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); } /** @} */