]> granicus.if.org Git - libnl/commitdiff
classid auto generation if provided tc name does not exist
authorThomas Graf <tgraf@suug.ch>
Mon, 1 Nov 2010 07:17:40 +0000 (08:17 +0100)
committerThomas Graf <tgraf@suug.ch>
Mon, 1 Nov 2010 07:17:40 +0000 (08:17 +0100)
Manually editing etc/libnl/classid before adding tc objects is a pain.
This patch adds code to attempt auto generating a unique tc id which
will then be assigned to the provided name and added to the classid
file.

This will make the following commands work with prior definitions of
the names "top" and "test"
sudo sbin/nl-qdisc-add --dev eth0 --parent root --id top htb
sudo sbin/nl-class-add --dev eth0 --parent top --id test htb --rate 100mbit

It will generate the following ids automatically:
4001: top
4001:1 test

14 files changed:
etc/classid
include/netlink/cli/tc.h
include/netlink/route/tc.h
lib/route/classid.c
src/lib/tc.c
src/nl-class-add.c
src/nl-class-delete.c
src/nl-class-list.c
src/nl-cls-add.c
src/nl-cls-delete.c
src/nl-cls-list.c
src/nl-qdisc-add.c
src/nl-qdisc-delete.c
src/nl-qdisc-list.c

index 76a11f2aca449742e54e34c8f042c4b70b012fad..2203243145df819ad86c8835012d9583e7dad1ae 100644 (file)
@@ -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>
index 762cc69db4cd2041d1fe737775cd8d2f4ab79ff9..82f9a1da0b46f3f01a8708f1559813af6821e842 100644 (file)
@@ -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 *);
index b4e953ee4e5057b260943a62e3d14de250e56e9b..f1e8605efe7ea604899de5ca25bcb6af74149c11 100644 (file)
@@ -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
 }
index 5650a209ebbdb099e2dc58393f3d79a0b3596553..0cb89b5c5d4fe870773b72a58e57c487c01d63c3 100644 (file)
@@ -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)
index 5f39498f2ae5b0c2f119a206ea230f7f53c7c68f..72407cf210f5f9d75703432d0db381cd3d55957f 100644 (file)
@@ -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);
 }
index 553dec110816715ec332fd4d89f5a6b028ad69c3..80ea826637708a2c49329910a7ae235034402fbe 100644 (file)
@@ -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);
 
index 94a6ab4b7e6d25a262d991cce19549425be3cf2b..3c5cdc1a513069f4f1dadba17cc9d2b08f538c86 100644 (file)
@@ -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;
                }
        }
index 3a3855522e6f3ffcaa3b3ebe09ab8fc8825fd7bd..fccc5126878d281a13b7b0ee3f4ec11439797435 100644 (file)
@@ -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;
                }
        }
index 5e2c2dc55fd5aac92d1da10f408c9605ef5f26c2..fad93130e47573b2ff1f2ae0d7a135288c6f77d3 100644 (file)
@@ -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);
 
index 0ffffb2b44bef8e847f66c22df24bdfe8993306f..359d15ea3c0b4d3fd8115790743006b3b5e21300 100644 (file)
@@ -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:
index a0220f819558a92517f32ef33299d1c815bb1035..e7c9a1210984b467f212a13e35e386dc5c465303 100644 (file)
@@ -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:
index 57603b05b275f1f00eba731f726060ae44198c91..9da0f18d7828fd6abfc3c8cde138b20fb6d5c5ba 100644 (file)
@@ -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);
 
index e91b054bb2f1c6e6c68a2168bf87270f5a993889..943d5ae56cf84dc35cb16b35177b43d21768b97c 100644 (file)
@@ -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++;
index 1ecb9a4736184a671310dd5b7c0a90f68d4ffc9b..de24fde1cd72481b926d06ddff0114c1520cdc1b 100644 (file)
@@ -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;
                }
        }