1*4dc78e53SAndroid Build Coastguard Worker /* SPDX-License-Identifier: LGPL-2.1-only */
2*4dc78e53SAndroid Build Coastguard Worker /*
3*4dc78e53SAndroid Build Coastguard Worker * Copyright (c) 2010-2013 Thomas Graf <[email protected]>
4*4dc78e53SAndroid Build Coastguard Worker */
5*4dc78e53SAndroid Build Coastguard Worker
6*4dc78e53SAndroid Build Coastguard Worker /**
7*4dc78e53SAndroid Build Coastguard Worker * @ingroup tc
8*4dc78e53SAndroid Build Coastguard Worker * @defgroup classid ClassID Management
9*4dc78e53SAndroid Build Coastguard Worker * @{
10*4dc78e53SAndroid Build Coastguard Worker */
11*4dc78e53SAndroid Build Coastguard Worker
12*4dc78e53SAndroid Build Coastguard Worker #include "nl-default.h"
13*4dc78e53SAndroid Build Coastguard Worker
14*4dc78e53SAndroid Build Coastguard Worker #include <sys/stat.h>
15*4dc78e53SAndroid Build Coastguard Worker #include <search.h>
16*4dc78e53SAndroid Build Coastguard Worker
17*4dc78e53SAndroid Build Coastguard Worker #include <netlink/netlink.h>
18*4dc78e53SAndroid Build Coastguard Worker #include <netlink/utils.h>
19*4dc78e53SAndroid Build Coastguard Worker #include <netlink/route/tc.h>
20*4dc78e53SAndroid Build Coastguard Worker
21*4dc78e53SAndroid Build Coastguard Worker #include "nl-route.h"
22*4dc78e53SAndroid Build Coastguard Worker #include "nl-aux-core/nl-core.h"
23*4dc78e53SAndroid Build Coastguard Worker
24*4dc78e53SAndroid Build Coastguard Worker struct classid_map
25*4dc78e53SAndroid Build Coastguard Worker {
26*4dc78e53SAndroid Build Coastguard Worker uint32_t classid;
27*4dc78e53SAndroid Build Coastguard Worker char * name;
28*4dc78e53SAndroid Build Coastguard Worker struct nl_list_head name_list;
29*4dc78e53SAndroid Build Coastguard Worker };
30*4dc78e53SAndroid Build Coastguard Worker
31*4dc78e53SAndroid Build Coastguard Worker #define CLASSID_NAME_HT_SIZ 256
32*4dc78e53SAndroid Build Coastguard Worker
33*4dc78e53SAndroid Build Coastguard Worker static struct nl_list_head tbl_name[CLASSID_NAME_HT_SIZ];
34*4dc78e53SAndroid Build Coastguard Worker
35*4dc78e53SAndroid Build Coastguard Worker static void *id_root = NULL;
36*4dc78e53SAndroid Build Coastguard Worker
compare_id(const void * pa,const void * pb)37*4dc78e53SAndroid Build Coastguard Worker static int compare_id(const void *pa, const void *pb)
38*4dc78e53SAndroid Build Coastguard Worker {
39*4dc78e53SAndroid Build Coastguard Worker const struct classid_map *ma = pa;
40*4dc78e53SAndroid Build Coastguard Worker const struct classid_map *mb = pb;
41*4dc78e53SAndroid Build Coastguard Worker
42*4dc78e53SAndroid Build Coastguard Worker if (ma->classid < mb->classid)
43*4dc78e53SAndroid Build Coastguard Worker return -1;
44*4dc78e53SAndroid Build Coastguard Worker
45*4dc78e53SAndroid Build Coastguard Worker if (ma->classid > mb->classid)
46*4dc78e53SAndroid Build Coastguard Worker return 1;
47*4dc78e53SAndroid Build Coastguard Worker
48*4dc78e53SAndroid Build Coastguard Worker return 0;
49*4dc78e53SAndroid Build Coastguard Worker }
50*4dc78e53SAndroid Build Coastguard Worker
51*4dc78e53SAndroid Build Coastguard Worker /* djb2 */
classid_tbl_hash(const char * str)52*4dc78e53SAndroid Build Coastguard Worker static unsigned int classid_tbl_hash(const char *str)
53*4dc78e53SAndroid Build Coastguard Worker {
54*4dc78e53SAndroid Build Coastguard Worker unsigned long hash = 5381;
55*4dc78e53SAndroid Build Coastguard Worker int c;
56*4dc78e53SAndroid Build Coastguard Worker
57*4dc78e53SAndroid Build Coastguard Worker while ((c = *str++))
58*4dc78e53SAndroid Build Coastguard Worker hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
59*4dc78e53SAndroid Build Coastguard Worker
60*4dc78e53SAndroid Build Coastguard Worker return hash % CLASSID_NAME_HT_SIZ;
61*4dc78e53SAndroid Build Coastguard Worker }
62*4dc78e53SAndroid Build Coastguard Worker
classid_lookup(const char * name,uint32_t * result)63*4dc78e53SAndroid Build Coastguard Worker static int classid_lookup(const char *name, uint32_t *result)
64*4dc78e53SAndroid Build Coastguard Worker {
65*4dc78e53SAndroid Build Coastguard Worker struct classid_map *map;
66*4dc78e53SAndroid Build Coastguard Worker int n = classid_tbl_hash(name);
67*4dc78e53SAndroid Build Coastguard Worker
68*4dc78e53SAndroid Build Coastguard Worker nl_list_for_each_entry(map, &tbl_name[n], name_list) {
69*4dc78e53SAndroid Build Coastguard Worker if (!strcasecmp(map->name, name)) {
70*4dc78e53SAndroid Build Coastguard Worker *result = map->classid;
71*4dc78e53SAndroid Build Coastguard Worker return 0;
72*4dc78e53SAndroid Build Coastguard Worker }
73*4dc78e53SAndroid Build Coastguard Worker }
74*4dc78e53SAndroid Build Coastguard Worker
75*4dc78e53SAndroid Build Coastguard Worker return -NLE_OBJ_NOTFOUND;
76*4dc78e53SAndroid Build Coastguard Worker }
77*4dc78e53SAndroid Build Coastguard Worker
name_lookup(const uint32_t classid)78*4dc78e53SAndroid Build Coastguard Worker static char *name_lookup(const uint32_t classid)
79*4dc78e53SAndroid Build Coastguard Worker {
80*4dc78e53SAndroid Build Coastguard Worker void *res;
81*4dc78e53SAndroid Build Coastguard Worker struct classid_map cm = {
82*4dc78e53SAndroid Build Coastguard Worker .classid = classid,
83*4dc78e53SAndroid Build Coastguard Worker .name = "search entry",
84*4dc78e53SAndroid Build Coastguard Worker };
85*4dc78e53SAndroid Build Coastguard Worker
86*4dc78e53SAndroid Build Coastguard Worker if ((res = tfind(&cm, &id_root, &compare_id)))
87*4dc78e53SAndroid Build Coastguard Worker return (*(struct classid_map **) res)->name;
88*4dc78e53SAndroid Build Coastguard Worker
89*4dc78e53SAndroid Build Coastguard Worker return NULL;
90*4dc78e53SAndroid Build Coastguard Worker }
91*4dc78e53SAndroid Build Coastguard Worker
92*4dc78e53SAndroid Build Coastguard Worker /**
93*4dc78e53SAndroid Build Coastguard Worker * @name Traffic Control Handle Translations
94*4dc78e53SAndroid Build Coastguard Worker * @{
95*4dc78e53SAndroid Build Coastguard Worker */
96*4dc78e53SAndroid Build Coastguard Worker
97*4dc78e53SAndroid Build Coastguard Worker /**
98*4dc78e53SAndroid Build Coastguard Worker * Convert a traffic control handle to a character string (Reentrant).
99*4dc78e53SAndroid Build Coastguard Worker * @arg handle traffic control handle
100*4dc78e53SAndroid Build Coastguard Worker * @arg buf destination buffer
101*4dc78e53SAndroid Build Coastguard Worker * @arg len buffer length
102*4dc78e53SAndroid Build Coastguard Worker *
103*4dc78e53SAndroid Build Coastguard Worker * Converts a tarffic control handle to a character string in the
104*4dc78e53SAndroid Build Coastguard Worker * form of \c MAJ:MIN and stores it in the specified destination buffer.
105*4dc78e53SAndroid Build Coastguard Worker *
106*4dc78e53SAndroid Build Coastguard Worker * @return The destination buffer or the type encoded in hexidecimal
107*4dc78e53SAndroid Build Coastguard Worker * form if no match was found.
108*4dc78e53SAndroid Build Coastguard Worker */
rtnl_tc_handle2str(uint32_t handle,char * buf,size_t len)109*4dc78e53SAndroid Build Coastguard Worker char *rtnl_tc_handle2str(uint32_t handle, char *buf, size_t len)
110*4dc78e53SAndroid Build Coastguard Worker {
111*4dc78e53SAndroid Build Coastguard Worker if (TC_H_ROOT == handle)
112*4dc78e53SAndroid Build Coastguard Worker snprintf(buf, len, "root");
113*4dc78e53SAndroid Build Coastguard Worker else if (TC_H_UNSPEC == handle)
114*4dc78e53SAndroid Build Coastguard Worker snprintf(buf, len, "none");
115*4dc78e53SAndroid Build Coastguard Worker else if (TC_H_INGRESS == handle)
116*4dc78e53SAndroid Build Coastguard Worker snprintf(buf, len, "ingress");
117*4dc78e53SAndroid Build Coastguard Worker else {
118*4dc78e53SAndroid Build Coastguard Worker char *name;
119*4dc78e53SAndroid Build Coastguard Worker
120*4dc78e53SAndroid Build Coastguard Worker if ((name = name_lookup(handle)))
121*4dc78e53SAndroid Build Coastguard Worker snprintf(buf, len, "%s", name);
122*4dc78e53SAndroid Build Coastguard Worker else if (0 == TC_H_MAJ(handle))
123*4dc78e53SAndroid Build Coastguard Worker snprintf(buf, len, ":%x", TC_H_MIN(handle));
124*4dc78e53SAndroid Build Coastguard Worker else if (0 == TC_H_MIN(handle))
125*4dc78e53SAndroid Build Coastguard Worker snprintf(buf, len, "%x:", TC_H_MAJ(handle) >> 16);
126*4dc78e53SAndroid Build Coastguard Worker else
127*4dc78e53SAndroid Build Coastguard Worker snprintf(buf, len, "%x:%x",
128*4dc78e53SAndroid Build Coastguard Worker TC_H_MAJ(handle) >> 16, TC_H_MIN(handle));
129*4dc78e53SAndroid Build Coastguard Worker }
130*4dc78e53SAndroid Build Coastguard Worker
131*4dc78e53SAndroid Build Coastguard Worker return buf;
132*4dc78e53SAndroid Build Coastguard Worker }
133*4dc78e53SAndroid Build Coastguard Worker
134*4dc78e53SAndroid Build Coastguard Worker /**
135*4dc78e53SAndroid Build Coastguard Worker * Convert a charactering strint to a traffic control handle
136*4dc78e53SAndroid Build Coastguard Worker * @arg str traffic control handle as character string
137*4dc78e53SAndroid Build Coastguard Worker * @arg res destination buffer
138*4dc78e53SAndroid Build Coastguard Worker *
139*4dc78e53SAndroid Build Coastguard Worker * Converts the provided character string specifying a traffic
140*4dc78e53SAndroid Build Coastguard Worker * control handle to the corresponding numeric value.
141*4dc78e53SAndroid Build Coastguard Worker *
142*4dc78e53SAndroid Build Coastguard Worker * The handle must be provided in one of the following formats:
143*4dc78e53SAndroid Build Coastguard Worker * - NAME
144*4dc78e53SAndroid Build Coastguard Worker * - root
145*4dc78e53SAndroid Build Coastguard Worker * - none
146*4dc78e53SAndroid Build Coastguard Worker * - MAJ:
147*4dc78e53SAndroid Build Coastguard Worker * - :MIN
148*4dc78e53SAndroid Build Coastguard Worker * - NAME:MIN
149*4dc78e53SAndroid Build Coastguard Worker * - MAJ:MIN
150*4dc78e53SAndroid Build Coastguard Worker * - MAJMIN
151*4dc78e53SAndroid Build Coastguard Worker *
152*4dc78e53SAndroid Build Coastguard Worker * @return 0 on success or a negative error code
153*4dc78e53SAndroid Build Coastguard Worker */
rtnl_tc_str2handle(const char * str,uint32_t * res)154*4dc78e53SAndroid Build Coastguard Worker int rtnl_tc_str2handle(const char *str, uint32_t *res)
155*4dc78e53SAndroid Build Coastguard Worker {
156*4dc78e53SAndroid Build Coastguard Worker char *colon, *end;
157*4dc78e53SAndroid Build Coastguard Worker uint32_t h;
158*4dc78e53SAndroid Build Coastguard Worker int err;
159*4dc78e53SAndroid Build Coastguard Worker
160*4dc78e53SAndroid Build Coastguard Worker if (!strcasecmp(str, "root")) {
161*4dc78e53SAndroid Build Coastguard Worker *res = TC_H_ROOT;
162*4dc78e53SAndroid Build Coastguard Worker return 0;
163*4dc78e53SAndroid Build Coastguard Worker }
164*4dc78e53SAndroid Build Coastguard Worker
165*4dc78e53SAndroid Build Coastguard Worker if (!strcasecmp(str, "none")) {
166*4dc78e53SAndroid Build Coastguard Worker *res = TC_H_UNSPEC;
167*4dc78e53SAndroid Build Coastguard Worker return 0;
168*4dc78e53SAndroid Build Coastguard Worker }
169*4dc78e53SAndroid Build Coastguard Worker
170*4dc78e53SAndroid Build Coastguard Worker if (!strcasecmp(str, "ingress")) {
171*4dc78e53SAndroid Build Coastguard Worker *res = TC_H_INGRESS;
172*4dc78e53SAndroid Build Coastguard Worker return 0;
173*4dc78e53SAndroid Build Coastguard Worker }
174*4dc78e53SAndroid Build Coastguard Worker
175*4dc78e53SAndroid Build Coastguard Worker h = strtoul(str, &colon, 16);
176*4dc78e53SAndroid Build Coastguard Worker
177*4dc78e53SAndroid Build Coastguard Worker /* MAJ is not a number */
178*4dc78e53SAndroid Build Coastguard Worker if (colon == str) {
179*4dc78e53SAndroid Build Coastguard Worker not_a_number:
180*4dc78e53SAndroid Build Coastguard Worker if (*colon == ':') {
181*4dc78e53SAndroid Build Coastguard Worker /* :YYYY */
182*4dc78e53SAndroid Build Coastguard Worker h = 0;
183*4dc78e53SAndroid Build Coastguard Worker } else {
184*4dc78e53SAndroid Build Coastguard Worker size_t len;
185*4dc78e53SAndroid Build Coastguard Worker char name[64] = { 0 };
186*4dc78e53SAndroid Build Coastguard Worker
187*4dc78e53SAndroid Build Coastguard Worker if (!(colon = strpbrk(str, ":"))) {
188*4dc78e53SAndroid Build Coastguard Worker /* NAME */
189*4dc78e53SAndroid Build Coastguard Worker return classid_lookup(str, res);
190*4dc78e53SAndroid Build Coastguard Worker } else {
191*4dc78e53SAndroid Build Coastguard Worker /* NAME:YYYY */
192*4dc78e53SAndroid Build Coastguard Worker len = colon - str;
193*4dc78e53SAndroid Build Coastguard Worker if (len >= sizeof(name))
194*4dc78e53SAndroid Build Coastguard Worker return -NLE_INVAL;
195*4dc78e53SAndroid Build Coastguard Worker
196*4dc78e53SAndroid Build Coastguard Worker memcpy(name, str, len);
197*4dc78e53SAndroid Build Coastguard Worker
198*4dc78e53SAndroid Build Coastguard Worker if ((err = classid_lookup(name, &h)) < 0)
199*4dc78e53SAndroid Build Coastguard Worker return err;
200*4dc78e53SAndroid Build Coastguard Worker
201*4dc78e53SAndroid Build Coastguard Worker /* Name must point to a qdisc alias */
202*4dc78e53SAndroid Build Coastguard Worker if (TC_H_MIN(h))
203*4dc78e53SAndroid Build Coastguard Worker return -NLE_INVAL;
204*4dc78e53SAndroid Build Coastguard Worker
205*4dc78e53SAndroid Build Coastguard Worker /* NAME: is not allowed */
206*4dc78e53SAndroid Build Coastguard Worker if (colon[1] == '\0')
207*4dc78e53SAndroid Build Coastguard Worker return -NLE_INVAL;
208*4dc78e53SAndroid Build Coastguard Worker
209*4dc78e53SAndroid Build Coastguard Worker goto update;
210*4dc78e53SAndroid Build Coastguard Worker }
211*4dc78e53SAndroid Build Coastguard Worker }
212*4dc78e53SAndroid Build Coastguard Worker }
213*4dc78e53SAndroid Build Coastguard Worker
214*4dc78e53SAndroid Build Coastguard Worker if (':' == *colon) {
215*4dc78e53SAndroid Build Coastguard Worker /* check if we would lose bits */
216*4dc78e53SAndroid Build Coastguard Worker if (TC_H_MAJ(h))
217*4dc78e53SAndroid Build Coastguard Worker return -NLE_RANGE;
218*4dc78e53SAndroid Build Coastguard Worker h <<= 16;
219*4dc78e53SAndroid Build Coastguard Worker
220*4dc78e53SAndroid Build Coastguard Worker if ('\0' == colon[1]) {
221*4dc78e53SAndroid Build Coastguard Worker /* XXXX: */
222*4dc78e53SAndroid Build Coastguard Worker *res = h;
223*4dc78e53SAndroid Build Coastguard Worker } else {
224*4dc78e53SAndroid Build Coastguard Worker /* XXXX:YYYY */
225*4dc78e53SAndroid Build Coastguard Worker uint32_t l;
226*4dc78e53SAndroid Build Coastguard Worker
227*4dc78e53SAndroid Build Coastguard Worker update:
228*4dc78e53SAndroid Build Coastguard Worker l = strtoul(colon+1, &end, 16);
229*4dc78e53SAndroid Build Coastguard Worker
230*4dc78e53SAndroid Build Coastguard Worker /* check if we overlap with major part */
231*4dc78e53SAndroid Build Coastguard Worker if (TC_H_MAJ(l))
232*4dc78e53SAndroid Build Coastguard Worker return -NLE_RANGE;
233*4dc78e53SAndroid Build Coastguard Worker
234*4dc78e53SAndroid Build Coastguard Worker if ('\0' != *end)
235*4dc78e53SAndroid Build Coastguard Worker return -NLE_INVAL;
236*4dc78e53SAndroid Build Coastguard Worker
237*4dc78e53SAndroid Build Coastguard Worker *res = (h | l);
238*4dc78e53SAndroid Build Coastguard Worker }
239*4dc78e53SAndroid Build Coastguard Worker } else if ('\0' == *colon) {
240*4dc78e53SAndroid Build Coastguard Worker /* XXXXYYYY */
241*4dc78e53SAndroid Build Coastguard Worker *res = h;
242*4dc78e53SAndroid Build Coastguard Worker } else
243*4dc78e53SAndroid Build Coastguard Worker goto not_a_number;
244*4dc78e53SAndroid Build Coastguard Worker
245*4dc78e53SAndroid Build Coastguard Worker return 0;
246*4dc78e53SAndroid Build Coastguard Worker }
247*4dc78e53SAndroid Build Coastguard Worker
free_nothing(void * arg)248*4dc78e53SAndroid Build Coastguard Worker static void free_nothing(void *arg)
249*4dc78e53SAndroid Build Coastguard Worker {
250*4dc78e53SAndroid Build Coastguard Worker }
251*4dc78e53SAndroid Build Coastguard Worker
classid_map_free(struct classid_map * map)252*4dc78e53SAndroid Build Coastguard Worker static void classid_map_free(struct classid_map *map)
253*4dc78e53SAndroid Build Coastguard Worker {
254*4dc78e53SAndroid Build Coastguard Worker if (!map)
255*4dc78e53SAndroid Build Coastguard Worker return;
256*4dc78e53SAndroid Build Coastguard Worker
257*4dc78e53SAndroid Build Coastguard Worker free(map->name);
258*4dc78e53SAndroid Build Coastguard Worker free(map);
259*4dc78e53SAndroid Build Coastguard Worker }
260*4dc78e53SAndroid Build Coastguard Worker
clear_hashtable(void)261*4dc78e53SAndroid Build Coastguard Worker static void clear_hashtable(void)
262*4dc78e53SAndroid Build Coastguard Worker {
263*4dc78e53SAndroid Build Coastguard Worker int i;
264*4dc78e53SAndroid Build Coastguard Worker
265*4dc78e53SAndroid Build Coastguard Worker for (i = 0; i < CLASSID_NAME_HT_SIZ; i++) {
266*4dc78e53SAndroid Build Coastguard Worker struct classid_map *map, *n;
267*4dc78e53SAndroid Build Coastguard Worker
268*4dc78e53SAndroid Build Coastguard Worker nl_list_for_each_entry_safe(map, n, &tbl_name[i], name_list)
269*4dc78e53SAndroid Build Coastguard Worker classid_map_free(map);
270*4dc78e53SAndroid Build Coastguard Worker
271*4dc78e53SAndroid Build Coastguard Worker nl_init_list_head(&tbl_name[i]);
272*4dc78e53SAndroid Build Coastguard Worker
273*4dc78e53SAndroid Build Coastguard Worker }
274*4dc78e53SAndroid Build Coastguard Worker
275*4dc78e53SAndroid Build Coastguard Worker if (id_root) {
276*4dc78e53SAndroid Build Coastguard Worker tdestroy(&id_root, &free_nothing);
277*4dc78e53SAndroid Build Coastguard Worker id_root = NULL;
278*4dc78e53SAndroid Build Coastguard Worker }
279*4dc78e53SAndroid Build Coastguard Worker }
280*4dc78e53SAndroid Build Coastguard Worker
classid_map_add(uint32_t classid,const char * name)281*4dc78e53SAndroid Build Coastguard Worker static int classid_map_add(uint32_t classid, const char *name)
282*4dc78e53SAndroid Build Coastguard Worker {
283*4dc78e53SAndroid Build Coastguard Worker struct classid_map *map;
284*4dc78e53SAndroid Build Coastguard Worker int n;
285*4dc78e53SAndroid Build Coastguard Worker
286*4dc78e53SAndroid Build Coastguard Worker if (!(map = calloc(1, sizeof(*map))))
287*4dc78e53SAndroid Build Coastguard Worker return -NLE_NOMEM;
288*4dc78e53SAndroid Build Coastguard Worker
289*4dc78e53SAndroid Build Coastguard Worker map->classid = classid;
290*4dc78e53SAndroid Build Coastguard Worker map->name = strdup(name);
291*4dc78e53SAndroid Build Coastguard Worker
292*4dc78e53SAndroid Build Coastguard Worker n = classid_tbl_hash(map->name);
293*4dc78e53SAndroid Build Coastguard Worker nl_list_add_tail(&map->name_list, &tbl_name[n]);
294*4dc78e53SAndroid Build Coastguard Worker
295*4dc78e53SAndroid Build Coastguard Worker if (!tsearch((void *) map, &id_root, &compare_id)) {
296*4dc78e53SAndroid Build Coastguard Worker classid_map_free(map);
297*4dc78e53SAndroid Build Coastguard Worker return -NLE_NOMEM;
298*4dc78e53SAndroid Build Coastguard Worker }
299*4dc78e53SAndroid Build Coastguard Worker
300*4dc78e53SAndroid Build Coastguard Worker return 0;
301*4dc78e53SAndroid Build Coastguard Worker }
302*4dc78e53SAndroid Build Coastguard Worker
303*4dc78e53SAndroid Build Coastguard Worker /**
304*4dc78e53SAndroid Build Coastguard Worker * (Re-)read classid file
305*4dc78e53SAndroid Build Coastguard Worker *
306*4dc78e53SAndroid Build Coastguard Worker * Rereads the contents of the classid file (typically found at the location
307*4dc78e53SAndroid Build Coastguard Worker * /etc/libnl/classid) and refreshes the classid maps.
308*4dc78e53SAndroid Build Coastguard Worker *
309*4dc78e53SAndroid Build Coastguard Worker * @return 0 on success or a negative error code.
310*4dc78e53SAndroid Build Coastguard Worker */
rtnl_tc_read_classid_file(void)311*4dc78e53SAndroid Build Coastguard Worker int rtnl_tc_read_classid_file(void)
312*4dc78e53SAndroid Build Coastguard Worker {
313*4dc78e53SAndroid Build Coastguard Worker static time_t last_read;
314*4dc78e53SAndroid Build Coastguard Worker struct stat st;
315*4dc78e53SAndroid Build Coastguard Worker char buf[256], *path;
316*4dc78e53SAndroid Build Coastguard Worker FILE *fd;
317*4dc78e53SAndroid Build Coastguard Worker int err;
318*4dc78e53SAndroid Build Coastguard Worker
319*4dc78e53SAndroid Build Coastguard Worker if (build_sysconf_path(&path, "classid") < 0)
320*4dc78e53SAndroid Build Coastguard Worker return -NLE_NOMEM;
321*4dc78e53SAndroid Build Coastguard Worker
322*4dc78e53SAndroid Build Coastguard Worker /* if stat fails, just (re-)read the file */
323*4dc78e53SAndroid Build Coastguard Worker if (stat(path, &st) == 0) {
324*4dc78e53SAndroid Build Coastguard Worker /* Don't re-read file if file is unchanged */
325*4dc78e53SAndroid Build Coastguard Worker if (last_read == st.st_mtime) {
326*4dc78e53SAndroid Build Coastguard Worker err = 0;
327*4dc78e53SAndroid Build Coastguard Worker goto errout;
328*4dc78e53SAndroid Build Coastguard Worker }
329*4dc78e53SAndroid Build Coastguard Worker }
330*4dc78e53SAndroid Build Coastguard Worker
331*4dc78e53SAndroid Build Coastguard Worker if (!(fd = fopen(path, "re"))) {
332*4dc78e53SAndroid Build Coastguard Worker err = -nl_syserr2nlerr(errno);
333*4dc78e53SAndroid Build Coastguard Worker goto errout;
334*4dc78e53SAndroid Build Coastguard Worker }
335*4dc78e53SAndroid Build Coastguard Worker
336*4dc78e53SAndroid Build Coastguard Worker clear_hashtable();
337*4dc78e53SAndroid Build Coastguard Worker
338*4dc78e53SAndroid Build Coastguard Worker while (fgets(buf, sizeof(buf), fd)) {
339*4dc78e53SAndroid Build Coastguard Worker uint32_t classid;
340*4dc78e53SAndroid Build Coastguard Worker char *ptr, *tok;
341*4dc78e53SAndroid Build Coastguard Worker
342*4dc78e53SAndroid Build Coastguard Worker /* ignore comments and empty lines */
343*4dc78e53SAndroid Build Coastguard Worker if (*buf == '#' || *buf == '\n' || *buf == '\r')
344*4dc78e53SAndroid Build Coastguard Worker continue;
345*4dc78e53SAndroid Build Coastguard Worker
346*4dc78e53SAndroid Build Coastguard Worker /* token 1 */
347*4dc78e53SAndroid Build Coastguard Worker if (!(tok = strtok_r(buf, " \t", &ptr))) {
348*4dc78e53SAndroid Build Coastguard Worker err = -NLE_INVAL;
349*4dc78e53SAndroid Build Coastguard Worker goto errout_close;
350*4dc78e53SAndroid Build Coastguard Worker }
351*4dc78e53SAndroid Build Coastguard Worker
352*4dc78e53SAndroid Build Coastguard Worker if ((err = rtnl_tc_str2handle(tok, &classid)) < 0)
353*4dc78e53SAndroid Build Coastguard Worker goto errout_close;
354*4dc78e53SAndroid Build Coastguard Worker
355*4dc78e53SAndroid Build Coastguard Worker if (!(tok = strtok_r(NULL, " \t\n\r#", &ptr))) {
356*4dc78e53SAndroid Build Coastguard Worker err = -NLE_INVAL;
357*4dc78e53SAndroid Build Coastguard Worker goto errout_close;
358*4dc78e53SAndroid Build Coastguard Worker }
359*4dc78e53SAndroid Build Coastguard Worker
360*4dc78e53SAndroid Build Coastguard Worker if ((err = classid_map_add(classid, tok)) < 0)
361*4dc78e53SAndroid Build Coastguard Worker goto errout_close;
362*4dc78e53SAndroid Build Coastguard Worker }
363*4dc78e53SAndroid Build Coastguard Worker
364*4dc78e53SAndroid Build Coastguard Worker err = 0;
365*4dc78e53SAndroid Build Coastguard Worker last_read = st.st_mtime;
366*4dc78e53SAndroid Build Coastguard Worker
367*4dc78e53SAndroid Build Coastguard Worker errout_close:
368*4dc78e53SAndroid Build Coastguard Worker fclose(fd);
369*4dc78e53SAndroid Build Coastguard Worker errout:
370*4dc78e53SAndroid Build Coastguard Worker free(path);
371*4dc78e53SAndroid Build Coastguard Worker
372*4dc78e53SAndroid Build Coastguard Worker return err;
373*4dc78e53SAndroid Build Coastguard Worker
374*4dc78e53SAndroid Build Coastguard Worker }
375*4dc78e53SAndroid Build Coastguard Worker
rtnl_classid_generate(const char * name,uint32_t * result,uint32_t parent)376*4dc78e53SAndroid Build Coastguard Worker int rtnl_classid_generate(const char *name, uint32_t *result, uint32_t parent)
377*4dc78e53SAndroid Build Coastguard Worker {
378*4dc78e53SAndroid Build Coastguard Worker static uint32_t base = 0x4000 << 16;
379*4dc78e53SAndroid Build Coastguard Worker uint32_t classid;
380*4dc78e53SAndroid Build Coastguard Worker char *path;
381*4dc78e53SAndroid Build Coastguard Worker FILE *fd;
382*4dc78e53SAndroid Build Coastguard Worker int err = 0;
383*4dc78e53SAndroid Build Coastguard Worker
384*4dc78e53SAndroid Build Coastguard Worker if (parent == TC_H_ROOT || parent == TC_H_INGRESS) {
385*4dc78e53SAndroid Build Coastguard Worker do {
386*4dc78e53SAndroid Build Coastguard Worker base += (1 << 16);
387*4dc78e53SAndroid Build Coastguard Worker if (base == TC_H_MAJ(TC_H_ROOT))
388*4dc78e53SAndroid Build Coastguard Worker base = 0x4000 << 16;
389*4dc78e53SAndroid Build Coastguard Worker } while (name_lookup(base));
390*4dc78e53SAndroid Build Coastguard Worker
391*4dc78e53SAndroid Build Coastguard Worker classid = base;
392*4dc78e53SAndroid Build Coastguard Worker } else {
393*4dc78e53SAndroid Build Coastguard Worker classid = TC_H_MAJ(parent);
394*4dc78e53SAndroid Build Coastguard Worker do {
395*4dc78e53SAndroid Build Coastguard Worker if (TC_H_MIN(++classid) == TC_H_MIN(TC_H_ROOT))
396*4dc78e53SAndroid Build Coastguard Worker return -NLE_RANGE;
397*4dc78e53SAndroid Build Coastguard Worker } while (name_lookup(classid));
398*4dc78e53SAndroid Build Coastguard Worker }
399*4dc78e53SAndroid Build Coastguard Worker
400*4dc78e53SAndroid Build Coastguard Worker NL_DBG(2, "Generated new classid %#x\n", classid);
401*4dc78e53SAndroid Build Coastguard Worker
402*4dc78e53SAndroid Build Coastguard Worker if (build_sysconf_path(&path, "classid") < 0)
403*4dc78e53SAndroid Build Coastguard Worker return -NLE_NOMEM;
404*4dc78e53SAndroid Build Coastguard Worker
405*4dc78e53SAndroid Build Coastguard Worker if (!(fd = fopen(path, "ae"))) {
406*4dc78e53SAndroid Build Coastguard Worker err = -nl_syserr2nlerr(errno);
407*4dc78e53SAndroid Build Coastguard Worker goto errout;
408*4dc78e53SAndroid Build Coastguard Worker }
409*4dc78e53SAndroid Build Coastguard Worker
410*4dc78e53SAndroid Build Coastguard Worker fprintf(fd, "%x:", TC_H_MAJ(classid) >> 16);
411*4dc78e53SAndroid Build Coastguard Worker if (TC_H_MIN(classid))
412*4dc78e53SAndroid Build Coastguard Worker fprintf(fd, "%x", TC_H_MIN(classid));
413*4dc78e53SAndroid Build Coastguard Worker fprintf(fd, "\t\t\t%s\n", name);
414*4dc78e53SAndroid Build Coastguard Worker
415*4dc78e53SAndroid Build Coastguard Worker fclose(fd);
416*4dc78e53SAndroid Build Coastguard Worker
417*4dc78e53SAndroid Build Coastguard Worker if (classid_map_add(classid, name) < 0) {
418*4dc78e53SAndroid Build Coastguard Worker /*
419*4dc78e53SAndroid Build Coastguard Worker * Error adding classid map, re-read classid file is best
420*4dc78e53SAndroid Build Coastguard Worker * option here. It is likely to fail as well but better
421*4dc78e53SAndroid Build Coastguard Worker * than nothing, entry was added to the file already anyway.
422*4dc78e53SAndroid Build Coastguard Worker */
423*4dc78e53SAndroid Build Coastguard Worker rtnl_tc_read_classid_file();
424*4dc78e53SAndroid Build Coastguard Worker }
425*4dc78e53SAndroid Build Coastguard Worker
426*4dc78e53SAndroid Build Coastguard Worker *result = classid;
427*4dc78e53SAndroid Build Coastguard Worker err = 0;
428*4dc78e53SAndroid Build Coastguard Worker errout:
429*4dc78e53SAndroid Build Coastguard Worker free(path);
430*4dc78e53SAndroid Build Coastguard Worker
431*4dc78e53SAndroid Build Coastguard Worker return err;
432*4dc78e53SAndroid Build Coastguard Worker }
433*4dc78e53SAndroid Build Coastguard Worker
434*4dc78e53SAndroid Build Coastguard Worker /** @} */
435*4dc78e53SAndroid Build Coastguard Worker
classid_init(void)436*4dc78e53SAndroid Build Coastguard Worker static void _nl_init classid_init(void)
437*4dc78e53SAndroid Build Coastguard Worker {
438*4dc78e53SAndroid Build Coastguard Worker int err, i;
439*4dc78e53SAndroid Build Coastguard Worker
440*4dc78e53SAndroid Build Coastguard Worker for (i = 0; i < CLASSID_NAME_HT_SIZ; i++)
441*4dc78e53SAndroid Build Coastguard Worker nl_init_list_head(&tbl_name[i]);
442*4dc78e53SAndroid Build Coastguard Worker
443*4dc78e53SAndroid Build Coastguard Worker if ((err = rtnl_tc_read_classid_file()) < 0)
444*4dc78e53SAndroid Build Coastguard Worker NL_DBG(1, "Failed to read classid file: %s\n", nl_geterror(err));
445*4dc78e53SAndroid Build Coastguard Worker }
446*4dc78e53SAndroid Build Coastguard Worker
free_map(void * map)447*4dc78e53SAndroid Build Coastguard Worker static void free_map(void *map)
448*4dc78e53SAndroid Build Coastguard Worker {
449*4dc78e53SAndroid Build Coastguard Worker free(((struct classid_map *)map)->name);
450*4dc78e53SAndroid Build Coastguard Worker free(map);
451*4dc78e53SAndroid Build Coastguard Worker }
452*4dc78e53SAndroid Build Coastguard Worker
classid_exit(void)453*4dc78e53SAndroid Build Coastguard Worker static void _nl_exit classid_exit(void)
454*4dc78e53SAndroid Build Coastguard Worker {
455*4dc78e53SAndroid Build Coastguard Worker tdestroy(id_root, free_map);
456*4dc78e53SAndroid Build Coastguard Worker }
457*4dc78e53SAndroid Build Coastguard Worker /** @} */
458