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
32static 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
46static 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);
67errout:
68	return err;
69}
70
71static 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
88static 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
103static 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
122struct rtnl_cls *rtnl_cls_alloc(void)
123{
124	return (struct rtnl_cls *) nl_object_alloc(&cls_obj_ops);
125}
126
127void 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
140void rtnl_cls_set_ifindex(struct rtnl_cls *f, int ifindex)
141{
142	tca_set_ifindex((struct rtnl_tca *) f, ifindex);
143}
144
145int rtnl_cls_get_ifindex(struct rtnl_cls *cls)
146{
147	return cls->c_ifindex;
148}
149
150void rtnl_cls_set_handle(struct rtnl_cls *f, uint32_t handle)
151{
152	tca_set_handle((struct rtnl_tca *) f, handle);
153}
154
155void rtnl_cls_set_parent(struct rtnl_cls *f, uint32_t parent)
156{
157	tca_set_parent((struct rtnl_tca *) f, parent);
158}
159
160uint32_t rtnl_cls_get_parent(struct rtnl_cls *cls)
161{
162	return cls->c_parent;
163}
164
165int 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
178struct rtnl_cls_ops *rtnl_cls_get_ops(struct rtnl_cls *cls)
179{
180	return cls->c_ops;
181}
182
183void 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
189uint16_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
197void 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
203uint16_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
211void *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
239struct 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