12#include <netlink-private/netlink.h>
13#include <netlink-private/tc.h>
14#include <netlink/netlink.h>
15#include <netlink/utils.h>
16#include <netlink/route/tc.h>
25#define CLASSID_NAME_HT_SIZ 256
29static void *id_root = NULL;
31static int compare_id(
const void *pa,
const void *pb)
36 if (ma->classid < mb->classid)
39 if (ma->classid > mb->classid)
46static unsigned int classid_tbl_hash(
const char *str)
48 unsigned long hash = 5381;
52 hash = ((hash << 5) + hash) + c;
54 return hash % CLASSID_NAME_HT_SIZ;
57static int classid_lookup(
const char *name, uint32_t *result)
60 int n = classid_tbl_hash(name);
62 nl_list_for_each_entry(map, &tbl_name[n], name_list) {
63 if (!strcasecmp(map->name, name)) {
64 *result = map->classid;
69 return -NLE_OBJ_NOTFOUND;
72static char *name_lookup(
const uint32_t classid)
77 .name =
"search entry",
80 if ((res = tfind(&cm, &id_root, &compare_id)))
105 if (TC_H_ROOT == handle)
106 snprintf(buf, len,
"root");
107 else if (TC_H_UNSPEC == handle)
108 snprintf(buf, len,
"none");
109 else if (TC_H_INGRESS == handle)
110 snprintf(buf, len,
"ingress");
114 if ((name = name_lookup(handle)))
115 snprintf(buf, len,
"%s", name);
116 else if (0 == TC_H_MAJ(handle))
117 snprintf(buf, len,
":%x", TC_H_MIN(handle));
118 else if (0 == TC_H_MIN(handle))
119 snprintf(buf, len,
"%x:", TC_H_MAJ(handle) >> 16);
121 snprintf(buf, len,
"%x:%x",
122 TC_H_MAJ(handle) >> 16, TC_H_MIN(handle));
154 if (!strcasecmp(str,
"root")) {
159 if (!strcasecmp(str,
"none")) {
164 if (!strcasecmp(str,
"ingress")) {
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) {
242static void free_nothing(
void *arg)
246static void classid_map_free(
struct classid_map *map)
255static 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);
275static 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;
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,
"re"))) {
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;
370int 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,
"ae"))) {
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 (classid_map_add(classid, name) < 0) {
430static void __init classid_init(
void)
434 for (i = 0; i < CLASSID_NAME_HT_SIZ; i++)
435 nl_init_list_head(&tbl_name[i]);
438 NL_DBG(1,
"Failed to read classid file: %s\n", nl_geterror(err));
441static void free_map(
void *map)
447static void __exit classid_exit(
void)
449 tdestroy(id_root, free_map);
int rtnl_tc_str2handle(const char *str, uint32_t *res)
Convert a charactering strint to a traffic control handle.
char * rtnl_tc_handle2str(uint32_t handle, char *buf, size_t len)
Convert a traffic control handle to a character string (Reentrant).
int rtnl_tc_read_classid_file(void)
(Re-)read classid file