18 #include <netlink-private/netlink.h>
19 #include <netlink-private/tc.h>
20 #include <netlink/netlink.h>
21 #include <netlink/utils.h>
22 #include <netlink/route/tc.h>
31 #define CLASSID_NAME_HT_SIZ 256
33 static struct nl_list_head tbl_name[CLASSID_NAME_HT_SIZ];
35 static void *id_root = NULL;
37 static int compare_id(
const void *pa,
const void *pb)
42 if (ma->classid < mb->classid)
45 if (ma->classid > mb->classid)
52 static unsigned int classid_tbl_hash(
const char *str)
54 unsigned long hash = 5381;
58 hash = ((hash << 5) + hash) + c;
60 return hash % CLASSID_NAME_HT_SIZ;
63 static int classid_lookup(
const char *name, uint32_t *result)
66 int n = classid_tbl_hash(name);
68 nl_list_for_each_entry(map, &tbl_name[n], name_list) {
69 if (!strcasecmp(map->name, name)) {
70 *result = map->classid;
75 return -NLE_OBJ_NOTFOUND;
78 static char *name_lookup(
const uint32_t classid)
83 .name =
"search entry",
86 if ((res = tfind(&cm, &id_root, &compare_id)))
111 if (TC_H_ROOT == handle)
112 snprintf(buf, len,
"root");
113 else if (TC_H_UNSPEC == handle)
114 snprintf(buf, len,
"none");
115 else if (TC_H_INGRESS == handle)
116 snprintf(buf, len,
"ingress");
120 if ((name = name_lookup(handle)))
121 snprintf(buf, len,
"%s", name);
122 else if (0 == TC_H_MAJ(handle))
123 snprintf(buf, len,
":%x", TC_H_MIN(handle));
124 else if (0 == TC_H_MIN(handle))
125 snprintf(buf, len,
"%x:", TC_H_MAJ(handle) >> 16);
127 snprintf(buf, len,
"%x:%x",
128 TC_H_MAJ(handle) >> 16, TC_H_MIN(handle));
160 if (!strcasecmp(str,
"root")) {
165 if (!strcasecmp(str,
"none")) {
170 if (!strcasecmp(str,
"ingress")) {
175 h = strtoul(str, &colon, 16);
185 char name[64] = { 0 };
187 if (!(colon = strpbrk(str,
":"))) {
189 return classid_lookup(str, res);
193 if (len >=
sizeof(name))
196 memcpy(name, str, len);
198 if ((err = classid_lookup(name, &h)) < 0)
206 if (colon[1] ==
'\0')
220 if (
'\0' == colon[1]) {
228 l = strtoul(colon+1, &end, 16);
239 }
else if (
'\0' == *colon) {
248 static void free_nothing(
void *arg)
252 static void classid_map_free(
struct classid_map *map)
261 static void clear_hashtable(
void)
265 for (i = 0; i < CLASSID_NAME_HT_SIZ; i++) {
268 nl_list_for_each_entry_safe(map, n, &tbl_name[i], name_list)
269 classid_map_free(map);
271 nl_init_list_head(&tbl_name[i]);
276 tdestroy(&id_root, &free_nothing);
281 static int classid_map_add(uint32_t classid,
const char *name)
286 if (!(map = calloc(1,
sizeof(*map))))
289 map->classid = classid;
290 map->name = strdup(name);
292 n = classid_tbl_hash(map->name);
293 nl_list_add_tail(&map->name_list, &tbl_name[n]);
295 if (!tsearch((
void *) map, &id_root, &compare_id)) {
296 classid_map_free(map);
313 static time_t last_read;
315 char buf[256], *path;
319 if (build_sysconf_path(&path,
"classid") < 0)
323 if (stat(path, &st) == 0) {
325 if (last_read == st.st_mtime) {
331 if (!(fd = fopen(path,
"r"))) {
332 err = -nl_syserr2nlerr(errno);
338 while (fgets(buf,
sizeof(buf), fd)) {
343 if (*buf ==
'#' || *buf ==
'\n' || *buf ==
'\r')
347 if (!(tok = strtok_r(buf,
" \t", &ptr))) {
355 if (!(tok = strtok_r(NULL,
" \t\n\r#", &ptr))) {
360 if ((err = classid_map_add(classid, tok)) < 0)
365 last_read = st.st_mtime;
376 int rtnl_classid_generate(
const char *name, uint32_t *result, uint32_t parent)
378 static uint32_t base = 0x4000 << 16;
384 if (parent == TC_H_ROOT || parent == TC_H_INGRESS) {
387 if (base == TC_H_MAJ(TC_H_ROOT))
389 }
while (name_lookup(base));
393 classid = TC_H_MAJ(parent);
395 if (TC_H_MIN(++classid) == TC_H_MIN(TC_H_ROOT))
397 }
while (name_lookup(classid));
400 NL_DBG(2,
"Generated new classid %#x\n", classid);
402 if (build_sysconf_path(&path,
"classid") < 0)
405 if (!(fd = fopen(path,
"a"))) {
406 err = -nl_syserr2nlerr(errno);
410 fprintf(fd,
"%x:", TC_H_MAJ(classid) >> 16);
411 if (TC_H_MIN(classid))
412 fprintf(fd,
"%x", TC_H_MIN(classid));
413 fprintf(fd,
"\t\t\t%s\n", name);
417 if ((err = classid_map_add(classid, name)) < 0) {
436 static void __init classid_init(
void)
440 for (i = 0; i < CLASSID_NAME_HT_SIZ; i++)
441 nl_init_list_head(&tbl_name[i]);
444 NL_DBG(1,
"Failed to read classid file: %s\n", nl_geterror(err));
447 static void free_map(
void *map) {
452 static void __exit classid_exit(
void)
454 tdestroy(id_root, free_map);