1 /*
2  * lib/route/cls_api.c       Classifier Object
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 cls
14  * @defgroup cls_obj Classifier Object
15  * @{
16  */
17 
18 #include <netlink-local.h>
19 #include <netlink-tc.h>
20 #include <netlink/netlink.h>
21 #include <netlink/utils.h>
22 #include <netlink/route/tc.h>
23 #include <netlink/route/classifier.h>
24 #include <netlink/route/classifier-modules.h>
25 #include <netlink/route/link.h>
26 
27 /** @cond SKIP */
28 #define CLS_ATTR_PRIO		(TCA_ATTR_MAX << 1)
29 #define CLS_ATTR_PROTOCOL	(TCA_ATTR_MAX << 2)
30 /** @endcond */
31 
cls_free_data(struct nl_object * obj)32 static void cls_free_data(struct nl_object *obj)
33 {
34 	struct rtnl_cls *cls = (struct rtnl_cls *) obj;
35 	struct rtnl_cls_ops *cops;
36 
37 	tca_free_data((struct rtnl_tca *) cls);
38 
39 	cops = rtnl_cls_lookup_ops(cls);
40 	if (cops && cops->co_free_data)
41 		cops->co_free_data(cls);
42 
43 	nl_data_free(cls->c_subdata);
44 }
45 
cls_clone(struct nl_object * _dst,struct nl_object * _src)46 static int cls_clone(struct nl_object *_dst, struct nl_object *_src)
47 {
48 	struct rtnl_cls *dst = nl_object_priv(_dst);
49 	struct rtnl_cls *src = nl_object_priv(_src);
50 	struct rtnl_cls_ops *cops;
51 	int err;
52 
53 	err = tca_clone((struct rtnl_tca *) dst, (struct rtnl_tca *) src);
54 	if (err < 0)
55 		goto errout;
56 
57 	if (src->c_subdata) {
58 		if (!(dst->c_subdata = nl_data_clone(src->c_subdata))) {
59 			err = -NLE_NOMEM;
60 			goto errout;
61 		}
62 	}
63 
64 	cops = rtnl_cls_lookup_ops(src);
65 	if (cops && cops->co_clone)
66 		err = cops->co_clone(dst, src);
67 errout:
68 	return err;
69 }
70 
cls_dump_line(struct nl_object * obj,struct nl_dump_params * p)71 static void cls_dump_line(struct nl_object *obj, struct nl_dump_params *p)
72 {
73 	char buf[32];
74 	struct rtnl_cls *cls = (struct rtnl_cls *) obj;
75 	struct rtnl_cls_ops *cops;
76 
77 	tca_dump_line((struct rtnl_tca *) cls, "cls", p);
78 
79 	nl_dump(p, " prio %u protocol %s", cls->c_prio,
80 		nl_ether_proto2str(cls->c_protocol, buf, sizeof(buf)));
81 
82 	cops = rtnl_cls_lookup_ops(cls);
83 	if (cops && cops->co_dump[NL_DUMP_LINE])
84 		cops->co_dump[NL_DUMP_LINE](cls, p);
85 	nl_dump(p, "\n");
86 }
87 
cls_dump_details(struct nl_object * obj,struct nl_dump_params * p)88 static void cls_dump_details(struct nl_object *obj, struct nl_dump_params *p)
89 {
90 	struct rtnl_cls *cls = (struct rtnl_cls *) obj;
91 	struct rtnl_cls_ops *cops;
92 
93 	cls_dump_line(obj, p);
94 	tca_dump_details((struct rtnl_tca *) cls, p);
95 
96 	cops = rtnl_cls_lookup_ops(cls);
97 	if (cops && cops->co_dump[NL_DUMP_DETAILS])
98 		cops->co_dump[NL_DUMP_DETAILS](cls, p);
99 	else
100 		nl_dump(p, "no options\n");
101 }
102 
cls_dump_stats(struct nl_object * obj,struct nl_dump_params * p)103 static void cls_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
104 {
105 	struct rtnl_cls *cls = (struct rtnl_cls *) obj;
106 	struct rtnl_cls_ops *cops;
107 
108 	cls_dump_details(obj, p);
109 	tca_dump_stats((struct rtnl_tca *) cls, p);
110 	nl_dump(p, "\n");
111 
112 	cops = rtnl_cls_lookup_ops(cls);
113 	if (cops && cops->co_dump[NL_DUMP_STATS])
114 		cops->co_dump[NL_DUMP_STATS](cls, p);
115 }
116 
117 /**
118  * @name Allocation/Freeing
119  * @{
120  */
121 
rtnl_cls_alloc(void)122 struct rtnl_cls *rtnl_cls_alloc(void)
123 {
124 	return (struct rtnl_cls *) nl_object_alloc(&cls_obj_ops);
125 }
126 
rtnl_cls_put(struct rtnl_cls * cls)127 void rtnl_cls_put(struct rtnl_cls *cls)
128 {
129 	nl_object_put((struct nl_object *) cls);
130 }
131 
132 /** @} */
133 
134 
135 /**
136  * @name Attributes
137  * @{
138  */
139 
rtnl_cls_set_ifindex(struct rtnl_cls * f,int ifindex)140 void rtnl_cls_set_ifindex(struct rtnl_cls *f, int ifindex)
141 {
142 	tca_set_ifindex((struct rtnl_tca *) f, ifindex);
143 }
144 
rtnl_cls_get_ifindex(struct rtnl_cls * cls)145 int rtnl_cls_get_ifindex(struct rtnl_cls *cls)
146 {
147 	return cls->c_ifindex;
148 }
149 
rtnl_cls_set_handle(struct rtnl_cls * f,uint32_t handle)150 void rtnl_cls_set_handle(struct rtnl_cls *f, uint32_t handle)
151 {
152 	tca_set_handle((struct rtnl_tca *) f, handle);
153 }
154 
rtnl_cls_set_parent(struct rtnl_cls * f,uint32_t parent)155 void rtnl_cls_set_parent(struct rtnl_cls *f, uint32_t parent)
156 {
157 	tca_set_parent((struct rtnl_tca *) f, parent);
158 }
159 
rtnl_cls_get_parent(struct rtnl_cls * cls)160 uint32_t rtnl_cls_get_parent(struct rtnl_cls *cls)
161 {
162 	return cls->c_parent;
163 }
164 
rtnl_cls_set_kind(struct rtnl_cls * cls,const char * kind)165 int rtnl_cls_set_kind(struct rtnl_cls *cls, const char *kind)
166 {
167 	if (cls->ce_mask & TCA_ATTR_KIND)
168 		return -NLE_EXIST;
169 
170 	tca_set_kind((struct rtnl_tca *) cls, kind);
171 
172 	/* Force allocation of data */
173 	rtnl_cls_data(cls);
174 
175 	return 0;
176 }
177 
rtnl_cls_get_ops(struct rtnl_cls * cls)178 struct rtnl_cls_ops *rtnl_cls_get_ops(struct rtnl_cls *cls)
179 {
180 	return cls->c_ops;
181 }
182 
rtnl_cls_set_prio(struct rtnl_cls * cls,uint16_t prio)183 void rtnl_cls_set_prio(struct rtnl_cls *cls, uint16_t prio)
184 {
185 	cls->c_prio = prio;
186 	cls->ce_mask |= CLS_ATTR_PRIO;
187 }
188 
rtnl_cls_get_prio(struct rtnl_cls * cls)189 uint16_t rtnl_cls_get_prio(struct rtnl_cls *cls)
190 {
191 	if (cls->ce_mask & CLS_ATTR_PRIO)
192 		return cls->c_prio;
193 	else
194 		return 0;
195 }
196 
rtnl_cls_set_protocol(struct rtnl_cls * cls,uint16_t protocol)197 void rtnl_cls_set_protocol(struct rtnl_cls *cls, uint16_t protocol)
198 {
199 	cls->c_protocol = protocol;
200 	cls->ce_mask |= CLS_ATTR_PROTOCOL;
201 }
202 
rtnl_cls_get_protocol(struct rtnl_cls * cls)203 uint16_t rtnl_cls_get_protocol(struct rtnl_cls *cls)
204 {
205 	if (cls->ce_mask & CLS_ATTR_PROTOCOL)
206 		return cls->c_protocol;
207 	else
208 		return ETH_P_ALL;
209 }
210 
rtnl_cls_data(struct rtnl_cls * cls)211 void *rtnl_cls_data(struct rtnl_cls *cls)
212 {
213 	if (!cls->c_subdata) {
214 		struct rtnl_cls_ops *ops = cls->c_ops;
215 
216 		if (!ops) {
217 			if (!cls->c_kind[0])
218 				BUG();
219 
220 			ops = __rtnl_cls_lookup_ops(cls->c_kind);
221 			if (ops == NULL)
222 				return NULL;
223 
224 			cls->c_ops = ops;
225 		}
226 
227 		if (!ops->co_size)
228 			BUG();
229 
230 		if (!(cls->c_subdata = nl_data_alloc(NULL, ops->co_size)))
231 			return NULL;
232 	}
233 
234 	return nl_data_get(cls->c_subdata);
235 }
236 
237 /** @} */
238 
239 struct nl_object_ops cls_obj_ops = {
240 	.oo_name		= "route/cls",
241 	.oo_size		= sizeof(struct rtnl_cls),
242 	.oo_free_data		= cls_free_data,
243 	.oo_clone		= cls_clone,
244 	.oo_dump = {
245 	    [NL_DUMP_LINE]	= cls_dump_line,
246 	    [NL_DUMP_DETAILS]	= cls_dump_details,
247 	    [NL_DUMP_STATS]	= cls_dump_stats,
248 	},
249 	.oo_compare		= tca_compare,
250 	.oo_id_attrs		= (TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE),
251 };
252 
253 /** @} */
254