dect
/
libnl
Archived
13
0
Fork 0

classid database

A database to resolve qdisc/class names to classid values and vice versa.
The function rtnl_tc_handle2str() and rtnl_tc_str2handle() will resolve
names automatically.

A CLI based tool nl-classid-lookup is provided to integrate the database
into existing iproute2 scripts.
This commit is contained in:
Thomas Graf 2010-10-19 16:31:23 +02:00
parent fa89403149
commit 757592ec1b
13 changed files with 535 additions and 113 deletions

View File

@ -8,12 +8,12 @@ if ENABLE_CLI
OPT_DIRS += src
endif
SUBDIRS = include lib doc $(OPT_DIRS)
SUBDIRS = include lib doc man $(OPT_DIRS)
pkgconfig_DATA = libnl-2.1.pc
sysconfdir = @sysconfdir@/libnl
sysconf_DATA = etc/pktloc
sysconf_DATA = etc/pktloc etc/classid
.PHONY: cscope
cscope:

View File

@ -37,6 +37,6 @@ AM_CONDITIONAL([ENABLE_CLI], [test "$enable_cli" = "yes"])
AC_CHECK_LIB([m], [pow], [], AC_MSG_ERROR([libm is required]))
AC_CONFIG_FILES([Makefile doc/Doxyfile doc/Makefile lib/Makefile
include/Makefile src/Makefile src/lib/Makefile \
include/Makefile src/Makefile src/lib/Makefile man/Makefile
libnl-2.1.pc include/netlink/version.h])
AC_OUTPUT

36
etc/classid Normal file
View File

@ -0,0 +1,36 @@
###############################################################################
#
# ClassID <-> Name Translation Table
#
# This file can be used to assign names to classids for easier reference
# in all libnl tools.
#
# Format:
# <MAJ:> <NAME> # qdisc definition
# <MAJ:MIN> <NAME> # class deifnition
# <NAME:MIN> <NAME> # class definition referencing an
# existing qdisc definition.
#
# Example:
# 1: top # top -> 1:0
# top:1 interactive # interactive -> 1:1
# top:2 www # www -> 1:2
# top:3 bulk # bulk -> 1:3
# 2:1 test_class # test_class -> 2:1
#
# Illegal Example:
# 30:1 classD
# classD:2 invalidClass # classD refers to a class, not a qdisc
#
###############################################################################
# <CLASSID> <NAME>
# Reserved default classids
0:0 none
ffff:ffff root
ffff:fff1 ingress
#
# List your classid definitions below:
#

View File

@ -28,6 +28,7 @@
#include <inttypes.h>
#include <assert.h>
#include <limits.h>
#include <search.h>
#include <arpa/inet.h>
#include <netdb.h>

View File

@ -53,6 +53,7 @@ extern int rtnl_tc_build_rate_table(uint32_t *, uint8_t, uint8_t, int, int);
/* TC Handle Translations */
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 *);

View File

@ -39,7 +39,7 @@ libnl_route_la_SOURCES = \
route/cls.c route/cls_api.c route/cls_obj.c route/link.c \
route/neigh.c route/neightbl.c route/nexthop.c route/qdisc.c \
route/qdisc_api.c route/qdisc_obj.c route/route.c route/route_obj.c \
route/route_utils.c route/rtnl.c route/rule.c route/tc.c \
route/route_utils.c route/rtnl.c route/rule.c route/tc.c route/classid.c \
\
route/cls/fw.c route/cls/police.c route/cls/u32.c \
\

357
lib/route/classid.c Normal file
View File

@ -0,0 +1,357 @@
/*
* lib/route/classid.c ClassID Management
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2010 Thomas Graf <tgraf@suug.ch>
*/
/**
* @ingroup tc
* @defgroup classid ClassID Management
* @{
*/
#include <netlink-local.h>
#include <netlink-tc.h>
#include <netlink/netlink.h>
#include <netlink/utils.h>
#include <netlink/route/tc.h>
struct classid_map
{
uint32_t classid;
char * name;
struct nl_list_head name_list;
};
#define CLASSID_NAME_HT_SIZ 256
static struct nl_list_head tbl_name[CLASSID_NAME_HT_SIZ];
static void *id_root = NULL;
static int compare_id(const void *pa, const void *pb)
{
const struct classid_map *ma = pa;
const struct classid_map *mb = pb;
if (ma->classid < mb->classid)
return -1;
if (ma->classid > mb->classid)
return 1;
return 0;
}
/* djb2 */
static unsigned int classid_tbl_hash(const char *str)
{
unsigned long hash = 5381;
int c;
while ((c = *str++))
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
return hash % CLASSID_NAME_HT_SIZ;
}
static int classid_lookup(const char *name, uint32_t *result)
{
struct classid_map *map;
int n = classid_tbl_hash(name);
nl_list_for_each_entry(map, &tbl_name[n], name_list) {
if (!strcasecmp(map->name, name)) {
*result = map->classid;
return 0;
}
}
return -NLE_OBJ_NOTFOUND;
}
/**
* @name Traffic Control Handle Translations
* @{
*/
/**
* Convert a traffic control handle to a character string (Reentrant).
* @arg handle traffic control handle
* @arg buf destination buffer
* @arg len buffer length
*
* Converts a tarffic control handle to a character string in the
* form of \c MAJ:MIN and stores it in the specified destination buffer.
*
* @return The destination buffer or the type encoded in hexidecimal
* form if no match was found.
*/
char * rtnl_tc_handle2str(uint32_t handle, char *buf, size_t len)
{
if (TC_H_ROOT == handle)
snprintf(buf, len, "root");
else if (TC_H_UNSPEC == handle)
snprintf(buf, len, "none");
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);
else if (0 == TC_H_MAJ(handle))
snprintf(buf, len, ":%02x", TC_H_MIN(handle));
else if (0 == TC_H_MIN(handle))
snprintf(buf, len, "%02x:", TC_H_MAJ(handle) >> 16);
else
snprintf(buf, len, "%02x:%02x",
TC_H_MAJ(handle) >> 16, TC_H_MIN(handle));
}
return buf;
}
/**
* Convert a charactering strint to a traffic control handle
* @arg str traffic control handle as character string
* @arg res destination buffer
*
* Converts the provided character string specifying a traffic
* control handle to the corresponding numeric value.
*
* The handle must be provided in one of the following formats:
* - NAME
* - root
* - none
* - MAJ:
* - :MIN
* - NAME:MIN
* - MAJ:MIN
* - MAJMIN
*
* @return 0 on success or a negative error code
*/
int rtnl_tc_str2handle(const char *str, uint32_t *res)
{
char *colon, *end;
uint32_t h, err;
if (!strcasecmp(str, "root")) {
*res = TC_H_ROOT;
return 0;
}
if (!strcasecmp(str, "none")) {
*res = TC_H_UNSPEC;
return 0;
}
h = strtoul(str, &colon, 16);
/* MAJ is not a number */
if (colon == str) {
if (*colon == ':') {
/* :YYYY */
h = 0;
} else {
size_t len;
char name[64] = { 0 };
if (!(colon = strpbrk(str, ":"))) {
/* NAME */
return classid_lookup(str, res);
} else {
/* NAME:YYYY */
len = colon - str;
if (len >= sizeof(name))
return -NLE_INVAL;
memcpy(name, str, len);
if ((err = classid_lookup(name, &h)) < 0)
return err;
/* Name must point to a qdisc alias */
if (TC_H_MIN(h))
return -NLE_INVAL;
/* NAME: is not allowed */
if (colon[1] == '\0')
return -NLE_INVAL;
goto update;
}
}
}
if (':' == *colon) {
/* check if we would lose bits */
if (TC_H_MAJ(h))
return -NLE_RANGE;
h <<= 16;
if ('\0' == colon[1]) {
/* XXXX: */
*res = h;
} else {
/* XXXX:YYYY */
uint32_t l;
update:
l = strtoul(colon+1, &end, 16);
/* check if we overlap with major part */
if (TC_H_MAJ(l))
return -NLE_RANGE;
if ('\0' != *end)
return -NLE_INVAL;
*res = (h | l);
}
} else if ('\0' == *colon) {
/* XXXXYYYY */
*res = h;
} else
return -NLE_INVAL;
return 0;
}
static void free_nothing(void *arg)
{
}
static void clear_hashtable(void)
{
int i;
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_init_list_head(&tbl_name[i]);
}
if (id_root) {
tdestroy(&id_root, &free_nothing);
id_root = NULL;
}
}
/**
* (Re-)read classid file
*
* Rereads the contents of the classid file (typically found at the location
* /etc/libnl/classid) and refreshes the classid maps.
*
* @return 0 on success or a negative error code.
*/
int rtnl_tc_read_classid_file(void)
{
static time_t last_read;
struct stat st = {0};
char buf[256], *path;
FILE *fd;
int err;
asprintf(&path, "%s/classid", SYSCONFDIR);
/* if stat fails, just (re-)read the file */
if (stat(path, &st) == 0) {
/* Don't re-read file if file is unchanged */
if (last_read == st.st_mtime) {
err = 0;
goto errout;
}
}
if (!(fd = fopen(path, "r"))) {
err = -nl_syserr2nlerr(errno);
goto errout;
}
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')
continue;
/* token 1 */
if (!(tok = strtok_r(buf, " \t", &ptr))) {
err = -NLE_INVAL;
goto errout_close;
}
if ((err = rtnl_tc_str2handle(tok, &classid)) < 0)
goto errout_close;
if (!(tok = strtok_r(NULL, " \t\n\r#", &ptr))) {
err = -NLE_INVAL;
goto errout_close;
}
if (!(map = calloc(1, sizeof(*map)))) {
err = -NLE_NOMEM;
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;
last_read = st.st_mtime;
errout_close:
fclose(fd);
errout:
free(path);
return err;
}
/** @} */
static void __init classid_init(void)
{
int err, i;
for (i = 0; i < CLASSID_NAME_HT_SIZ; i++)
nl_init_list_head(&tbl_name[i]);
if ((err = rtnl_tc_read_classid_file()) < 0)
fprintf(stderr, "Failed to read classid file: %s\n", nl_geterror(err));
}
/** @} */

View File

@ -465,113 +465,5 @@ int rtnl_tc_build_rate_table(uint32_t *dst, uint8_t mpu, uint8_t overhead,
/** @} */
/**
* @name Traffic Control Handle Translations
* @{
*/
/**
* Convert a traffic control handle to a character string (Reentrant).
* @arg handle traffic control handle
* @arg buf destination buffer
* @arg len buffer length
*
* Converts a tarffic control handle to a character string in the
* form of \c MAJ:MIN and stores it in the specified destination buffer.
*
* @return The destination buffer or the type encoded in hexidecimal
* form if no match was found.
*/
char * rtnl_tc_handle2str(uint32_t handle, char *buf, size_t len)
{
if (TC_H_ROOT == handle)
snprintf(buf, len, "root");
else if (TC_H_UNSPEC == handle)
snprintf(buf, len, "none");
else if (0 == TC_H_MAJ(handle))
snprintf(buf, len, ":%02x", TC_H_MIN(handle));
else if (0 == TC_H_MIN(handle))
snprintf(buf, len, "%02x:", TC_H_MAJ(handle) >> 16);
else
snprintf(buf, len, "%02x:%02x",
TC_H_MAJ(handle) >> 16, TC_H_MIN(handle));
return buf;
}
/**
* Convert a charactering strint to a traffic control handle
* @arg name traffic control handle as character string
* @arg res destination buffer
*
* Converts the provided character string specifying a traffic
* control handle to the corresponding numeric value.
*
* The handle must be provided in one of the following formats:
* - root
* - none
* - XXXX:
* - :YYYY
* - XXXX:YYYY
* - XXXXYYYY
*
* @return 0 on success or a negative error code
*/
int rtnl_tc_str2handle(const char *name, uint32_t *res)
{
char *colon, *end;
uint32_t h;
if (!strcasecmp(name, "root")) {
*res = TC_H_ROOT;
return 0;
}
if (!strcasecmp(name, "none")) {
*res = TC_H_UNSPEC;
return 0;
}
h = strtoul(name, &colon, 16);
if (colon == name) {
/* :YYYY */
h = 0;
if (':' != *colon)
return -NLE_INVAL;
}
if (':' == *colon) {
/* check if we would lose bits */
if (TC_H_MAJ(h))
return -NLE_RANGE;
h <<= 16;
if ('\0' == colon[1]) {
/* XXXX: */
*res = h;
} else {
/* XXXX:YYYY */
uint32_t l = strtoul(colon+1, &end, 16);
/* check if we overlap with major part */
if (TC_H_MAJ(l))
return -NLE_RANGE;
if ('\0' != *end)
return -NLE_INVAL;
*res = (h | l);
}
} else if ('\0' == *colon) {
/* XXXXYYYY */
*res = h;
} else
return -NLE_INVAL;
return 0;
}
/** @} */
/** @} */

3
man/Makefile.am Normal file
View File

@ -0,0 +1,3 @@
# -*- Makefile -*-
dist_man8_MANS = nl-classid-lookup.8

48
man/nl-classid-lookup.8 Normal file
View File

@ -0,0 +1,48 @@
.TH nl\-classid\-lookup 8 "19 October 2010" "libnl"
.LO 1
.SH NAME
nl\-classid\-lookup - Lookup classid definitions
.SH SYNOPSIS
.B nl\-classid\-lookup
.RB [ \-hv ]
.RB [ \-r ]
.I name
.SH DESCRIPTION
.PP
nl\-classid\-lookup searches the classid database for a matching entry. It is used
to resolve qdisc/class names to classid values and vice versa.
.SH OPTIONS
.TP
.BR \-\^h " or " \-\-help
Print help text to console and exit.
.TP
.BR \-\^v " or " \-\-version
Print versioning information to console and exit.
.TP
.BR \-\^r " or " \-\-reverse
Do a reverse lookup. Lookup a classid and print its name.
.SH USAGE
.PP
Resolve the qdisc/class name "interactive":
.PP
.RS
# nl\-classid\-lookup interactive
.RE
.PP
Lookup the name of classid 1:2:
.PP
.RS
# nl\-classid\-lookup -r 1:2
.RE
.SH FILES
.PP
/etc/libnl/classid
.SH AUTHOR
.PP
Thomas Graf is the original author and current maintainer of libnl and
libnl tools. Many people have contributed to it since.

1
src/.gitignore vendored
View File

@ -29,3 +29,4 @@ nl-rule-list
nl-tctree-list
nl-util-addr
nf-queue
nl-classid-lookup

View File

@ -6,7 +6,8 @@ AM_CPPFLAGS = -Wall -I${top_srcdir}/include -I${top_builddir}/include -D_GNU_SO
AM_LDFLAGS = -L${top_builddir}/lib -L${top_builddir}/src/lib -lnl-cli
sbin_PROGRAMS = \
nl-qdisc-add
nl-qdisc-add \
nl-classid-lookup
noinst_PROGRAMS = \
genl-ctrl-list \
@ -104,3 +105,6 @@ nl_util_addr_LDADD = -lnl-route
nl_pktloc_lookup_SOURCES = nl-pktloc-lookup.c
nl_pktloc_lookup_LDADD = -lnl-route
nl_classid_lookup_SOURCES = nl-classid-lookup.c
nl_classid_lookup_LDADD = -lnl-route

79
src/nl-classid-lookup.c Normal file
View File

@ -0,0 +1,79 @@
/*
* src/nl-classid-lookup.c Lookup classid
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2010 Thomas Graf <tgraf@suug.ch>
*/
#include <netlink/cli/utils.h>
static void print_usage(void)
{
printf(
"Usage: nl-classid-lookup [OPTIONS]... NAME\n"
"\n"
"OPTIONS\n"
" -h, --help Show this help text.\n"
" -v, --version Show versioning information.\n"
" -r, --reverse Do a reverse lookup, i.e. classid to name.\n"
"\n"
"EXAMPLE\n"
" $ nl-classid-lookup low_latency\n"
" $ nl-classid-lookup -r 1:12\n"
"\n"
);
exit(0);
}
int main(int argc, char *argv[])
{
uint32_t classid;
char *name;
int err, reverse = 0;
for (;;) {
int c, optidx = 0;
static struct option long_opts[] = {
{ "help", 0, 0, 'h' },
{ "version", 0, 0, 'v' },
{ "reverse", 0, 0, 'r' },
{ 0, 0, 0, 0 }
};
c = getopt_long(argc, argv, "hvr", long_opts, &optidx);
if (c == -1)
break;
switch (c) {
case 'h': print_usage(); break;
case 'v': nl_cli_print_version(); break;
case 'r': reverse = 1; break;
}
}
if (optind >= argc)
print_usage();
name = argv[optind++];
/*
* We use rtnl_tc_str2handle() even while doing a reverse lookup. This
* allows for name -> name lookups. This is intentional, it does not
* do any harm and avoids duplicating a lot of code.
*/
if ((err = rtnl_tc_str2handle(name, &classid)) < 0)
nl_cli_fatal(err, "Unable to lookup classid \"%s\": %s",
name, nl_geterror(err));
if (reverse) {
char buf[64];
printf("%s\n", rtnl_tc_handle2str(classid, buf, sizeof(buf)));
} else
printf("%x:%x\n", TC_H_MAJ(classid) >> 16, TC_H_MIN(classid));
return 0;
}