diff options
-rw-r--r-- | etc/classid | 11 | ||||
-rw-r--r-- | include/netlink/cli/tc.h | 2 | ||||
-rw-r--r-- | include/netlink/route/tc.h | 2 | ||||
-rw-r--r-- | lib/route/classid.c | 138 | ||||
-rw-r--r-- | src/lib/tc.c | 17 | ||||
-rw-r--r-- | src/nl-class-add.c | 9 | ||||
-rw-r--r-- | src/nl-class-delete.c | 2 | ||||
-rw-r--r-- | src/nl-class-list.c | 2 | ||||
-rw-r--r-- | src/nl-cls-add.c | 9 | ||||
-rw-r--r-- | src/nl-cls-delete.c | 2 | ||||
-rw-r--r-- | src/nl-cls-list.c | 2 | ||||
-rw-r--r-- | src/nl-qdisc-add.c | 9 | ||||
-rw-r--r-- | src/nl-qdisc-delete.c | 2 | ||||
-rw-r--r-- | src/nl-qdisc-list.c | 2 |
14 files changed, 162 insertions, 47 deletions
diff --git a/etc/classid b/etc/classid index 76a11f2..2203243 100644 --- a/etc/classid +++ b/etc/classid @@ -32,5 +32,14 @@ ffff:ffff root ffff:fff1 ingress # -# List your classid definitions below: +# List your classid definitions here: # + + + +############################################################################### +# List of auto-generated classids +# +# DO NOT ADD CLASSID DEFINITIONS BELOW THIS LINE +# +# <CLASSID> <NAME> diff --git a/include/netlink/cli/tc.h b/include/netlink/cli/tc.h index 762cc69..82f9a1d 100644 --- a/include/netlink/cli/tc.h +++ b/include/netlink/cli/tc.h @@ -16,7 +16,7 @@ extern void nl_cli_tc_parse_dev(struct rtnl_tc *, struct nl_cache *, char *); extern void nl_cli_tc_parse_parent(struct rtnl_tc *, char *); -extern void nl_cli_tc_parse_handle(struct rtnl_tc *, char *); +extern void nl_cli_tc_parse_handle(struct rtnl_tc *, char *, int); extern void nl_cli_tc_parse_mtu(struct rtnl_tc *, char *); extern void nl_cli_tc_parse_mpu(struct rtnl_tc *, char *); extern void nl_cli_tc_parse_overhead(struct rtnl_tc *, char *); diff --git a/include/netlink/route/tc.h b/include/netlink/route/tc.h index b4e953e..f1e8605 100644 --- a/include/netlink/route/tc.h +++ b/include/netlink/route/tc.h @@ -66,6 +66,8 @@ extern int rtnl_tc_calc_cell_log(int); extern int rtnl_tc_read_classid_file(void); extern char * rtnl_tc_handle2str(uint32_t, char *, size_t); extern int rtnl_tc_str2handle(const char *, uint32_t *); +extern int rtnl_classid_generate(const char *, uint32_t *, + uint32_t); #ifdef __cplusplus } diff --git a/lib/route/classid.c b/lib/route/classid.c index 5650a20..0cb89b5 100644 --- a/lib/route/classid.c +++ b/lib/route/classid.c @@ -75,6 +75,20 @@ static int classid_lookup(const char *name, uint32_t *result) return -NLE_OBJ_NOTFOUND; } +static char *name_lookup(const uint32_t classid) +{ + void *res; + struct classid_map cm = { + .classid = classid, + .name = "search entry", + }; + + if ((res = tfind(&cm, &id_root, &compare_id))) + return (*(struct classid_map **) res)->name; + + return NULL; +} + /** * @name Traffic Control Handle Translations * @{ @@ -101,14 +115,10 @@ char * rtnl_tc_handle2str(uint32_t handle, char *buf, size_t len) else if (TC_H_INGRESS == handle) snprintf(buf, len, "ingress"); else { - void *res; - struct classid_map cm = { - .classid = handle, - .name = "search entry", - }; - - if ((res = tfind(&cm, &id_root, &compare_id))) - snprintf(buf, len, "%s", (*(struct classid_map **) res)->name); + char *name; + + if ((name = name_lookup(handle))) + snprintf(buf, len, "%s", name); else if (0 == TC_H_MAJ(handle)) snprintf(buf, len, ":%02x", TC_H_MIN(handle)); else if (0 == TC_H_MIN(handle)) @@ -232,6 +242,15 @@ static void free_nothing(void *arg) { } +static void classid_map_free(struct classid_map *map) +{ + if (!map) + return; + + free(map->name); + free(map); +} + static void clear_hashtable(void) { int i; @@ -239,10 +258,8 @@ static void clear_hashtable(void) for (i = 0; i < CLASSID_NAME_HT_SIZ; i++) { struct classid_map *map, *n; - nl_list_for_each_entry_safe(map, n, &tbl_name[i], name_list) { - free(map->name); - free(map); - } + nl_list_for_each_entry_safe(map, n, &tbl_name[i], name_list) + classid_map_free(map); nl_init_list_head(&tbl_name[i]); @@ -254,6 +271,28 @@ static void clear_hashtable(void) } } +static int classid_map_add(uint32_t classid, const char *name) +{ + struct classid_map *map; + int n; + + if (!(map = calloc(1, sizeof(*map)))) + return -NLE_NOMEM; + + map->classid = classid; + map->name = strdup(name); + + n = classid_tbl_hash(map->name); + nl_list_add_tail(&map->name_list, &tbl_name[n]); + + if (!tsearch((void *) map, &id_root, &compare_id)) { + classid_map_free(map); + return -NLE_NOMEM; + } + + return 0; +} + /** * (Re-)read classid file * @@ -289,10 +328,8 @@ int rtnl_tc_read_classid_file(void) clear_hashtable(); while (fgets(buf, sizeof(buf), fd)) { - struct classid_map *map; uint32_t classid; char *ptr, *tok; - int n; /* ignore comments and empty lines */ if (*buf == '#' || *buf == '\n' || *buf == '\r') @@ -312,21 +349,8 @@ int rtnl_tc_read_classid_file(void) goto errout_close; } - if (!(map = calloc(1, sizeof(*map)))) { - err = -NLE_NOMEM; + if ((err = classid_map_add(classid, tok)) < 0) goto errout_close; - } - - map->classid = classid; - map->name = strdup(tok); - - n = classid_tbl_hash(map->name); - nl_list_add_tail(&map->name_list, &tbl_name[n]); - - if (!tsearch((void *) map, &id_root, &compare_id)) { - err = -NLE_NOMEM; - goto errout_close; - } } err = 0; @@ -341,6 +365,64 @@ errout: } +int rtnl_classid_generate(const char *name, uint32_t *result, uint32_t parent) +{ + static uint32_t base = 0x4000 << 16; + uint32_t classid; + char *path; + FILE *fd; + int err = 0; + + if (parent == TC_H_ROOT || parent == TC_H_INGRESS) { + do { + base += (1 << 16); + if (base == TC_H_MAJ(TC_H_ROOT)) + base = 0x4000 << 16; + } while (name_lookup(base)); + + classid = base; + } else { + classid = TC_H_MAJ(parent); + do { + if (++classid == TC_H_MIN(TC_H_ROOT)) + return -NLE_RANGE; + } while (name_lookup(base)); + } + + NL_DBG(2, "Generated new classid %#x\n", classid); + + if (asprintf(&path, "%s/classid", SYSCONFDIR) < 0) + return -NLE_NOMEM; + + if (!(fd = fopen(path, "a"))) { + err = -nl_syserr2nlerr(errno); + goto errout; + } + + fprintf(fd, "%x:", TC_H_MAJ(classid) >> 16); + if (TC_H_MIN(classid)) + fprintf(fd, "%x", TC_H_MIN(classid)); + fprintf(fd, "\t\t\t%s\n", name); + + fclose(fd); + + if ((err = classid_map_add(classid, name)) < 0) { + /* + * Error adding classid map, re-read classid file is best + * option here. It is likely to fail as well but better + * than nothing, entry was added to the file already anyway. + */ + rtnl_tc_read_classid_file(); + } + + *result = classid; + err = 0; +errout: + free(path); + + return err; +} + /** @} */ static void __init classid_init(void) diff --git a/src/lib/tc.c b/src/lib/tc.c index 5f39498..72407cf 100644 --- a/src/lib/tc.c +++ b/src/lib/tc.c @@ -42,14 +42,21 @@ void nl_cli_tc_parse_parent(struct rtnl_tc *tc, char *arg) rtnl_tc_set_parent(tc, parent); } -void nl_cli_tc_parse_handle(struct rtnl_tc *tc, char *arg) +void nl_cli_tc_parse_handle(struct rtnl_tc *tc, char *arg, int create) { - uint32_t handle; + uint32_t handle, parent; int err; - if ((err = rtnl_tc_str2handle(arg, &handle)) < 0) - nl_cli_fatal(err, "Unable to parse handle \"%s\": %s", - arg, nl_geterror(err)); + parent = rtnl_tc_get_parent(tc); + + if ((err = rtnl_tc_str2handle(arg, &handle)) < 0) { + if (err == -NLE_OBJ_NOTFOUND && create) + err = rtnl_classid_generate(arg, &handle, parent); + + if (err < 0) + nl_cli_fatal(err, "Unable to parse handle \"%s\": %s", + arg, nl_geterror(err)); + } rtnl_tc_set_handle(tc, handle); } diff --git a/src/nl-class-add.c b/src/nl-class-add.c index 553dec1..80ea826 100644 --- a/src/nl-class-add.c +++ b/src/nl-class-add.c @@ -59,7 +59,7 @@ int main(int argc, char *argv[]) struct nl_cli_qdisc_module *qm; struct rtnl_class_ops *ops; int err, flags = NLM_F_CREATE | NLM_F_EXCL; - char *kind; + char *kind, *id = NULL; sock = nl_cli_alloc_socket(); nl_cli_connect(sock, NETLINK_ROUTE); @@ -106,7 +106,7 @@ int main(int argc, char *argv[]) case 'v': nl_cli_print_version(); break; case 'd': nl_cli_tc_parse_dev(tc, link_cache, optarg); break; case 'p': nl_cli_tc_parse_parent(tc, optarg); break; - case 'i': nl_cli_tc_parse_handle(tc, optarg); break; + case 'i': id = strdup(optarg); break; case ARG_UPDATE: flags = NLM_F_CREATE; break; case ARG_UPDATE_ONLY: flags = 0; break; case ARG_MTU: nl_cli_tc_parse_mtu(tc, optarg); break; @@ -125,6 +125,11 @@ int main(int argc, char *argv[]) if (!rtnl_tc_get_parent(tc)) nl_cli_fatal(EINVAL, "You must specify a parent (--parent=XXX)"); + if (id) { + nl_cli_tc_parse_handle(tc, id, 1); + free(id); + } + kind = argv[optind++]; rtnl_class_set_kind(class, kind); diff --git a/src/nl-class-delete.c b/src/nl-class-delete.c index 94a6ab4..3c5cdc1 100644 --- a/src/nl-class-delete.c +++ b/src/nl-class-delete.c @@ -109,7 +109,7 @@ int main(int argc, char *argv[]) case 'v': nl_cli_print_version(); break; case 'd': nl_cli_tc_parse_dev(tc, link_cache, optarg); break; case 'p': nl_cli_tc_parse_parent(tc, optarg); break; - case 'i': nl_cli_tc_parse_handle(tc, optarg); break; + case 'i': nl_cli_tc_parse_handle(tc, optarg, 0); break; case 'k': nl_cli_class_parse_kind(class, optarg); break; } } diff --git a/src/nl-class-list.c b/src/nl-class-list.c index 3a38555..fccc512 100644 --- a/src/nl-class-list.c +++ b/src/nl-class-list.c @@ -103,7 +103,7 @@ int main(int argc, char *argv[]) case 'v': nl_cli_print_version(); break; case 'd': nl_cli_tc_parse_dev(tc, link_cache, optarg); break; case 'p': nl_cli_tc_parse_parent(tc, optarg); break; - case 'i': nl_cli_tc_parse_handle(tc, optarg); break; + case 'i': nl_cli_tc_parse_handle(tc, optarg, 0); break; case 'k': nl_cli_class_parse_kind(class, optarg); break; } } diff --git a/src/nl-cls-add.c b/src/nl-cls-add.c index 5e2c2dc..fad9313 100644 --- a/src/nl-cls-add.c +++ b/src/nl-cls-add.c @@ -59,7 +59,7 @@ int main(int argc, char *argv[]) struct nl_cli_cls_module *cm; struct rtnl_cls_ops *ops; int err, flags = NLM_F_CREATE | NLM_F_EXCL; - char *kind; + char *kind, *id = NULL; sock = nl_cli_alloc_socket(); nl_cli_connect(sock, NETLINK_ROUTE); @@ -110,7 +110,7 @@ int main(int argc, char *argv[]) case 'v': nl_cli_print_version(); break; case 'd': nl_cli_tc_parse_dev(tc, link_cache, optarg); break; case 'p': nl_cli_tc_parse_parent(tc, optarg); break; - case 'i': nl_cli_tc_parse_handle(tc, optarg); break; + case 'i': id = strdup(optarg); break; case ARG_UPDATE: flags = NLM_F_CREATE; break; case ARG_UPDATE_ONLY: flags = 0; break; case ARG_MTU: nl_cli_tc_parse_mtu(tc, optarg); break; @@ -133,6 +133,11 @@ int main(int argc, char *argv[]) if (!rtnl_tc_get_parent(tc)) nl_cli_fatal(EINVAL, "You must specify a parent (--parent=XXX)"); + if (id) { + nl_cli_tc_parse_handle(tc, id, 1); + free(id); + } + kind = argv[optind++]; rtnl_cls_set_kind(cls, kind); diff --git a/src/nl-cls-delete.c b/src/nl-cls-delete.c index 0ffffb2..359d15e 100644 --- a/src/nl-cls-delete.c +++ b/src/nl-cls-delete.c @@ -134,7 +134,7 @@ int main(int argc, char *argv[]) case 'v': nl_cli_print_version(); break; case 'd': nl_cli_tc_parse_dev(tc, link_cache, optarg); break; case 'p': nl_cli_tc_parse_parent(tc, optarg); break; - case 'i': nl_cli_tc_parse_handle(tc, optarg); break; + case 'i': nl_cli_tc_parse_handle(tc, optarg, 0); break; case 'k': nl_cli_cls_parse_kind(cls, optarg); break; case ARG_PROTO: nl_cli_cls_parse_proto(cls, optarg); break; case ARG_PRIO: diff --git a/src/nl-cls-list.c b/src/nl-cls-list.c index a0220f8..e7c9a12 100644 --- a/src/nl-cls-list.c +++ b/src/nl-cls-list.c @@ -111,7 +111,7 @@ int main(int argc, char *argv[]) case 'v': nl_cli_print_version(); break; case 'd': nl_cli_tc_parse_dev(tc, link_cache, optarg); break; case 'p': nl_cli_tc_parse_parent(tc, optarg); break; - case 'i': nl_cli_tc_parse_handle(tc, optarg); break; + case 'i': nl_cli_tc_parse_handle(tc, optarg, 0); break; case 'k': nl_cli_cls_parse_kind(cls, optarg); break; case ARG_PROTO: nl_cli_cls_parse_proto(cls, optarg); break; case ARG_PRIO: diff --git a/src/nl-qdisc-add.c b/src/nl-qdisc-add.c index 57603b0..9da0f18 100644 --- a/src/nl-qdisc-add.c +++ b/src/nl-qdisc-add.c @@ -56,7 +56,7 @@ int main(int argc, char *argv[]) struct nl_cli_qdisc_module *qm; struct rtnl_qdisc_ops *ops; int err, flags = NLM_F_CREATE | NLM_F_EXCL; - char *kind; + char *kind, *id = NULL; sock = nl_cli_alloc_socket(); nl_cli_connect(sock, NETLINK_ROUTE); @@ -99,7 +99,7 @@ int main(int argc, char *argv[]) case 'v': nl_cli_print_version(); break; case 'd': nl_cli_tc_parse_dev(tc, link_cache, optarg); break; case 'p': nl_cli_tc_parse_parent(tc, optarg); break; - case 'i': nl_cli_tc_parse_handle(tc, optarg); break; + case 'i': id = strdup(optarg); break; case ARG_UPDATE: flags = NLM_F_CREATE; break; case ARG_REPLACE: flags = NLM_F_CREATE | NLM_F_REPLACE; break; case ARG_UPDATE_ONLY: flags = 0; break; @@ -116,6 +116,11 @@ int main(int argc, char *argv[]) if (!rtnl_tc_get_parent(tc)) nl_cli_fatal(EINVAL, "You must specify a parent"); + if (id) { + nl_cli_tc_parse_handle(tc, id, 1); + free(id); + } + kind = argv[optind++]; rtnl_qdisc_set_kind(qdisc, kind); diff --git a/src/nl-qdisc-delete.c b/src/nl-qdisc-delete.c index e91b054..943d5ae 100644 --- a/src/nl-qdisc-delete.c +++ b/src/nl-qdisc-delete.c @@ -115,7 +115,7 @@ int main(int argc, char *argv[]) break; case 'i': nfilter++; - nl_cli_tc_parse_handle(tc, optarg); + nl_cli_tc_parse_handle(tc, optarg, 0); break; case 'k': nfilter++; diff --git a/src/nl-qdisc-list.c b/src/nl-qdisc-list.c index 1ecb9a4..de24fde 100644 --- a/src/nl-qdisc-list.c +++ b/src/nl-qdisc-list.c @@ -85,7 +85,7 @@ int main(int argc, char *argv[]) case 'v': nl_cli_print_version(); break; case 'd': nl_cli_tc_parse_dev(tc, link_cache, optarg); break; case 'p': nl_cli_tc_parse_parent(tc, optarg); break; - case 'i': nl_cli_tc_parse_handle(tc, optarg); break; + case 'i': nl_cli_tc_parse_handle(tc, optarg, 0); break; case 'k': nl_cli_qdisc_parse_kind(qdisc, optarg); break; } } |