summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--etc/classid11
-rw-r--r--include/netlink/cli/tc.h2
-rw-r--r--include/netlink/route/tc.h2
-rw-r--r--lib/route/classid.c138
-rw-r--r--src/lib/tc.c17
-rw-r--r--src/nl-class-add.c9
-rw-r--r--src/nl-class-delete.c2
-rw-r--r--src/nl-class-list.c2
-rw-r--r--src/nl-cls-add.c9
-rw-r--r--src/nl-cls-delete.c2
-rw-r--r--src/nl-cls-list.c2
-rw-r--r--src/nl-qdisc-add.c9
-rw-r--r--src/nl-qdisc-delete.c2
-rw-r--r--src/nl-qdisc-list.c2
14 files changed, 162 insertions, 47 deletions
diff --git a/etc/classid b/etc/classid
index 76a11f2a..22032431 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 762cc69d..82f9a1da 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 b4e953ee..f1e8605e 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 5650a209..0cb89b5c 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 5f39498f..72407cf2 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 553dec11..80ea8266 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 94a6ab4b..3c5cdc1a 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 3a385552..fccc5126 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 5e2c2dc5..fad93130 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 0ffffb2b..359d15ea 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 a0220f81..e7c9a121 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 57603b05..9da0f18d 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 e91b054b..943d5ae5 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 1ecb9a47..de24fde1 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;
}
}