xref: /aosp_15_r20/external/libnl/lib/route/cls/cgroup.c (revision 4dc78e53d49367fa8e61b07018507c90983a077d)
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3  * Copyright (c) 2009-2013 Thomas Graf <[email protected]>
4  */
5 
6 /**
7  * @ingroup cls
8  * @defgroup cls_cgroup Control Groups Classifier
9  *
10  * @{
11  */
12 
13 #include "nl-default.h"
14 
15 #include <netlink/netlink.h>
16 #include <netlink/attr.h>
17 #include <netlink/utils.h>
18 #include <netlink/route/classifier.h>
19 #include <netlink/route/cls/cgroup.h>
20 #include <netlink/route/cls/ematch.h>
21 
22 #include "tc-api.h"
23 
24 /** @cond SKIP */
25 struct rtnl_cgroup {
26 	struct rtnl_ematch_tree *cg_ematch;
27 	int cg_mask;
28 };
29 
30 #define CGROUP_ATTR_EMATCH      0x001
31 /** @endcond */
32 
33 static struct nla_policy cgroup_policy[TCA_CGROUP_MAX+1] = {
34 	[TCA_CGROUP_EMATCHES]	= { .type = NLA_NESTED },
35 };
36 
cgroup_clone(void * _dst,void * _src)37 static int cgroup_clone(void *_dst, void *_src)
38 {
39 	struct rtnl_cgroup *dst = _dst, *src = _src;
40 
41 	dst->cg_ematch = NULL;
42 
43 	if (src->cg_ematch) {
44 		dst->cg_ematch = rtnl_ematch_tree_clone(src->cg_ematch);
45 		if (!dst->cg_ematch)
46 			return -NLE_NOMEM;
47 	}
48 
49 	return 0;
50 }
51 
cgroup_free_data(struct rtnl_tc * tc,void * data)52 static void cgroup_free_data(struct rtnl_tc *tc, void *data)
53 {
54 	struct rtnl_cgroup *c = data;
55 
56 	if (!c)
57 		return;
58 
59 	rtnl_ematch_tree_free(c->cg_ematch);
60 }
61 
cgroup_msg_parser(struct rtnl_tc * tc,void * data)62 static int cgroup_msg_parser(struct rtnl_tc *tc, void *data)
63 {
64 	struct nlattr *tb[TCA_CGROUP_MAX + 1];
65 	struct rtnl_cgroup *c = data;
66 	int err;
67 
68 	err = tca_parse(tb, TCA_CGROUP_MAX, tc, cgroup_policy);
69 	if (err < 0)
70 		return err;
71 
72 	if (tb[TCA_CGROUP_EMATCHES]) {
73 		if ((err = rtnl_ematch_parse_attr(tb[TCA_CGROUP_EMATCHES],
74 						  &c->cg_ematch)) < 0)
75 			return err;
76 		c->cg_mask |= CGROUP_ATTR_EMATCH;
77 	}
78 
79 #if 0
80 	TODO:
81 	TCA_CGROUP_ACT,
82 	TCA_CGROUP_POLICE,
83 #endif
84 
85 	return 0;
86 }
87 
cgroup_dump_line(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)88 static void cgroup_dump_line(struct rtnl_tc *tc, void *data,
89 			     struct nl_dump_params *p)
90 {
91 	struct rtnl_cgroup *c = data;
92 
93 	if (!c)
94 		return;
95 
96 	if (c->cg_mask & CGROUP_ATTR_EMATCH)
97 		nl_dump(p, " ematch");
98 	else
99 		nl_dump(p, " match-all");
100 }
101 
cgroup_dump_details(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)102 static void cgroup_dump_details(struct rtnl_tc *tc, void *data,
103 				struct nl_dump_params *p)
104 {
105 	struct rtnl_cgroup *c = data;
106 
107 	if (!c)
108 		return;
109 
110 	if (c->cg_mask & CGROUP_ATTR_EMATCH) {
111 		nl_dump_line(p, "    ematch ");
112 
113 		if (c->cg_ematch)
114 			rtnl_ematch_tree_dump(c->cg_ematch, p);
115 		else
116 			nl_dump(p, "<no tree>");
117 	} else
118 		nl_dump(p, "no options");
119 }
120 
cgroup_fill_msg(struct rtnl_tc * tc,void * data,struct nl_msg * msg)121 static int cgroup_fill_msg(struct rtnl_tc *tc, void *data,
122 			   struct nl_msg *msg)
123 {
124 	struct rtnl_cgroup *c = data;
125 
126 	if (!c)
127 		BUG();
128 
129 	if (!(tc->ce_mask & TCA_ATTR_HANDLE))
130 		return -NLE_MISSING_ATTR;
131 
132 	if (c->cg_mask & CGROUP_ATTR_EMATCH)
133 		return rtnl_ematch_fill_attr(msg, TCA_CGROUP_EMATCHES,
134 					     c->cg_ematch);
135 
136 	return 0;
137 }
138 
139 
140 /**
141  * @name Attribute Modifications
142  * @{
143  */
144 
rtnl_cgroup_set_ematch(struct rtnl_cls * cls,struct rtnl_ematch_tree * tree)145 void rtnl_cgroup_set_ematch(struct rtnl_cls *cls, struct rtnl_ematch_tree *tree)
146 {
147 	struct rtnl_cgroup *c;
148 
149 	if (!(c = rtnl_tc_data(TC_CAST(cls))))
150 		BUG();
151 
152 	if (c->cg_ematch) {
153 		rtnl_ematch_tree_free(c->cg_ematch);
154 		c->cg_mask &= ~CGROUP_ATTR_EMATCH;
155 	}
156 
157 	c->cg_ematch = tree;
158 
159 	if (tree)
160 		c->cg_mask |= CGROUP_ATTR_EMATCH;
161 }
162 
rtnl_cgroup_get_ematch(struct rtnl_cls * cls)163 struct rtnl_ematch_tree *rtnl_cgroup_get_ematch(struct rtnl_cls *cls)
164 {
165 	struct rtnl_cgroup *c;
166 
167 	if (!(c = rtnl_tc_data(TC_CAST(cls))))
168 		BUG();
169 
170 	return c->cg_ematch;
171 }
172 
173 /** @} */
174 
175 static struct rtnl_tc_ops cgroup_ops = {
176 	.to_kind		= "cgroup",
177 	.to_type		= RTNL_TC_TYPE_CLS,
178 	.to_size		= sizeof(struct rtnl_cgroup),
179 	.to_clone		= cgroup_clone,
180 	.to_msg_parser		= cgroup_msg_parser,
181 	.to_free_data		= cgroup_free_data,
182 	.to_msg_fill		= cgroup_fill_msg,
183 	.to_dump = {
184 	    [NL_DUMP_LINE]	= cgroup_dump_line,
185 	    [NL_DUMP_DETAILS]	= cgroup_dump_details,
186 	},
187 };
188 
cgroup_init(void)189 static void _nl_init cgroup_init(void)
190 {
191 	rtnl_tc_register(&cgroup_ops);
192 }
193 
cgroup_exit(void)194 static void _nl_exit cgroup_exit(void)
195 {
196 	rtnl_tc_unregister(&cgroup_ops);
197 }
198 
199 /** @} */
200