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:
parent
fa89403149
commit
757592ec1b
13 changed files with 535 additions and 113 deletions
|
@ -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:
|
||||
|
|
|
@ -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
36
etc/classid
Normal 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:
|
||||
#
|
|
@ -28,6 +28,7 @@
|
|||
#include <inttypes.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <search.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
|
|
|
@ -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 *);
|
||||
|
||||
|
|
|
@ -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
357
lib/route/classid.c
Normal 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));
|
||||
}
|
||||
|
||||
/** @} */
|
108
lib/route/tc.c
108
lib/route/tc.c
|
@ -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
3
man/Makefile.am
Normal file
|
@ -0,0 +1,3 @@
|
|||
# -*- Makefile -*-
|
||||
|
||||
dist_man8_MANS = nl-classid-lookup.8
|
48
man/nl-classid-lookup.8
Normal file
48
man/nl-classid-lookup.8
Normal 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
1
src/.gitignore
vendored
|
@ -29,3 +29,4 @@ nl-rule-list
|
|||
nl-tctree-list
|
||||
nl-util-addr
|
||||
nf-queue
|
||||
nl-classid-lookup
|
||||
|
|
|
@ -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
79
src/nl-classid-lookup.c
Normal 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;
|
||||
}
|
Loading…
Add table
Reference in a new issue