--- /dev/null
+#ifndef DB_NAMES_H_
+#define DB_NAMES_H_ 1
+
+#define IDNAME_MAX 256
+
+struct db_entry {
+ struct db_entry *next;
+ unsigned int id;
+ char *name;
+};
+
+struct db_names {
+ unsigned int size;
+ struct db_entry *cached;
+ struct db_entry **hash;
+ int max;
+};
+
+struct db_names *db_names_alloc(const char *path);
+void db_names_free(struct db_names *db);
+
+char *id_to_name(struct db_names *db, int id, char *name);
+int name_to_id(struct db_names *db, int *id, const char *name);
+
+#endif
CFLAGS += -fPIC
-UTILOBJ=utils.o rt_names.o ll_types.o ll_proto.o ll_addr.o inet_proto.o namespace.o
+UTILOBJ=utils.o rt_names.o ll_types.o ll_proto.o ll_addr.o inet_proto.o namespace.o \
+ names.o
NLOBJ=libgenl.o ll_map.o libnetlink.o
--- /dev/null
+/*
+ * names.c db names
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "names.h"
+
+#define MAX_ENTRIES 256
+#define NAME_MAX_LEN 512
+
+static int read_id_name(FILE *fp, int *id, char *name)
+{
+ char buf[NAME_MAX_LEN];
+ int min, maj;
+
+ while (fgets(buf, sizeof(buf), fp)) {
+ char *p = buf;
+
+ while (*p == ' ' || *p == '\t')
+ p++;
+
+ if (*p == '#' || *p == '\n' || *p == 0)
+ continue;
+
+ if (sscanf(p, "%x:%x %s\n", &maj, &min, name) == 3) {
+ *id = (maj << 16) | min;
+ } else if (sscanf(p, "%x:%x %s #", &maj, &min, name) == 3) {
+ *id = (maj << 16) | min;
+ } else if (sscanf(p, "0x%x %s\n", id, name) != 2 &&
+ sscanf(p, "0x%x %s #", id, name) != 2 &&
+ sscanf(p, "%d %s\n", id, name) != 2 &&
+ sscanf(p, "%d %s #", id, name) != 2) {
+ strcpy(name, p);
+ return -1;
+ }
+ return 1;
+ }
+
+ return 0;
+}
+
+struct db_names *db_names_alloc(const char *path)
+{
+ struct db_names *db;
+ struct db_entry *entry;
+ FILE *fp;
+ int id;
+ char namebuf[NAME_MAX_LEN] = {0};
+ int ret;
+
+ fp = fopen(path, "r");
+ if (!fp) {
+ fprintf(stderr, "Can't open file: %s\n", path);
+ return NULL;
+ }
+
+ db = malloc(sizeof(*db));
+ memset(db, 0, sizeof(*db));
+
+ db->size = MAX_ENTRIES;
+ db->hash = malloc(sizeof(struct db_entry *) * db->size);
+ memset(db->hash, 0, sizeof(struct db_entry *) * db->size);
+
+ while ((ret = read_id_name(fp, &id, &namebuf[0]))) {
+ if (ret == -1) {
+ fprintf(stderr, "Database %s is corrupted at %s\n",
+ path, namebuf);
+ fclose(fp);
+ return NULL;
+ }
+
+ if (id < 0)
+ continue;
+
+ entry = malloc(sizeof(*entry));
+ entry->id = id;
+ entry->name = strdup(namebuf);
+ entry->next = db->hash[id & (db->size - 1)];
+ db->hash[id & (db->size - 1)] = entry;
+ }
+
+ fclose(fp);
+ return db;
+}
+
+void db_names_free(struct db_names *db)
+{
+ int i;
+
+ if (!db)
+ return;
+
+ for (i = 0; i < db->size; i++) {
+ struct db_entry *entry = db->hash[i];
+
+ while (entry) {
+ struct db_entry *next = entry->next;
+
+ free(entry->name);
+ free(entry);
+ entry = next;
+ }
+ }
+
+ free(db->hash);
+ free(db);
+}
+
+char *id_to_name(struct db_names *db, int id, char *name)
+{
+ struct db_entry *entry = db->hash[id & (db->size - 1)];
+
+ while (entry && entry->id != id)
+ entry = entry->next;
+
+ if (entry) {
+ strncpy(name, entry->name, IDNAME_MAX);
+ return name;
+ }
+
+ snprintf(name, IDNAME_MAX, "%d", id);
+ return NULL;
+}
+
+int name_to_id(struct db_names *db, int *id, const char *name)
+{
+ struct db_entry *entry;
+ int i;
+
+ if (db->cached && strcmp(db->cached->name, name) == 0) {
+ *id = db->cached->id;
+ return 0;
+ }
+
+ for (i = 0; i < db->size; i++) {
+ entry = db->hash[i];
+ while (entry && strcmp(entry->name, name))
+ entry = entry->next;
+ if (entry) {
+ db->cached = entry;
+ *id = entry->id;
+ return 0;
+ }
+ }
+
+ return -1;
+}
int resolve_hosts = 0;
int use_iec = 0;
int force = 0;
+bool use_names = false;
+
+static char *conf_file;
+
struct rtnl_handle rth;
static void *BODY = NULL; /* cached handle dlopen(NULL) */
" tc [-force] -batch filename\n"
"where OBJECT := { qdisc | class | filter | action | monitor }\n"
" OPTIONS := { -s[tatistics] | -d[etails] | -r[aw] | -p[retty] | -b[atch] [filename] | "
- "-n[etns] name }\n");
+ "-n[etns] name |\n"
+ " -nm | -nam[es] | { -cf | -conf } path }\n");
}
static int do_cmd(int argc, char **argv)
return 0;
} else if (matches(argv[1], "-force") == 0) {
++force;
- } else if (matches(argv[1], "-batch") == 0) {
+ } else if (matches(argv[1], "-batch") == 0) {
argc--; argv++;
if (argc <= 1)
usage();
NEXT_ARG();
if (netns_switch(argv[1]))
return -1;
+ } else if (matches(argv[1], "-names") == 0 ||
+ matches(argv[1], "-nm") == 0) {
+ use_names = true;
+ } else if (matches(argv[1], "-cf") == 0 ||
+ matches(argv[1], "-conf") == 0) {
+ NEXT_ARG();
+ conf_file = argv[1];
} else {
fprintf(stderr, "Option \"%s\" is unknown, try \"tc -help\".\n", argv[1]);
return -1;
exit(1);
}
+ if (use_names && cls_names_init(conf_file)) {
+ ret = -1;
+ goto Exit;
+ }
+
ret = do_cmd(argc-1, argv+1);
+Exit:
rtnl_close(&rth);
+ if (use_names)
+ cls_names_uninit();
+
return ret;
}
extern int check_size_table_opts(struct tc_sizespec *s);
extern int show_graph;
+extern bool use_names;
#include <math.h>
#include "utils.h"
+#include "names.h"
#include "tc_util.h"
+#include "tc_common.h"
#ifndef LIBDIR
#define LIBDIR "/usr/lib"
#endif
+static struct db_names *cls_names = NULL;
+
+#define NAMES_DB "/etc/iproute2/cls_names"
+
+int cls_names_init(char *path)
+{
+ cls_names = db_names_alloc(path ?: NAMES_DB);
+ if (!cls_names) {
+ fprintf(stderr, "Error while opening class names file\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+void cls_names_uninit(void)
+{
+ db_names_free(cls_names);
+}
+
const char *get_tc_lib(void)
{
const char *lib_dir;
int print_tc_classid(char *buf, int len, __u32 h)
{
+ char handle[40] = {};
+
if (h == TC_H_ROOT)
- sprintf(buf, "root");
+ sprintf(handle, "root");
else if (h == TC_H_UNSPEC)
- snprintf(buf, len, "none");
+ snprintf(handle, len, "none");
else if (TC_H_MAJ(h) == 0)
- snprintf(buf, len, ":%x", TC_H_MIN(h));
+ snprintf(handle, len, ":%x", TC_H_MIN(h));
else if (TC_H_MIN(h) == 0)
- snprintf(buf, len, "%x:", TC_H_MAJ(h)>>16);
+ snprintf(handle, len, "%x:", TC_H_MAJ(h) >> 16);
else
- snprintf(buf, len, "%x:%x", TC_H_MAJ(h)>>16, TC_H_MIN(h));
+ snprintf(handle, len, "%x:%x", TC_H_MAJ(h) >> 16, TC_H_MIN(h));
+
+ if (use_names) {
+ char clname[IDNAME_MAX] = {};
+
+ if (id_to_name(cls_names, h, clname))
+ snprintf(buf, len, "%s#%s", clname, handle);
+ else
+ snprintf(buf, len, "%s", handle);
+ } else {
+ snprintf(buf, len, "%s", handle);
+ }
+
return 0;
}
-char * sprint_tc_classid(__u32 h, char *buf)
+char *sprint_tc_classid(__u32 h, char *buf)
{
if (print_tc_classid(buf, SPRINT_BSIZE-1, h))
strcpy(buf, "???");
extern void print_tm(FILE *f, const struct tcf_t *tm);
extern int prio_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt);
+extern int cls_names_init(char *path);
+extern void cls_names_uninit(void);
+
#endif