1 /*
2  * lib/route/class.c            Queueing Classes
3  *
4  *	This library is free software; you can redistribute it and/or
5  *	modify it under the terms of the GNU Lesser General Public
6  *	License as published by the Free Software Foundation version 2.1
7  *	of the License.
8  *
9  * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
10  */
11 
12 /**
13  * @ingroup class
14  * @defgroup class_obj Class Object
15  * @{
16  */
17 
18 #include <netlink-local.h>
19 #include <netlink-tc.h>
20 #include <netlink/netlink.h>
21 #include <netlink/route/tc.h>
22 #include <netlink/route/class.h>
23 #include <netlink/route/class-modules.h>
24 #include <netlink/route/qdisc.h>
25 #include <netlink/route/classifier.h>
26 #include <netlink/utils.h>
27 
class_free_data(struct nl_object * obj)28 static void class_free_data(struct nl_object *obj)
29 {
30 	struct rtnl_class *class = (struct rtnl_class *) obj;
31 	struct rtnl_class_ops *cops;
32 
33 	tca_free_data((struct rtnl_tca *) class);
34 
35 	cops = rtnl_class_lookup_ops(class);
36 	if (cops && cops->co_free_data)
37 		cops->co_free_data(class);
38 }
39 
class_clone(struct nl_object * _dst,struct nl_object * _src)40 static int class_clone(struct nl_object *_dst, struct nl_object *_src)
41 {
42 	struct rtnl_class *dst = nl_object_priv(_dst);
43 	struct rtnl_class *src = nl_object_priv(_src);
44 	struct rtnl_class_ops *cops;
45 	int err;
46 
47 	err = tca_clone((struct rtnl_tca *) dst, (struct rtnl_tca *) src);
48 	if (err < 0)
49 		goto errout;
50 
51 	cops = rtnl_class_lookup_ops(src);
52 	if (cops && cops->co_clone)
53 		err = cops->co_clone(dst, src);
54 errout:
55 	return err;
56 }
57 
class_dump_line(struct nl_object * obj,struct nl_dump_params * p)58 static void class_dump_line(struct nl_object *obj, struct nl_dump_params *p)
59 {
60 	struct rtnl_class *class = (struct rtnl_class *) obj;
61 	struct rtnl_class_ops *cops;
62 
63 	tca_dump_line((struct rtnl_tca *) class, "class", p);
64 
65 	cops = rtnl_class_lookup_ops(class);
66 	if (cops && cops->co_dump[NL_DUMP_LINE])
67 		cops->co_dump[NL_DUMP_LINE](class, p);
68 	nl_dump(p, "\n");
69 }
70 
class_dump_details(struct nl_object * obj,struct nl_dump_params * p)71 static void class_dump_details(struct nl_object *obj, struct nl_dump_params *p)
72 {
73 	struct rtnl_class *class = (struct rtnl_class *) obj;
74 	struct rtnl_class_ops *cops;
75 
76 	class_dump_line(obj, p);
77 	tca_dump_details((struct rtnl_tca *) class, p);
78 
79 	if (class->c_info) {
80 		char buf[32];
81 		nl_dump(p, "child-qdisc %s ",
82 			rtnl_tc_handle2str(class->c_info, buf, sizeof(buf)));
83 	}
84 
85 	cops = rtnl_class_lookup_ops(class);
86 	if (cops && cops->co_dump[NL_DUMP_DETAILS])
87 		cops->co_dump[NL_DUMP_DETAILS](class, p);
88 	else if (!class->c_info)
89 		nl_dump(p, "noop (no leaf qdisc)");
90 
91 	nl_dump(p, "\n");
92 }
93 
class_dump_stats(struct nl_object * obj,struct nl_dump_params * p)94 static void class_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
95 {
96 	struct rtnl_class *class = (struct rtnl_class *) obj;
97 	struct rtnl_class_ops *cops;
98 
99 	class_dump_details(obj, p);
100 	tca_dump_stats((struct rtnl_tca *) class, p);
101 	nl_dump(p, "\n");
102 
103 	cops = rtnl_class_lookup_ops(class);
104 	if (cops && cops->co_dump[NL_DUMP_STATS])
105 		cops->co_dump[NL_DUMP_STATS](class, p);
106 }
107 
108 /**
109  * @name Allocation/Freeing
110  * @{
111  */
112 
rtnl_class_alloc(void)113 struct rtnl_class *rtnl_class_alloc(void)
114 {
115 	return (struct rtnl_class *) nl_object_alloc(&class_obj_ops);
116 }
117 
rtnl_class_put(struct rtnl_class * class)118 void rtnl_class_put(struct rtnl_class *class)
119 {
120 	nl_object_put((struct nl_object *) class);
121 }
122 
123 /** @} */
124 
125 /**
126  * @name Leaf Qdisc
127  * @{
128  */
129 
130 /**
131  * Lookup the leaf qdisc of a class
132  * @arg class		the parent class
133  * @arg cache		a qdisc cache including at laest all qdiscs of the
134  *                      interface the specified class is attached to
135  * @return The qdisc from the cache or NULL if the class has no leaf qdisc
136  */
rtnl_class_leaf_qdisc(struct rtnl_class * class,struct nl_cache * cache)137 struct rtnl_qdisc *rtnl_class_leaf_qdisc(struct rtnl_class *class,
138 					 struct nl_cache *cache)
139 {
140 	struct rtnl_qdisc *leaf;
141 
142 	if (!class->c_info)
143 		return NULL;
144 
145 	leaf = rtnl_qdisc_get_by_parent(cache, class->c_ifindex,
146 					class->c_handle);
147 	if (!leaf || leaf->q_handle != class->c_info)
148 		return NULL;
149 
150 	return leaf;
151 }
152 
153 /** @} */
154 
155 
156 /**
157  * @name Iterators
158  * @{
159  */
160 
161 /**
162  * Call a callback for each child of a class
163  * @arg class		the parent class
164  * @arg cache		a class cache including all classes of the interface
165  *                      the specified class is attached to
166  * @arg cb              callback function
167  * @arg arg             argument to be passed to callback function
168  */
rtnl_class_foreach_child(struct rtnl_class * class,struct nl_cache * cache,void (* cb)(struct nl_object *,void *),void * arg)169 void rtnl_class_foreach_child(struct rtnl_class *class, struct nl_cache *cache,
170 			      void (*cb)(struct nl_object *, void *), void *arg)
171 {
172 	struct rtnl_class *filter;
173 
174 	filter = rtnl_class_alloc();
175 	if (!filter)
176 		return;
177 
178 	rtnl_class_set_parent(filter, class->c_handle);
179 	rtnl_class_set_ifindex(filter, class->c_ifindex);
180 	rtnl_class_set_kind(filter, class->c_kind);
181 
182 	nl_cache_foreach_filter(cache, (struct nl_object *) filter, cb, arg);
183 	rtnl_class_put(filter);
184 }
185 
186 /**
187  * Call a callback for each classifier attached to the class
188  * @arg class		the parent class
189  * @arg cache		a filter cache including at least all the filters
190  *                      attached to the specified class
191  * @arg cb              callback function
192  * @arg arg             argument to be passed to callback function
193  */
rtnl_class_foreach_cls(struct rtnl_class * class,struct nl_cache * cache,void (* cb)(struct nl_object *,void *),void * arg)194 void rtnl_class_foreach_cls(struct rtnl_class *class, struct nl_cache *cache,
195 			    void (*cb)(struct nl_object *, void *), void *arg)
196 {
197 	struct rtnl_cls *filter;
198 
199 	filter = rtnl_cls_alloc();
200 	if (!filter)
201 		return;
202 
203 	rtnl_cls_set_ifindex(filter, class->c_ifindex);
204 	rtnl_cls_set_parent(filter, class->c_parent);
205 
206 	nl_cache_foreach_filter(cache, (struct nl_object *) filter, cb, arg);
207 	rtnl_cls_put(filter);
208 }
209 
210 /** @} */
211 
212 
213 /**
214  * @name Attributes
215  * @{
216  */
217 
rtnl_class_set_ifindex(struct rtnl_class * class,int ifindex)218 void rtnl_class_set_ifindex(struct rtnl_class *class, int ifindex)
219 {
220 	tca_set_ifindex((struct rtnl_tca *) class, ifindex);
221 }
222 
rtnl_class_get_ifindex(struct rtnl_class * class)223 int rtnl_class_get_ifindex(struct rtnl_class *class)
224 {
225 	return tca_get_ifindex((struct rtnl_tca *) class);
226 }
227 
rtnl_class_set_handle(struct rtnl_class * class,uint32_t handle)228 void rtnl_class_set_handle(struct rtnl_class *class, uint32_t handle)
229 {
230 	tca_set_handle((struct rtnl_tca *) class, handle);
231 }
232 
rtnl_class_get_handle(struct rtnl_class * class)233 uint32_t rtnl_class_get_handle(struct rtnl_class *class)
234 {
235 	return tca_get_handle((struct rtnl_tca *) class);
236 }
237 
rtnl_class_set_parent(struct rtnl_class * class,uint32_t parent)238 void rtnl_class_set_parent(struct rtnl_class *class, uint32_t parent)
239 {
240 	tca_set_parent((struct rtnl_tca *) class, parent);
241 }
242 
rtnl_class_get_parent(struct rtnl_class * class)243 uint32_t rtnl_class_get_parent(struct rtnl_class *class)
244 {
245 	return tca_get_parent((struct rtnl_tca *) class);
246 }
247 
rtnl_class_set_kind(struct rtnl_class * class,const char * name)248 void rtnl_class_set_kind(struct rtnl_class *class, const char *name)
249 {
250 	tca_set_kind((struct rtnl_tca *) class, name);
251 	class->c_ops = __rtnl_class_lookup_ops(name);
252 }
253 
rtnl_class_get_kind(struct rtnl_class * class)254 char *rtnl_class_get_kind(struct rtnl_class *class)
255 {
256 	return tca_get_kind((struct rtnl_tca *) class);
257 }
258 
rtnl_class_get_stat(struct rtnl_class * class,enum rtnl_tc_stats_id id)259 uint64_t rtnl_class_get_stat(struct rtnl_class *class,
260 			     enum rtnl_tc_stats_id id)
261 {
262 	return tca_get_stat((struct rtnl_tca *) class, id);
263 }
264 
265 /** @} */
266 
267 struct nl_object_ops class_obj_ops = {
268 	.oo_name		= "route/class",
269 	.oo_size		= sizeof(struct rtnl_class),
270 	.oo_free_data         	= class_free_data,
271 	.oo_clone		= class_clone,
272 	.oo_dump = {
273 	    [NL_DUMP_LINE]	= class_dump_line,
274 	    [NL_DUMP_DETAILS]	= class_dump_details,
275 	    [NL_DUMP_STATS]	= class_dump_stats,
276 	},
277 	.oo_compare		= tca_compare,
278 	.oo_id_attrs		= (TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE),
279 };
280 
281 /** @} */
282