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>
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));
159 if (!strcasecmp(str,
"root")) {
164 if (!strcasecmp(str,
"none")) {
169 h = strtoul(str, &colon, 16);
179 char name[64] = { 0 };
181 if (!(colon = strpbrk(str,
":"))) {
183 return classid_lookup(str, res);
187 if (len >=
sizeof(name))
190 memcpy(name, str, len);
192 if ((err = classid_lookup(name, &h)) < 0)
200 if (colon[1] ==
'\0')
214 if (
'\0' == colon[1]) {
222 l = strtoul(colon+1, &end, 16);
233 }
else if (
'\0' == *colon) {
242 static void free_nothing(
void *arg)
246 static void classid_map_free(
struct classid_map *map)
255 static void clear_hashtable(
void)
259 for (i = 0; i < CLASSID_NAME_HT_SIZ; i++) {
262 nl_list_for_each_entry_safe(map, n, &tbl_name[i], name_list)
263 classid_map_free(map);
265 nl_init_list_head(&tbl_name[i]);
270 tdestroy(&id_root, &free_nothing);
275 static int classid_map_add(uint32_t classid,
const char *name)
280 if (!(map = calloc(1,
sizeof(*map))))
283 map->classid = classid;
284 map->name = strdup(name);
286 n = classid_tbl_hash(map->name);
287 nl_list_add_tail(&map->name_list, &tbl_name[n]);
289 if (!tsearch((
void *) map, &id_root, &compare_id)) {
290 classid_map_free(map);
307 static time_t last_read;
308 struct stat st = {0};
309 char buf[256], *path;
313 if (build_sysconf_path(&path,
"classid") < 0)
317 if (stat(path, &st) == 0) {
319 if (last_read == st.st_mtime) {
325 if (!(fd = fopen(path,
"r"))) {
326 err = -nl_syserr2nlerr(errno);
332 while (fgets(buf,
sizeof(buf), fd)) {
337 if (*buf ==
'#' || *buf ==
'\n' || *buf ==
'\r')
341 if (!(tok = strtok_r(buf,
" \t", &ptr))) {
349 if (!(tok = strtok_r(NULL,
" \t\n\r#", &ptr))) {
354 if ((err = classid_map_add(classid, tok)) < 0)
359 last_read = st.st_mtime;
370 int rtnl_classid_generate(
const char *name, uint32_t *result, uint32_t parent)
372 static uint32_t base = 0x4000 << 16;
378 if (parent == TC_H_ROOT || parent == TC_H_INGRESS) {
381 if (base == TC_H_MAJ(TC_H_ROOT))
383 }
while (name_lookup(base));
387 classid = TC_H_MAJ(parent);
389 if (TC_H_MIN(++classid) == TC_H_MIN(TC_H_ROOT))
391 }
while (name_lookup(classid));
394 NL_DBG(2,
"Generated new classid %#x\n", classid);
396 if (build_sysconf_path(&path,
"classid") < 0)
399 if (!(fd = fopen(path,
"a"))) {
400 err = -nl_syserr2nlerr(errno);
404 fprintf(fd,
"%x:", TC_H_MAJ(classid) >> 16);
405 if (TC_H_MIN(classid))
406 fprintf(fd,
"%x", TC_H_MIN(classid));
407 fprintf(fd,
"\t\t\t%s\n", name);
411 if ((err = classid_map_add(classid, name)) < 0) {
430 static void __init classid_init(
void)
434 for (i = 0; i < CLASSID_NAME_HT_SIZ; i++)
435 nl_init_list_head(&tbl_name[i]);
438 fprintf(stderr,
"Failed to read classid file: %s\n", nl_geterror(err));