dect
/
libnl
Archived
13
0
Fork 0

- Reworked the classifier interface.

- Added initial ematch support
- Added support for the basic classifier
- Added support for the cgroup classifier
This commit is contained in:
Thomas Graf 2009-09-02 18:31:14 +02:00
parent 7d249fc2e1
commit ef858fb492
31 changed files with 2047 additions and 201 deletions

View File

@ -1,6 +1,7 @@
#ifndef __LINUX_PKT_CLS_H
#define __LINUX_PKT_CLS_H
#include <linux/types.h>
#include <linux/pkt_sched.h>
/* I think i could have done better macros ; for now this is stolen from
@ -201,8 +202,8 @@ enum
struct tc_u32_key
{
__u32 mask;
__u32 val;
__be32 mask;
__be32 val;
int off;
int offmask;
};
@ -213,12 +214,12 @@ struct tc_u32_sel
unsigned char offshift;
unsigned char nkeys;
__u16 offmask;
__be16 offmask;
__u16 off;
short offoff;
short hoff;
__u32 hmask;
__be32 hmask;
struct tc_u32_key keys[0];
};
@ -328,6 +329,58 @@ enum
#define TCA_TCINDEX_MAX (__TCA_TCINDEX_MAX - 1)
/* Flow filter */
enum
{
FLOW_KEY_SRC,
FLOW_KEY_DST,
FLOW_KEY_PROTO,
FLOW_KEY_PROTO_SRC,
FLOW_KEY_PROTO_DST,
FLOW_KEY_IIF,
FLOW_KEY_PRIORITY,
FLOW_KEY_MARK,
FLOW_KEY_NFCT,
FLOW_KEY_NFCT_SRC,
FLOW_KEY_NFCT_DST,
FLOW_KEY_NFCT_PROTO_SRC,
FLOW_KEY_NFCT_PROTO_DST,
FLOW_KEY_RTCLASSID,
FLOW_KEY_SKUID,
FLOW_KEY_SKGID,
FLOW_KEY_VLAN_TAG,
__FLOW_KEY_MAX,
};
#define FLOW_KEY_MAX (__FLOW_KEY_MAX - 1)
enum
{
FLOW_MODE_MAP,
FLOW_MODE_HASH,
};
enum
{
TCA_FLOW_UNSPEC,
TCA_FLOW_KEYS,
TCA_FLOW_MODE,
TCA_FLOW_BASECLASS,
TCA_FLOW_RSHIFT,
TCA_FLOW_ADDEND,
TCA_FLOW_MASK,
TCA_FLOW_XOR,
TCA_FLOW_DIVISOR,
TCA_FLOW_ACT,
TCA_FLOW_POLICE,
TCA_FLOW_EMATCHES,
TCA_FLOW_PERTURB,
__TCA_FLOW_MAX
};
#define TCA_FLOW_MAX (__TCA_FLOW_MAX - 1)
/* Basic filter */
enum
@ -342,6 +395,20 @@ enum
#define TCA_BASIC_MAX (__TCA_BASIC_MAX - 1)
/* Cgroup classifier */
enum
{
TCA_CGROUP_UNSPEC,
TCA_CGROUP_ACT,
TCA_CGROUP_POLICE,
TCA_CGROUP_EMATCHES,
__TCA_CGROUP_MAX,
};
#define TCA_CGROUP_MAX (__TCA_CGROUP_MAX - 1)
/* Extended Matches */
struct tcf_ematch_tree_hdr
@ -409,7 +476,8 @@ enum
#define TCF_EM_U32 3
#define TCF_EM_META 4
#define TCF_EM_TEXT 5
#define TCF_EM_MAX 5
#define TCF_EM_VLAN 6
#define TCF_EM_MAX 6
enum
{

View File

@ -453,7 +453,7 @@ struct rtnl_tstats
struct nl_data * pre ##_opts; \
uint64_t pre ##_stats[RTNL_TC_STATS_MAX+1]; \
struct nl_data * pre ##_xstats; \
void * pre ##_subdata; \
struct nl_data * pre ##_subdata; \
struct rtnl_tca
@ -476,8 +476,8 @@ struct rtnl_class
struct rtnl_cls
{
NL_TCA_GENERIC(c);
uint16_t c_prio;
uint16_t c_protocol;
uint16_t c_prio;
uint16_t c_protocol;
struct rtnl_cls_ops *c_ops;
};
@ -495,6 +495,12 @@ struct rtnl_u32
int cu_mask;
};
struct rtnl_cgroup
{
struct rtnl_ematch_tree *cg_ematch;
int cg_mask;
};
struct rtnl_fw
{
uint32_t cf_classid;
@ -504,6 +510,26 @@ struct rtnl_fw
int cf_mask;
};
struct rtnl_ematch
{
uint16_t e_id;
uint16_t e_kind;
uint16_t e_flags;
struct nl_list_head e_childs;
struct nl_list_head e_list;
struct rtnl_ematch_ops *e_ops;
char e_data[0];
};
struct rtnl_ematch_tree
{
uint16_t et_progid;
struct nl_list_head et_list;
};
struct rtnl_dsmark_qdisc
{
uint16_t qdm_indices;

View File

@ -232,6 +232,16 @@ extern int nla_parse_nested(struct nlattr **, int, struct nlattr *,
NLA_PUT(msg, attrtype, nl_addr_get_len(addr), \
nl_addr_get_binary_addr(addr))
/**
* Add abstract data attribute to netlink message.
* @arg msg Netlink message.
* @arg attrtype Attribute type.
* @arg data Abstract data object.
*/
#define NLA_PUT_DATA(msg, attrtype, data) \
NLA_PUT(msg, attrtype, nl_data_get_size(data), \
nl_data_get(data))
/** @} */
/**

View File

@ -18,6 +18,11 @@ struct nl_list_head
struct nl_list_head * prev;
};
static inline void NL_INIT_LIST_HEAD(struct nl_list_head *list)
{
list->next = list;
list->prev = list;
}
static inline void __nl_list_add(struct nl_list_head *obj,
struct nl_list_head *prev,

View File

@ -6,7 +6,7 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch>
*/
#ifndef NETLINK_CLASS_MODULES_H_
@ -25,10 +25,16 @@ extern "C" {
struct rtnl_cls_ops
{
/**
* Kind/Name of classifier
* Name of classifier module
*/
char co_kind[32];
/**
* Size of private classifier data
*/
size_t co_size;
/**
* Dump callbacks
*/
@ -37,7 +43,7 @@ struct rtnl_cls_ops
/**
* Must return the contents supposed to be in TCA_OPTIONS
*/
struct nl_msg *(*co_get_opts)(struct rtnl_cls *);
int (*co_get_opts)(struct rtnl_cls *, struct nl_msg *);
/**
* TCA_OPTIONS message parser

View File

@ -6,7 +6,7 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch>
*/
#ifndef NETLINK_CLASSIFIER_H_
@ -40,8 +40,10 @@ extern int rtnl_cls_build_delete_request(struct rtnl_cls *, int,
extern int rtnl_cls_delete(struct nl_sock *, struct rtnl_cls *, int);
extern void rtnl_cls_set_ifindex(struct rtnl_cls *, int);
extern int rtnl_cls_get_ifindex(struct rtnl_cls *);
extern void rtnl_cls_set_handle(struct rtnl_cls *, uint32_t);
extern void rtnl_cls_set_parent(struct rtnl_cls *, uint32_t);
extern uint32_t rtnl_cls_get_parent(struct rtnl_cls *);
extern int rtnl_cls_set_kind(struct rtnl_cls *, const char *);
extern struct rtnl_cls_ops *rtnl_cls_get_ops(struct rtnl_cls *);
@ -51,6 +53,8 @@ extern uint16_t rtnl_cls_get_prio(struct rtnl_cls *);
extern void rtnl_cls_set_protocol(struct rtnl_cls *, uint16_t);
extern uint16_t rtnl_cls_get_protocol(struct rtnl_cls *);
extern void *rtnl_cls_data(struct rtnl_cls *);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,33 @@
/*
* netlink/route/cls/basic.h Basic Classifier
*
* 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) 2008-2009 Thomas Graf <tgraf@suug.ch>
*/
#ifndef NETLINK_BASIC_H_
#define NETLINK_BASIC_H_
#include <netlink/netlink.h>
#ifdef __cplusplus
extern "C" {
#endif
extern struct rtnl_cls_ops *rtnl_basic_get_ops(void);
extern int rtnl_basic_set_classid(struct rtnl_cls *, uint32_t);
extern uint32_t rtnl_basic_get_classid(struct rtnl_cls *);
extern int rtnl_basic_set_ematch(struct rtnl_cls *,
struct rtnl_ematch_tree *);
extern struct rtnl_ematch_tree *
rtnl_basic_get_ematch(struct rtnl_cls *);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,31 @@
/*
* netlink/route/cls/cgroup.h Control Groups Classifier
*
* 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) 2009 Thomas Graf <tgraf@suug.ch>
*/
#ifndef NETLINK_CLS_CGROUP_H_
#define NETLINK_CLS_CGROUP_H_
#include <netlink/netlink.h>
#include <netlink/cache.h>
#ifdef __cplusplus
extern "C" {
#endif
extern int rtnl_cgroup_set_ematch(struct rtnl_cls *,
struct rtnl_ematch_tree *);
extern struct rtnl_ematch_tree *
rtnl_cgroup_get_ematch(struct rtnl_cls *);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,73 @@
/*
* netlink/route/cls/ematch.h Extended Matches
*
* 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) 2008 Thomas Graf <tgraf@suug.ch>
*/
#ifndef NETLINK_CLS_EMATCH_H_
#define NETLINK_CLS_EMATCH_H_
#include <netlink/netlink.h>
#include <netlink/route/classifier.h>
#include <linux/pkt_cls.h>
#ifdef __cplusplus
extern "C" {
#endif
struct rtnl_ematch;
struct rtnl_ematch_tree;
struct rtnl_ematch_ops
{
int eo_kind;
const char * eo_name;
size_t eo_datalen;
int (*eo_parse)(struct rtnl_ematch *,
void *, size_t);
void (*eo_dump)(struct rtnl_ematch *,
struct nl_dump_params *);
struct nl_list_head eo_list;
};
extern int rtnl_ematch_register(struct rtnl_ematch_ops *);
extern int rtnl_ematch_unregister(struct rtnl_ematch_ops *);
extern struct rtnl_ematch_ops *
rtnl_ematch_lookup_ops(int);
extern struct rtnl_ematch_ops *
rtnl_ematch_lookup_ops_name(const char *);
extern struct rtnl_ematch *
rtnl_ematch_alloc(struct rtnl_ematch_ops *);
extern void rtnl_ematch_add_child(struct rtnl_ematch *,
struct rtnl_ematch *);
extern void rtnl_ematch_unlink(struct rtnl_ematch *);
extern void rtnl_ematch_free(struct rtnl_ematch *);
extern void * rtnl_ematch_data(struct rtnl_ematch *);
extern void rtnl_ematch_set_flags(struct rtnl_ematch *, uint16_t);
extern void rtnl_ematch_unset_flags(struct rtnl_ematch *, uint16_t);
extern uint16_t rtnl_ematch_get_flags(struct rtnl_ematch *);
extern struct rtnl_ematch_tree *
rtnl_ematch_tree_alloc(uint16_t);
extern void rtnl_ematch_tree_free(struct rtnl_ematch_tree *);
extern int rtnl_ematch_parse(struct nlattr *, struct rtnl_ematch_tree **);
extern void rtnl_ematch_tree_add_tail(struct rtnl_ematch_tree *,
struct rtnl_ematch *);
extern void rtnl_ematch_tree_dump(struct rtnl_ematch_tree *,
struct nl_dump_params *);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,31 @@
/*
* netlink/route/cls/ematch/cmp.h Simple Comparison
*
* 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) 2008 Thomas Graf <tgraf@suug.ch>
*/
#ifndef NETLINK_CLS_EMATCH_CMP_H_
#define NETLINK_CLS_EMATCH_CMP_H_
#include <netlink/netlink.h>
#include <netlink/route/cls/ematch.h>
#ifdef __cplusplus
extern "C" {
#endif
extern void rtnl_ematch_cmp_set(struct rtnl_ematch *,
struct tcf_em_cmp *);
extern struct tcf_em_cmp *
rtnl_ematch_cmp_get(struct rtnl_ematch *);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -18,6 +18,7 @@ CORE_OBJ := $(CORE_C:%.c=%.o)
ROUTE_C := $(wildcard route/*.c)
ROUTE_C += $(wildcard route/cls/*.c)
ROUTE_C += $(wildcard route/cls/ematch/*.c)
ROUTE_C += $(wildcard route/sch/*.c)
ROUTE_C += $(wildcard route/link/*.c)
ROUTE_C += $(wildcard fib_lookup/*.c)

View File

@ -6,7 +6,7 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch>
*/
/**
@ -38,9 +38,9 @@ static struct nl_cache_ops rtnl_cls_ops;
static int cls_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
struct nlmsghdr *nlh, struct nl_parser_param *pp)
{
int err;
struct rtnl_cls *cls;
struct rtnl_cls_ops *cops;
struct rtnl_cls *cls;
int err;
cls = rtnl_cls_alloc();
if (!cls) {
@ -57,11 +57,8 @@ static int cls_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
cls->c_protocol = ntohs(TC_H_MIN(cls->c_info));
cops = rtnl_cls_lookup_ops(cls);
if (cops && cops->co_msg_parser) {
err = cops->co_msg_parser(cls);
if (err < 0)
goto errout_free;
}
if (cops && cops->co_msg_parser && (err = cops->co_msg_parser(cls)) < 0)
goto errout_free;
err = pp->pp_cb((struct nl_object *) cls, pp);
errout_free:
@ -97,19 +94,23 @@ static int cls_build(struct rtnl_cls *cls, int type, int flags,
tchdr = nlmsg_data(nlmsg_hdr(*result));
prio = rtnl_cls_get_prio(cls);
proto = rtnl_cls_get_protocol(cls);
tchdr->tcm_info = TC_H_MAKE(prio << 16, htons(proto)),
tchdr->tcm_info = TC_H_MAKE(prio << 16, htons(proto));
cops = rtnl_cls_lookup_ops(cls);
if (cops && cops->co_get_opts) {
struct nl_msg *opts;
opts = cops->co_get_opts(cls);
if (opts) {
err = nla_put_nested(*result, TCA_OPTIONS, opts);
nlmsg_free(opts);
if (err < 0)
goto errout;
if (!(opts = nlmsg_alloc())) {
err = -NLE_NOMEM;
goto errout;
}
if (!(err = cops->co_get_opts(cls, opts)))
err = nla_put_nested(*result, TCA_OPTIONS, opts);
nlmsg_free(opts);
if (err < 0)
goto errout;
}
return 0;

211
lib/route/cls/basic.c Normal file
View File

@ -0,0 +1,211 @@
/*
* lib/route/cls/basic.c Basic Classifier
*
* 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) 2008-2009 Thomas Graf <tgraf@suug.ch>
*/
/**
* @ingroup cls
* @defgroup basic Basic Classifier
*
* @par Introduction
* The basic classifier is the simplest form of a classifier. It does
* not have any special classification capabilities, instead it can be
* used to classify exclusively based on extended matches or to
* create a "catch-all" filter.
*
* @{
*/
#include <netlink-local.h>
#include <netlink-tc.h>
#include <netlink/netlink.h>
#include <netlink/route/classifier.h>
#include <netlink/route/classifier-modules.h>
#include <netlink/route/cls/basic.h>
#include <netlink/route/cls/ematch.h>
struct rtnl_basic
{
uint32_t b_classid;
struct rtnl_ematch_tree * b_ematch;
int b_mask;
};
/** @cond SKIP */
#define BASIC_ATTR_CLASSID 0x001
#define BASIC_ATTR_EMATCH 0x002
/** @endcond */
static struct nla_policy basic_policy[TCA_FW_MAX+1] = {
[TCA_BASIC_CLASSID] = { .type = NLA_U32 },
[TCA_BASIC_EMATCHES] = { .type = NLA_NESTED },
[TCA_BASIC_ACT] = { .type = NLA_NESTED },
[TCA_BASIC_POLICE] = { .type = NLA_NESTED },
};
static int basic_clone(struct rtnl_cls *_dst, struct rtnl_cls *_src)
{
return -NLE_OPNOTSUPP;
}
static void basic_free_data(struct rtnl_cls *cls)
{
struct rtnl_basic *basic = rtnl_cls_data(cls);
rtnl_ematch_tree_free(basic->b_ematch);
}
static int basic_msg_parser(struct rtnl_cls *cls)
{
struct nlattr *tb[TCA_BASIC_MAX + 1];
struct rtnl_basic *basic = rtnl_cls_data(cls);
int err;
err = tca_parse(tb, TCA_BASIC_MAX, (struct rtnl_tca *) cls, basic_policy);
if (err < 0)
return err;
if (tb[TCA_BASIC_CLASSID]) {
basic->b_classid = nla_get_u32(tb[TCA_BASIC_CLASSID]);
basic->b_mask |= BASIC_ATTR_CLASSID;
}
if (tb[TCA_BASIC_EMATCHES]) {
if ((err = rtnl_ematch_parse(tb[TCA_BASIC_EMATCHES],
&basic->b_ematch)) < 0)
return err;
if (basic->b_ematch)
basic->b_mask |= BASIC_ATTR_EMATCH;
}
if (tb[TCA_BASIC_ACT]) {
/* XXX */
}
if (tb[TCA_BASIC_POLICE]) {
/* XXX */
}
return 0;
}
static void basic_dump_line(struct rtnl_cls *cls, struct nl_dump_params *p)
{
struct rtnl_basic *b = rtnl_cls_data(cls);
char buf[32];
if (b->b_mask & BASIC_ATTR_EMATCH)
nl_dump(p, " ematch");
else
nl_dump(p, " match-all");
if (b->b_mask & BASIC_ATTR_CLASSID)
nl_dump(p, " classify-to %s",
rtnl_tc_handle2str(b->b_classid, buf, sizeof(buf)));
}
static void basic_dump_details(struct rtnl_cls *cls, struct nl_dump_params *p)
{
struct rtnl_basic *b = rtnl_cls_data(cls);
if (b->b_mask & BASIC_ATTR_EMATCH) {
nl_dump(p, "\n");
nl_dump_line(p, " ematch ");
rtnl_ematch_tree_dump(b->b_ematch, p);
} else
nl_dump(p, "no options.\n");
}
static int basic_get_opts(struct rtnl_cls *cls, struct nl_msg *msg)
{
struct rtnl_basic *b = rtnl_cls_data(cls);
if (!(b->b_mask & BASIC_ATTR_CLASSID))
return -NLE_MISSING_ATTR;
NLA_PUT_U32(msg, TCA_BASIC_CLASSID, b->b_classid);
return 0;
nla_put_failure:
return -NLE_NOMEM;
}
/**
* @name Attribute Modifications
* @{
*/
int rtnl_basic_set_classid(struct rtnl_cls *cls, uint32_t classid)
{
struct rtnl_basic *b = rtnl_cls_data(cls);
b->b_classid = classid;
b->b_mask |= BASIC_ATTR_CLASSID;
return 0;
}
uint32_t rtnl_basic_get_classid(struct rtnl_cls *cls)
{
struct rtnl_basic *b = rtnl_cls_data(cls);
return b->b_classid;
}
int rtnl_basic_set_ematch(struct rtnl_cls *cls, struct rtnl_ematch_tree *tree)
{
struct rtnl_basic *b = rtnl_cls_data(cls);
if (b->b_ematch) {
rtnl_ematch_tree_free(b->b_ematch);
b->b_mask &= ~BASIC_ATTR_EMATCH;
}
b->b_ematch = tree;
if (tree)
b->b_mask |= BASIC_ATTR_EMATCH;
return 0;
}
struct rtnl_ematch_tree *rtnl_basic_get_ematch(struct rtnl_cls *cls)
{
struct rtnl_basic *b = rtnl_cls_data(cls);
return b->b_ematch;
}
/** @} */
static struct rtnl_cls_ops basic_ops = {
.co_kind = "basic",
.co_size = sizeof(struct rtnl_basic),
.co_msg_parser = basic_msg_parser,
.co_clone = basic_clone,
.co_free_data = basic_free_data,
.co_get_opts = basic_get_opts,
.co_dump = {
[NL_DUMP_LINE] = basic_dump_line,
[NL_DUMP_DETAILS] = basic_dump_details,
},
};
static void __init basic_init(void)
{
rtnl_cls_register(&basic_ops);
}
static void __exit basic_exit(void)
{
rtnl_cls_unregister(&basic_ops);
}
/** @} */

141
lib/route/cls/cgroup.c Normal file
View File

@ -0,0 +1,141 @@
/*
* lib/route/cls/cgroup.c Control Groups Classifier
*
* 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) 2009 Thomas Graf <tgraf@suug.ch>
*/
/**
* @ingroup cls_api
* @defgroup cgroup Control Groups Classifier
*
* @{
*/
#include <netlink-local.h>
#include <netlink-tc.h>
#include <netlink/netlink.h>
#include <netlink/attr.h>
#include <netlink/utils.h>
#include <netlink/route/classifier.h>
#include <netlink/route/classifier-modules.h>
#include <netlink/route/cls/cgroup.h>
#include <netlink/route/cls/ematch.h>
/** @cond SKIP */
#define CGROUP_ATTR_EMATCH 0x001
/** @endcond */
static struct nla_policy cgroup_policy[TCA_CGROUP_MAX+1] = {
[TCA_CGROUP_EMATCHES] = { .type = NLA_NESTED },
};
static void cgroup_free_data(struct rtnl_cls *cls)
{
struct rtnl_cgroup *cg = rtnl_cls_data(cls);
rtnl_ematch_tree_free(cg->cg_ematch);
}
static int cgroup_msg_parser(struct rtnl_cls *cls)
{
struct rtnl_cgroup *cg = rtnl_cls_data(cls);
struct nlattr *tb[TCA_CGROUP_MAX + 1];
int err;
err = tca_parse(tb, TCA_CGROUP_MAX, (struct rtnl_tca *) cls,
cgroup_policy);
if (err < 0)
return err;
if (tb[TCA_CGROUP_EMATCHES]) {
if ((err = rtnl_ematch_parse(tb[TCA_CGROUP_EMATCHES],
&cg->cg_ematch)) < 0)
return err;
cg->cg_mask |= CGROUP_ATTR_EMATCH;
}
#if 0
TODO:
TCA_CGROUP_ACT,
TCA_CGROUP_POLICE,
#endif
return 0;
}
static void cgroup_dump_line(struct rtnl_cls *cls, struct nl_dump_params *p)
{
struct rtnl_cgroup *cg = rtnl_cls_data(cls);
if (cg->cg_mask & CGROUP_ATTR_EMATCH)
nl_dump(p, " ematch");
else
nl_dump(p, " match-all");
}
static void cgroup_dump_details(struct rtnl_cls *cls, struct nl_dump_params *p)
{
struct rtnl_cgroup *cg = rtnl_cls_data(cls);
if (cg->cg_mask & CGROUP_ATTR_EMATCH) {
nl_dump(p, "\n");
nl_dump_line(p, " ematch ");
rtnl_ematch_tree_dump(cg->cg_ematch, p);
}
}
/**
* @name Attribute Modifications
* @{
*/
int rtnl_cgroup_set_ematch(struct rtnl_cls *cls, struct rtnl_ematch_tree *tree)
{
struct rtnl_cgroup *cg = rtnl_cls_data(cls);
if (cg->cg_ematch) {
rtnl_ematch_tree_free(cg->cg_ematch);
cg->cg_mask &= ~CGROUP_ATTR_EMATCH;
}
cg->cg_ematch = tree;
if (tree)
cg->cg_mask |= CGROUP_ATTR_EMATCH;
return 0;
}
struct rtnl_ematch_tree *rtnl_cgroup_get_ematch(struct rtnl_cls *cls)
{
struct rtnl_cgroup *cg = rtnl_cls_data(cls);
return cg->cg_ematch;
}
static struct rtnl_cls_ops cgroup_ops = {
.co_kind = "cgroup",
.co_size = sizeof(struct rtnl_cgroup),
.co_msg_parser = cgroup_msg_parser,
.co_free_data = cgroup_free_data,
.co_dump = {
[NL_DUMP_LINE] = cgroup_dump_line,
[NL_DUMP_DETAILS] = cgroup_dump_details,
},
};
static void __init cgroup_init(void)
{
rtnl_cls_register(&cgroup_ops);
}
static void __exit cgroup_exit(void)
{
rtnl_cls_unregister(&cgroup_ops);
}
/** @} */

410
lib/route/cls/ematch.c Normal file
View File

@ -0,0 +1,410 @@
/*
* lib/route/cls/ematch.c Extended Matches
*
* 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) 2008-2009 Thomas Graf <tgraf@suug.ch>
*/
/**
* @ingroup cls
* @defgroup ematch Extended Match
*
* @{
*/
#include <netlink-local.h>
#include <netlink-tc.h>
#include <netlink/netlink.h>
#include <netlink/route/classifier.h>
#include <netlink/route/classifier-modules.h>
#include <netlink/route/cls/ematch.h>
/**
* @name Module Registration
* @{
*/
static NL_LIST_HEAD(ematch_ops_list);
/**
* Register ematch module
* @arg ops Module operations.
*
* @return 0 on success or a negative error code.
*/
int rtnl_ematch_register(struct rtnl_ematch_ops *ops)
{
if (rtnl_ematch_lookup_ops(ops->eo_kind))
return -NLE_EXIST;
nl_list_add_tail(&ops->eo_list, &ematch_ops_list);
return 0;
}
/**
* Unregister ematch module
* @arg ops Module operations.
*
* @return 0 on success or a negative error code.
*/
int rtnl_ematch_unregister(struct rtnl_ematch_ops *ops)
{
struct rtnl_ematch_ops *o;
nl_list_for_each_entry(o, &ematch_ops_list, eo_list) {
if (ops->eo_kind == o->eo_kind) {
nl_list_del(&o->eo_list);
return 0;
}
}
return -NLE_OBJ_NOTFOUND;
}
/**
* Lookup ematch module by kind
* @arg kind Module kind.
*
* @return Module operations or NULL if not found.
*/
struct rtnl_ematch_ops *rtnl_ematch_lookup_ops(int kind)
{
struct rtnl_ematch_ops *ops;
nl_list_for_each_entry(ops, &ematch_ops_list, eo_list)
if (ops->eo_kind == kind)
return ops;
return NULL;
}
/**
* Lookup ematch module by name
* @arg name Name of ematch module.
*
* @return Module operations or NULL if not fuond.
*/
struct rtnl_ematch_ops *rtnl_ematch_lookup_ops_name(const char *name)
{
struct rtnl_ematch_ops *ops;
nl_list_for_each_entry(ops, &ematch_ops_list, eo_list)
if (!strcasecmp(ops->eo_name, name))
return ops;
return NULL;
}
/** @} */
/**
* @name Match
*/
struct rtnl_ematch *rtnl_ematch_alloc(struct rtnl_ematch_ops *ops)
{
struct rtnl_ematch *e;
size_t len = sizeof(*e) + (ops ? ops->eo_datalen : 0);
if (!(e = calloc(1, len)))
return NULL;
NL_INIT_LIST_HEAD(&e->e_list);
NL_INIT_LIST_HEAD(&e->e_childs);
if (ops) {
e->e_ops = ops;
e->e_kind = ops->eo_kind;
}
return e;
}
/**
* Add ematch to the end of the parent's list of children.
* @arg parent Parent ematch.
* @arg child Ematch to be added as new child of parent.
*/
void rtnl_ematch_add_child(struct rtnl_ematch *parent,
struct rtnl_ematch *child)
{
nl_list_add_tail(&child->e_list, &parent->e_childs);
}
/**
* Remove ematch from the list it is linked to.
* @arg ematch Ematch to be unlinked.
*/
void rtnl_ematch_unlink(struct rtnl_ematch *ematch)
{
nl_list_del(&ematch->e_list);
}
void rtnl_ematch_free(struct rtnl_ematch *ematch)
{
if (!ematch)
return;
free(ematch);
}
void rtnl_ematch_set_flags(struct rtnl_ematch *ematch, uint16_t flags)
{
ematch->e_flags |= flags;
}
void rtnl_ematch_unset_flags(struct rtnl_ematch *ematch, uint16_t flags)
{
ematch->e_flags &= ~flags;
}
uint16_t rtnl_ematch_get_flags(struct rtnl_ematch *ematch)
{
return ematch->e_flags;
}
void *rtnl_ematch_data(struct rtnl_ematch *ematch)
{
return ematch->e_data;
}
/** @} */
/**
* @name Tree
*/
struct rtnl_ematch_tree *rtnl_ematch_tree_alloc(uint16_t progid)
{
struct rtnl_ematch_tree *tree;
if (!(tree = calloc(1, sizeof(*tree))))
return NULL;
NL_INIT_LIST_HEAD(&tree->et_list);
tree->et_progid = progid;
return tree;
}
static void free_ematch_list(struct nl_list_head *head)
{
struct rtnl_ematch *pos, *next;
nl_list_for_each_entry_safe(pos, next, head, e_list) {
if (!nl_list_empty(&pos->e_childs))
free_ematch_list(&pos->e_childs);
rtnl_ematch_free(pos);
}
}
void rtnl_ematch_tree_free(struct rtnl_ematch_tree *tree)
{
if (!tree)
return;
free_ematch_list(&tree->et_list);
free(tree);
}
void rtnl_ematch_tree_add_tail(struct rtnl_ematch_tree *tree,
struct rtnl_ematch *ematch)
{
nl_list_add_tail(&ematch->e_list, &tree->et_list);
}
static inline uint32_t container_ref(struct rtnl_ematch *ematch)
{
return *((uint32_t *) rtnl_ematch_data(ematch));
}
static int link_tree(struct rtnl_ematch *index[], int nmatches, int pos,
struct nl_list_head *root)
{
struct rtnl_ematch *ematch;
int i;
for (i = pos; i < nmatches; i++) {
ematch = index[i];
nl_list_add_tail(&ematch->e_list, root);
if (ematch->e_kind == TCF_EM_CONTAINER)
link_tree(index, nmatches, container_ref(ematch),
&ematch->e_childs);
if (!(ematch->e_flags & TCF_EM_REL_MASK))
return 0;
}
/* Last entry in chain can't possibly have no relation */
return -NLE_INVAL;
}
static struct nla_policy tree_policy[TCA_EMATCH_TREE_MAX+1] = {
[TCA_EMATCH_TREE_HDR] = { .minlen=sizeof(struct tcf_ematch_tree_hdr) },
[TCA_EMATCH_TREE_LIST] = { .type = NLA_NESTED },
};
/**
* Parse ematch netlink attributes
*
* @return 0 on success or a negative error code.
*/
int rtnl_ematch_parse(struct nlattr *attr, struct rtnl_ematch_tree **result)
{
struct nlattr *a, *tb[TCA_EMATCH_TREE_MAX+1];
struct tcf_ematch_tree_hdr *thdr;
struct rtnl_ematch_tree *tree;
struct rtnl_ematch **index;
int nmatches = 0, err, remaining;
err = nla_parse_nested(tb, TCA_EMATCH_TREE_MAX, attr, tree_policy);
if (err < 0)
return err;
if (!tb[TCA_EMATCH_TREE_HDR])
return -NLE_MISSING_ATTR;
thdr = nla_data(tb[TCA_EMATCH_TREE_HDR]);
/* Ignore empty trees */
if (thdr->nmatches == 0)
return 0;
if (!tb[TCA_EMATCH_TREE_LIST])
return -NLE_MISSING_ATTR;
if (thdr->nmatches > (nla_len(tb[TCA_EMATCH_TREE_LIST]) /
nla_total_size(sizeof(struct tcf_ematch_hdr))))
return -NLE_INVAL;
if (!(index = calloc(thdr->nmatches, sizeof(struct rtnl_ematch *))))
return -NLE_NOMEM;
if (!(tree = rtnl_ematch_tree_alloc(thdr->progid))) {
err = -NLE_NOMEM;
goto errout;
}
nla_for_each_nested(a, tb[TCA_EMATCH_TREE_LIST], remaining) {
struct rtnl_ematch_ops *ops;
struct tcf_ematch_hdr *hdr;
struct rtnl_ematch *ematch;
void *data;
size_t len;
if (nla_len(a) < sizeof(*hdr)) {
err = -NLE_INVAL;
goto errout;
}
if (nmatches >= thdr->nmatches) {
err = -NLE_RANGE;
goto errout;
}
hdr = nla_data(a);
data = nla_data(a) + NLA_ALIGN(sizeof(*hdr));
len = nla_len(a) - NLA_ALIGN(sizeof(*hdr));
ops = rtnl_ematch_lookup_ops(hdr->kind);
if (ops && ops->eo_datalen && len < ops->eo_datalen) {
err = -NLE_INVAL;
goto errout;
}
if (!(ematch = rtnl_ematch_alloc(ops))) {
err = -NLE_NOMEM;
goto errout;
}
ematch->e_id = hdr->matchid;
ematch->e_kind = hdr->kind;
ematch->e_flags = hdr->flags;
if (ops && (err = ops->eo_parse(ematch, data, len)) < 0)
goto errout;
if (hdr->kind == TCF_EM_CONTAINER &&
container_ref(ematch) >= thdr->nmatches) {
err = -NLE_INVAL;
goto errout;
}
index[nmatches++] = ematch;
}
if (nmatches != thdr->nmatches) {
err = -NLE_INVAL;
goto errout;
}
err = link_tree(index, nmatches, 0, &tree->et_list);
if (err < 0)
goto errout;
free(index);
*result = tree;
return 0;
errout:
rtnl_ematch_tree_free(tree);
free(index);
return err;
}
static void dump_ematch_sequence(struct nl_list_head *head,
struct nl_dump_params *p)
{
struct rtnl_ematch *match;
nl_list_for_each_entry(match, head, e_list) {
if (match->e_flags & TCF_EM_INVERT)
nl_dump(p, "NOT ");
if (match->e_kind == TCF_EM_CONTAINER) {
nl_dump(p, "(");
dump_ematch_sequence(&match->e_childs, p);
nl_dump(p, ")");
} else if (!match->e_ops) {
nl_dump(p, "[unknown ematch %d]", match->e_kind);
} else {
nl_dump(p, "%s(", match->e_ops->eo_name);
if (match->e_ops->eo_dump)
match->e_ops->eo_dump(match, p);
nl_dump(p, ")");
}
switch (match->e_flags & TCF_EM_REL_MASK) {
case TCF_EM_REL_AND:
nl_dump(p, " AND ");
break;
case TCF_EM_REL_OR:
nl_dump(p, " OR ");
break;
default:
/* end of first level ematch sequence */
return;
}
}
}
void rtnl_ematch_tree_dump(struct rtnl_ematch_tree *tree,
struct nl_dump_params *p)
{
dump_ematch_sequence(&tree->et_list, p);
nl_dump(p, "\n");
}
/** @} */
/** @} */

116
lib/route/cls/ematch/cmp.c Normal file
View File

@ -0,0 +1,116 @@
/*
* lib/route/cls/ematch/cmp.c Simple packet data comparison ematch
*
* 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) 2008-2009 Thomas Graf <tgraf@suug.ch>
*/
/**
* @ingroup ematch
* @defgroup em_cmp Simple packet data comparison
*
* @{
*/
#include <netlink-local.h>
#include <netlink-tc.h>
#include <netlink/netlink.h>
#include <netlink/route/cls/ematch.h>
#include <linux/tc_ematch/tc_em_cmp.h>
void rtnl_ematch_cmp_set(struct rtnl_ematch *ematch,
struct tcf_em_cmp *cfg)
{
memcpy(rtnl_ematch_data(ematch), cfg, sizeof(*cfg));
}
struct tcf_em_cmp *rtnl_ematch_cmp_get(struct rtnl_ematch *ematch)
{
return rtnl_ematch_data(ematch);
}
static const char *align_txt(struct tcf_em_cmp *cmp)
{
switch (cmp->align) {
case TCF_EM_ALIGN_U8:
return "u8";
case TCF_EM_ALIGN_U16:
return (cmp->flags & TCF_EM_CMP_TRANS) ? "h16" : "u16";
case TCF_EM_ALIGN_U32:
return (cmp->flags & TCF_EM_CMP_TRANS) ? "h32" : "u32";
default:
return (cmp->flags & TCF_EM_CMP_TRANS) ? "h?" : "u?";
}
}
static const char *layer_txt(struct tcf_em_cmp *cmp)
{
switch (cmp->layer) {
case TCF_LAYER_LINK:
return "link";
case TCF_LAYER_NETWORK:
return "network";
case TCF_LAYER_TRANSPORT:
return "transport";
default:
return "?";
}
}
static const char *relation_txt(struct tcf_em_cmp *cmp)
{
switch (cmp->opnd) {
case TCF_EM_OPND_EQ:
return "eq";
case TCF_EM_OPND_LT:
return "lt";
case TCF_EM_OPND_GT:
return "gt";
default:
return "?";
}
}
static int cmp_parse(struct rtnl_ematch *m, void *data, size_t len)
{
memcpy(rtnl_ematch_data(m), data, len);
return 0;
}
static void cmp_dump(struct rtnl_ematch *m, struct nl_dump_params *p)
{
struct tcf_em_cmp *cmp = rtnl_ematch_data(m);
nl_dump(p, "%s at %s+%u ",
align_txt(cmp), layer_txt(cmp), cmp->off);
if (cmp->mask)
nl_dump(p, "& 0x%x ", cmp->mask);
nl_dump(p, "%s %u", relation_txt(cmp), cmp->val);
}
static struct rtnl_ematch_ops cmp_ops = {
.eo_kind = TCF_EM_CMP,
.eo_name = "cmp",
.eo_datalen = sizeof(struct tcf_em_cmp),
.eo_parse = cmp_parse,
.eo_dump = cmp_dump,
};
static void __init cmp_init(void)
{
rtnl_ematch_register(&cmp_ops);
}
static void __exit cmp_exit(void)
{
rtnl_ematch_unregister(&cmp_ops);
}
/** @} */

View File

@ -0,0 +1,39 @@
/*
* lib/route/cls/ematch/container.c Container Ematch
*
* 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) 2008-2009 Thomas Graf <tgraf@suug.ch>
*/
#include <netlink-local.h>
#include <netlink-tc.h>
#include <netlink/netlink.h>
#include <netlink/route/cls/ematch.h>
static int container_parse(struct rtnl_ematch *m, void *data, size_t len)
{
memcpy(m->e_data, data, sizeof(uint32_t));
return 0;
}
static struct rtnl_ematch_ops container_ops = {
.eo_kind = TCF_EM_CONTAINER,
.eo_name = "container",
.eo_datalen = sizeof(uint32_t),
.eo_parse = container_parse,
};
static void __init container_init(void)
{
rtnl_ematch_register(&container_ops);
}
static void __exit container_exit(void)
{
rtnl_ematch_unregister(&container_ops);
}

View File

@ -6,7 +6,7 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2006 Petr Gotthard <petr.gotthard@siemens.com>
* Copyright (c) 2006 Siemens AG Oesterreich
*/
@ -32,19 +32,6 @@
#define FW_ATTR_INDEV 0x008
/** @endcond */
static inline struct rtnl_fw *fw_cls(struct rtnl_cls *cls)
{
return (struct rtnl_fw *) cls->c_subdata;
}
static inline struct rtnl_fw *fw_alloc(struct rtnl_cls *cls)
{
if (!cls->c_subdata)
cls->c_subdata = calloc(1, sizeof(struct rtnl_fw));
return fw_cls(cls);
}
static struct nla_policy fw_policy[TCA_FW_MAX+1] = {
[TCA_FW_CLASSID] = { .type = NLA_U32 },
[TCA_FW_INDEV] = { .type = NLA_STRING,
@ -53,18 +40,14 @@ static struct nla_policy fw_policy[TCA_FW_MAX+1] = {
static int fw_msg_parser(struct rtnl_cls *cls)
{
int err;
struct rtnl_fw *f = rtnl_cls_data(cls);
struct nlattr *tb[TCA_FW_MAX + 1];
struct rtnl_fw *f;
int err;
err = tca_parse(tb, TCA_FW_MAX, (struct rtnl_tca *) cls, fw_policy);
if (err < 0)
return err;
f = fw_alloc(cls);
if (!f)
return -NLE_NOMEM;
if (tb[TCA_FW_CLASSID]) {
f->cf_classid = nla_get_u32(tb[TCA_FW_CLASSID]);
f->cf_mask |= FW_ATTR_CLASSID;
@ -94,47 +77,31 @@ static int fw_msg_parser(struct rtnl_cls *cls)
static void fw_free_data(struct rtnl_cls *cls)
{
struct rtnl_fw *f = fw_cls(cls);
if (!f)
return;
struct rtnl_fw *f = rtnl_cls_data(cls);
nl_data_free(f->cf_act);
nl_data_free(f->cf_police);
free(cls->c_subdata);
}
static int fw_clone(struct rtnl_cls *_dst, struct rtnl_cls *_src)
{
struct rtnl_fw *dst, *src = fw_cls(_src);
struct rtnl_fw *dst = rtnl_cls_data(_dst);
struct rtnl_fw *src = rtnl_cls_data(_src);
if (!src)
return 0;
dst = fw_alloc(_dst);
if (!dst)
if (src->cf_act && !(dst->cf_act = nl_data_clone(src->cf_act)))
return -NLE_NOMEM;
if (src->cf_act)
if (!(dst->cf_act = nl_data_clone(src->cf_act)))
return -NLE_NOMEM;
if (src->cf_police)
if (!(dst->cf_police = nl_data_clone(src->cf_police)))
return -NLE_NOMEM;
if (src->cf_police && !(dst->cf_police = nl_data_clone(src->cf_police)))
return -NLE_NOMEM;
return 0;
}
static void fw_dump_line(struct rtnl_cls *cls, struct nl_dump_params *p)
{
struct rtnl_fw *f = fw_cls(cls);
struct rtnl_fw *f = rtnl_cls_data(cls);
char buf[32];
if (!f)
return;
if (f->cf_mask & FW_ATTR_CLASSID)
nl_dump(p, " target %s",
rtnl_tc_handle2str(f->cf_classid, buf, sizeof(buf)));
@ -142,45 +109,32 @@ static void fw_dump_line(struct rtnl_cls *cls, struct nl_dump_params *p)
static void fw_dump_details(struct rtnl_cls *cls, struct nl_dump_params *p)
{
struct rtnl_fw *f = fw_cls(cls);
if (!f)
return;
struct rtnl_fw *f = rtnl_cls_data(cls);
if (f->cf_mask & FW_ATTR_INDEV)
nl_dump(p, "indev %s ", f->cf_indev);
}
static void fw_dump_stats(struct rtnl_cls *cls, struct nl_dump_params *p)
static int fw_get_opts(struct rtnl_cls *cls, struct nl_msg *msg)
{
}
static struct nl_msg *fw_get_opts(struct rtnl_cls *cls)
{
struct rtnl_fw *f;
struct nl_msg *msg;
struct rtnl_fw *f = rtnl_cls_data(cls);
f = fw_cls(cls);
if (!f)
return NULL;
msg = nlmsg_alloc();
if (!msg)
return NULL;
if (f->cf_mask & FW_ATTR_CLASSID)
nla_put_u32(msg, TCA_FW_CLASSID, f->cf_classid);
NLA_PUT_U32(msg, TCA_FW_CLASSID, f->cf_classid);
if (f->cf_mask & FW_ATTR_ACTION)
nla_put_data(msg, TCA_FW_ACT, f->cf_act);
NLA_PUT_DATA(msg, TCA_FW_ACT, f->cf_act);
if (f->cf_mask & FW_ATTR_POLICE)
nla_put_data(msg, TCA_FW_POLICE, f->cf_police);
NLA_PUT_DATA(msg, TCA_FW_POLICE, f->cf_police);
if (f->cf_mask & FW_ATTR_INDEV)
nla_put_string(msg, TCA_FW_INDEV, f->cf_indev);
NLA_PUT_STRING(msg, TCA_FW_INDEV, f->cf_indev);
return msg;
return 0;
nla_put_failure:
return -NLE_NOMEM;
}
/**
@ -190,12 +144,8 @@ static struct nl_msg *fw_get_opts(struct rtnl_cls *cls)
int rtnl_fw_set_classid(struct rtnl_cls *cls, uint32_t classid)
{
struct rtnl_fw *f;
struct rtnl_fw *f = rtnl_cls_data(cls);
f = fw_alloc(cls);
if (!f)
return -NLE_NOMEM;
f->cf_classid = classid;
f->cf_mask |= FW_ATTR_CLASSID;
@ -206,6 +156,7 @@ int rtnl_fw_set_classid(struct rtnl_cls *cls, uint32_t classid)
static struct rtnl_cls_ops fw_ops = {
.co_kind = "fw",
.co_size = sizeof(struct rtnl_fw),
.co_msg_parser = fw_msg_parser,
.co_free_data = fw_free_data,
.co_clone = fw_clone,
@ -213,7 +164,6 @@ static struct rtnl_cls_ops fw_ops = {
.co_dump = {
[NL_DUMP_LINE] = fw_dump_line,
[NL_DUMP_DETAILS] = fw_dump_details,
[NL_DUMP_STATS] = fw_dump_stats,
},
};

View File

@ -6,7 +6,7 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2005-2006 Petr Gotthard <petr.gotthard@siemens.com>
* Copyright (c) 2005-2006 Siemens AG Oesterreich
*/
@ -40,19 +40,6 @@
#define U32_ATTR_INDEV 0x100
/** @endcond */
static inline struct rtnl_u32 *u32_cls(struct rtnl_cls *cls)
{
return (struct rtnl_u32 *) cls->c_subdata;
}
static inline struct rtnl_u32 *u32_alloc(struct rtnl_cls *cls)
{
if (!cls->c_subdata)
cls->c_subdata = calloc(1, sizeof(struct rtnl_u32));
return u32_cls(cls);
}
static inline struct tc_u32_sel *u32_selector(struct rtnl_u32 *u)
{
return (struct tc_u32_sel *) u->cu_selector->d_data;
@ -79,18 +66,14 @@ static struct nla_policy u32_policy[TCA_U32_MAX+1] = {
static int u32_msg_parser(struct rtnl_cls *cls)
{
int err;
struct rtnl_u32 *u = rtnl_cls_data(cls);
struct nlattr *tb[TCA_U32_MAX + 1];
struct rtnl_u32 *u;
int err;
err = tca_parse(tb, TCA_U32_MAX, (struct rtnl_tca *) cls, u32_policy);
if (err < 0)
return err;
u = u32_alloc(cls);
if (!u)
goto errout_nomem;
if (tb[TCA_U32_DIVISOR]) {
u->cu_divisor = nla_get_u32(tb[TCA_U32_DIVISOR]);
u->cu_mask |= U32_ATTR_DIVISOR;
@ -170,57 +153,40 @@ errout:
static void u32_free_data(struct rtnl_cls *cls)
{
struct rtnl_u32 *u = u32_cls(cls);
if (!u)
return;
struct rtnl_u32 *u = rtnl_cls_data(cls);
nl_data_free(u->cu_selector);
nl_data_free(u->cu_act);
nl_data_free(u->cu_police);
nl_data_free(u->cu_pcnt);
free(cls->c_subdata);
}
static int u32_clone(struct rtnl_cls *_dst, struct rtnl_cls *_src)
{
struct rtnl_u32 *dst, *src = u32_cls(_src);
struct rtnl_u32 *dst = rtnl_cls_data(_dst);
struct rtnl_u32 *src = rtnl_cls_data(_src);
if (!src)
return 0;
dst = u32_alloc(_dst);
if (!dst)
if (src->cu_selector &&
!(dst->cu_selector = nl_data_clone(src->cu_selector)))
return -NLE_NOMEM;
if (src->cu_selector)
if (!(dst->cu_selector = nl_data_clone(src->cu_selector)))
return -NLE_NOMEM;
if (src->cu_act && !(dst->cu_act = nl_data_clone(src->cu_act)))
return -NLE_NOMEM;
if (src->cu_act)
if (!(dst->cu_act = nl_data_clone(src->cu_act)))
return -NLE_NOMEM;
if (src->cu_police && !(dst->cu_police = nl_data_clone(src->cu_police)))
return -NLE_NOMEM;
if (src->cu_police)
if (!(dst->cu_police = nl_data_clone(src->cu_police)))
return -NLE_NOMEM;
if (src->cu_pcnt)
if (!(dst->cu_pcnt = nl_data_clone(src->cu_pcnt)))
return -NLE_NOMEM;
if (src->cu_pcnt && !(dst->cu_pcnt = nl_data_clone(src->cu_pcnt)))
return -NLE_NOMEM;
return 0;
}
static void u32_dump_line(struct rtnl_cls *cls, struct nl_dump_params *p)
{
struct rtnl_u32 *u = u32_cls(cls);
struct rtnl_u32 *u = rtnl_cls_data(cls);
char buf[32];
if (!u)
return;
if (u->cu_mask & U32_ATTR_DIVISOR)
nl_dump(p, " divisor %u", u->cu_divisor);
else if (u->cu_mask & U32_ATTR_CLASSID)
@ -289,12 +255,9 @@ static void print_selector(struct nl_dump_params *p, struct tc_u32_sel *sel,
static void u32_dump_details(struct rtnl_cls *cls, struct nl_dump_params *p)
{
struct rtnl_u32 *u = u32_cls(cls);
struct rtnl_u32 *u = rtnl_cls_data(cls);
struct tc_u32_sel *s;
if (!u)
return;
if (!(u->cu_mask & U32_ATTR_SELECTOR)) {
nl_dump(p, "no-selector\n");
return;
@ -328,10 +291,7 @@ static void u32_dump_details(struct rtnl_cls *cls, struct nl_dump_params *p)
static void u32_dump_stats(struct rtnl_cls *cls, struct nl_dump_params *p)
{
struct rtnl_u32 *u = u32_cls(cls);
if (!u)
return;
struct rtnl_u32 *u = rtnl_cls_data(cls);
if (u->cu_mask & U32_ATTR_PCNT) {
struct tc_u32_pcnt *pc = u->cu_pcnt->d_data;
@ -342,44 +302,38 @@ static void u32_dump_stats(struct rtnl_cls *cls, struct nl_dump_params *p)
}
}
static struct nl_msg *u32_get_opts(struct rtnl_cls *cls)
static int u32_get_opts(struct rtnl_cls *cls, struct nl_msg *msg)
{
struct rtnl_u32 *u;
struct nl_msg *msg;
struct rtnl_u32 *u = rtnl_cls_data(cls);
u = u32_cls(cls);
if (!u)
return NULL;
msg = nlmsg_alloc();
if (!msg)
return NULL;
if (u->cu_mask & U32_ATTR_DIVISOR)
nla_put_u32(msg, TCA_U32_DIVISOR, u->cu_divisor);
NLA_PUT_U32(msg, TCA_U32_DIVISOR, u->cu_divisor);
if (u->cu_mask & U32_ATTR_HASH)
nla_put_u32(msg, TCA_U32_HASH, u->cu_hash);
NLA_PUT_U32(msg, TCA_U32_HASH, u->cu_hash);
if (u->cu_mask & U32_ATTR_CLASSID)
nla_put_u32(msg, TCA_U32_CLASSID, u->cu_classid);
NLA_PUT_U32(msg, TCA_U32_CLASSID, u->cu_classid);
if (u->cu_mask & U32_ATTR_LINK)
nla_put_u32(msg, TCA_U32_LINK, u->cu_link);
NLA_PUT_U32(msg, TCA_U32_LINK, u->cu_link);
if (u->cu_mask & U32_ATTR_SELECTOR)
nla_put_data(msg, TCA_U32_SEL, u->cu_selector);
NLA_PUT_DATA(msg, TCA_U32_SEL, u->cu_selector);
if (u->cu_mask & U32_ATTR_ACTION)
nla_put_data(msg, TCA_U32_ACT, u->cu_act);
NLA_PUT_DATA(msg, TCA_U32_ACT, u->cu_act);
if (u->cu_mask & U32_ATTR_POLICE)
nla_put_data(msg, TCA_U32_POLICE, u->cu_police);
NLA_PUT_DATA(msg, TCA_U32_POLICE, u->cu_police);
if (u->cu_mask & U32_ATTR_INDEV)
nla_put_string(msg, TCA_U32_INDEV, u->cu_indev);
NLA_PUT_STRING(msg, TCA_U32_INDEV, u->cu_indev);
return msg;
return 0;
nla_put_failure:
return -NLE_NOMEM;
}
/**
@ -397,12 +351,8 @@ void rtnl_u32_set_handle(struct rtnl_cls *cls, int htid, int hash,
int rtnl_u32_set_classid(struct rtnl_cls *cls, uint32_t classid)
{
struct rtnl_u32 *u;
struct rtnl_u32 *u = rtnl_cls_data(cls);
u = u32_alloc(cls);
if (!u)
return -NLE_NOMEM;
u->cu_classid = classid;
u->cu_mask |= U32_ATTR_CLASSID;
@ -419,11 +369,7 @@ int rtnl_u32_set_classid(struct rtnl_cls *cls, uint32_t classid)
int rtnl_u32_set_flags(struct rtnl_cls *cls, int flags)
{
struct tc_u32_sel *sel;
struct rtnl_u32 *u;
u = u32_alloc(cls);
if (!u)
return -NLE_NOMEM;
struct rtnl_u32 *u = rtnl_cls_data(cls);
sel = u32_selector_alloc(u);
if (!sel)
@ -453,13 +399,9 @@ int rtnl_u32_add_key(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
int off, int offmask)
{
struct tc_u32_sel *sel;
struct rtnl_u32 *u;
struct rtnl_u32 *u = rtnl_cls_data(cls);
int err;
u = u32_alloc(cls);
if (!u)
return -NLE_NOMEM;
sel = u32_selector_alloc(u);
if (!sel)
return -NLE_NOMEM;
@ -562,6 +504,7 @@ int rtnl_u32_add_key_in6_addr(struct rtnl_cls *cls, struct in6_addr *addr,
static struct rtnl_cls_ops u32_ops = {
.co_kind = "u32",
.co_size = sizeof(struct rtnl_u32),
.co_msg_parser = u32_msg_parser,
.co_free_data = u32_free_data,
.co_clone = u32_clone,

View File

@ -39,6 +39,8 @@ static void cls_free_data(struct nl_object *obj)
cops = rtnl_cls_lookup_ops(cls);
if (cops && cops->co_free_data)
cops->co_free_data(cls);
nl_data_free(cls->c_subdata);
}
static int cls_clone(struct nl_object *_dst, struct nl_object *_src)
@ -52,6 +54,13 @@ static int cls_clone(struct nl_object *_dst, struct nl_object *_src)
if (err < 0)
goto errout;
if (src->c_subdata) {
if (!(dst->c_subdata = nl_data_clone(src->c_subdata))) {
err = -NLE_NOMEM;
goto errout;
}
}
cops = rtnl_cls_lookup_ops(src);
if (cops && cops->co_clone)
err = cops->co_clone(dst, src);
@ -133,6 +142,11 @@ void rtnl_cls_set_ifindex(struct rtnl_cls *f, int ifindex)
tca_set_ifindex((struct rtnl_tca *) f, ifindex);
}
int rtnl_cls_get_ifindex(struct rtnl_cls *cls)
{
return cls->c_ifindex;
}
void rtnl_cls_set_handle(struct rtnl_cls *f, uint32_t handle)
{
tca_set_handle((struct rtnl_tca *) f, handle);
@ -143,14 +157,21 @@ void rtnl_cls_set_parent(struct rtnl_cls *f, uint32_t parent)
tca_set_parent((struct rtnl_tca *) f, parent);
}
int rtnl_cls_set_kind(struct rtnl_cls *f, const char *kind)
uint32_t rtnl_cls_get_parent(struct rtnl_cls *cls)
{
tca_set_kind((struct rtnl_tca *) f, kind);
return cls->c_parent;
}
int rtnl_cls_set_kind(struct rtnl_cls *cls, const char *kind)
{
if (cls->ce_mask & TCA_ATTR_KIND)
return -NLE_EXIST;
tca_set_kind((struct rtnl_tca *) cls, kind);
/* Force allocation of data */
rtnl_cls_data(cls);
f->c_ops = __rtnl_cls_lookup_ops(kind);
if (f->c_ops == NULL)
return -NLE_OBJ_NOTFOUND;
return 0;
}
@ -187,6 +208,32 @@ uint16_t rtnl_cls_get_protocol(struct rtnl_cls *cls)
return ETH_P_ALL;
}
void *rtnl_cls_data(struct rtnl_cls *cls)
{
if (!cls->c_subdata) {
struct rtnl_cls_ops *ops = cls->c_ops;
if (!ops) {
if (!cls->c_kind[0])
BUG();
ops = __rtnl_cls_lookup_ops(cls->c_kind);
if (ops == NULL)
return NULL;
cls->c_ops = ops;
}
if (!ops->co_size)
BUG();
if (!(cls->c_subdata = nl_data_alloc(NULL, ops->co_size)))
return NULL;
}
return nl_data_get(cls->c_subdata);
}
/** @} */
struct nl_object_ops cls_obj_ops = {

View File

@ -17,6 +17,9 @@ LDFLAGS += -L../lib -lnl
CIN := $(wildcard nl-*.c) $(wildcard genl-*.c) $(wildcard nf-*.c)
TOOLS := $(CIN:%.c=%)
CLS := $(wildcard cls/*.c)
CLS_OBJ := $(CLS:%.c=%.o)
all: $(TOOLS)
$(TOOLS): utils.o
@ -31,6 +34,7 @@ nl-rule-list: rule-utils.o rtnl-utils.o
nl-neightbl-list: rtnl-utils.o
nl-monitor: rtnl-utils.o
nl-tctree-list: rtnl-utils.o
nl-cls-add nl-cls-delete nl-cls-list: rtnl-utils.o cls/utils.o $(CLS_OBJ)
genl-ctrl-list: ctrl-utils.o

90
src/cls/basic.c Normal file
View File

@ -0,0 +1,90 @@
/*
* src/cls/basic.c Basic Classifier
*
* This library 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 version 2 of the License.
*
* Copyright (c) 2008 Thomas Graf <tgraf@suug.ch>
*/
#include "utils.h"
#include <netlink/route/cls/basic.h>
#include <netlink/route/cls/ematch.h>
static void print_usage(void)
{
printf(
"Usage: ... basic [OPTIONS]...\n"
"\n"
"Options\n"
" -h, --help Show this help.\n"
" -e, --ematch=MATCH Extended match (See --ematch help).\n"
" -c, --classid=HANDLE Target class to classify matching packets to.\n"
);
exit(0);
}
static void basic_parse_argv(struct rtnl_cls *cls, int argc, char **argv)
{
uint32_t classid;
for (;;) {
int c, optidx = 0, err;
static struct option long_opts[] = {
{ "help", 0, 0, 'h' },
{ "ematch", 1, 0, 'e' },
{ "classid", 1, 0, 'c' },
{ 0, 0, 0, 0 }
};
c = getopt_long(argc, argv, "he:c:", long_opts, &optidx);
if (c == -1)
break;
switch (c) {
case '?':
exit(NLE_INVAL);
case 'h':
print_usage();
case 'e':
#if 0
if ((err = parse_ematch_syntax(optarg, &tree)) < 0)
fatal(err, "Error while parsing ematch: %s",
nl_geterror(err));
if ((err = rtnl_basic_set_ematch(cls, tree)) < 0)
fatal(err, "Unable to set ematch: %s",
nl_geterror(err));
#endif
break;
case 'c':
if ((err = rtnl_tc_str2handle(optarg, &classid)) < 0)
fatal(err, "Invalid classid \"%s\": %s",
optarg, nl_geterror(err));
if ((err = rtnl_basic_set_classid(cls, classid)) < 0)
fatal(err, "Unable to set classid: %s",
nl_geterror(err));
break;
}
}
}
static struct cls_module basic_module = {
.name = "basic",
.parse_argv = basic_parse_argv,
};
static void __attribute__ ((constructor)) basic_init(void)
{
register_cls_module(&basic_module);
}
static void __attribute__ ((destructor)) basic_exit(void)
{
unregister_cls_module(&basic_module);
}

78
src/cls/cgroup.c Normal file
View File

@ -0,0 +1,78 @@
/*
* src/cls/cgroup.c Control Groups Classifier
*
* This library 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 version 2 of the License.
*
* Copyright (c) 2009 Thomas Graf <tgraf@suug.ch>
*/
#include "utils.h"
#include <netlink/route/cls/cgroup.h>
#include <netlink/route/cls/ematch.h>
static void print_usage(void)
{
printf(
"Usage: ... cgroup [OPTIONS]...\n"
"\n"
"Options\n"
" -h, --help Show this help.\n"
" -e, --ematch=MATCH Extended match (See --ematch help).\n"
" -c, --classid=HANDLE Target class to classify matching packets to.\n"
);
exit(0);
}
static void basic_parse_argv(struct rtnl_cls *cls, int argc, char **argv)
{
for (;;) {
int c, optidx = 0;
static struct option long_opts[] = {
{ "help", 0, 0, 'h' },
{ "ematch", 1, 0, 'e' },
{ "classid", 1, 0, 'c' },
{ 0, 0, 0, 0 }
};
c = getopt_long(argc, argv, "he:c:", long_opts, &optidx);
if (c == -1)
break;
switch (c) {
case '?':
exit(NLE_INVAL);
case 'h':
print_usage();
#if 0
case 'e':
if ((err = parse_ematch_syntax(optarg, &tree)) < 0)
fatal(err, "Error while parsing ematch: %s",
nl_geterror(err));
if ((err = rtnl_basic_set_ematch(cls, tree)) < 0)
fatal(err, "Unable to set ematch: %s",
nl_geterror(err));
break;
#endif
}
}
}
static struct cls_module cgroup_module = {
.name = "cgroup",
.parse_argv = basic_parse_argv,
};
static void __init cgroup_init(void)
{
register_cls_module(&cgroup_module);
}
static void __exit cgroup_exit(void)
{
unregister_cls_module(&cgroup_module);
}

105
src/cls/utils.c Normal file
View File

@ -0,0 +1,105 @@
/*
* src/cls-utils.c Classifier Helpers
*
* This library 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 version 2 of the License.
*
* Copyright (c) 2008-2009 Thomas Graf <tgraf@suug.ch>
*/
#include "utils.h"
struct rtnl_cls *nlt_alloc_cls(void)
{
struct rtnl_cls *cls;
cls = rtnl_cls_alloc();
if (!cls)
fatal(ENOMEM, "Unable to allocate classifier object");
return cls;
}
void parse_dev(struct rtnl_cls *cls, struct nl_cache *link_cache, char *arg)
{
int ival;
if (!(ival = rtnl_link_name2i(link_cache, arg)))
fatal(ENOENT, "Link \"%s\" does not exist", arg);
rtnl_cls_set_ifindex(cls, ival);
}
void parse_prio(struct rtnl_cls *cls, char *arg)
{
uint32_t prio = parse_u32(arg);
rtnl_cls_set_prio(cls, prio);
}
void parse_parent(struct rtnl_cls *cls, char *arg)
{
uint32_t parent;
int err;
if ((err = rtnl_tc_str2handle(arg, &parent)) < 0)
fatal(err, "Unable to parse handle \"%s\": %s",
arg, nl_geterror(err));
rtnl_cls_set_parent(cls, parent);
}
void parse_handle(struct rtnl_cls *cls, char *arg)
{
uint32_t handle;
int err;
if ((err = rtnl_tc_str2handle(arg, &handle)) < 0)
fatal(err, "Unable to parse handle \"%s\": %s",
arg, nl_geterror(err));
rtnl_cls_set_handle(cls, handle);
}
void parse_proto(struct rtnl_cls *cls, char *arg)
{
int proto = nl_str2ether_proto(arg);
if (proto < 0)
fatal(proto, "Unable to parse protocol \"%s\": %s",
arg, nl_geterror(proto));
rtnl_cls_set_protocol(cls, proto);
}
static NL_LIST_HEAD(cls_modules);
struct cls_module *lookup_cls_mod(struct rtnl_cls_ops *ops)
{
struct cls_module *mod;
nl_list_for_each_entry(mod, &cls_modules, list) {
if (mod->ops == ops)
return mod;
}
return NULL;
}
void register_cls_module(struct cls_module *mod)
{
struct rtnl_cls_ops *ops;
if (!(ops = __rtnl_cls_lookup_ops(mod->name)))
fatal(ENOENT, "Could not locate classifier module \"%s\"",
mod->name);
if (lookup_cls_mod(ops) != NULL)
fatal(EEXIST, "Duplicate classifier module registration.");
mod->ops = ops;
nl_list_add_tail(&mod->list, &cls_modules);
}
void unregister_cls_module(struct cls_module *mod)
{
nl_list_del(&mod->list);
}

51
src/cls/utils.h Normal file
View File

@ -0,0 +1,51 @@
/*
* src/cls-utils.h Classifier Helpers
*
* This library 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 version 2 of the License.
*
* Copyright (c) 2008-2009 Thomas Graf <tgraf@suug.ch>
*/
#ifndef __CLS_UTILS_H_
#define __CLS_UTILS_H_
#include "../utils.h"
#include <netlink/route/classifier-modules.h>
#include <netlink/route/cls/ematch.h>
struct cls_module
{
const char * name;
struct rtnl_cls_ops * ops;
void (*parse_argv)(struct rtnl_cls *, int, char **);
struct nl_list_head list;
};
extern struct cls_module *lookup_cls_mod(struct rtnl_cls_ops *);
extern void register_cls_module(struct cls_module *);
extern void unregister_cls_module(struct cls_module *);
struct ematch_module
{
int kind;
struct rtnl_ematch_ops *ops;
void (*parse_argv)(struct rtnl_ematch *, int, char **);
struct nl_list_head list;
};
extern struct ematch_module *lookup_ematch_mod(struct rtnl_ematch_ops *);
extern void register_ematch_module(struct ematch_module *);
extern void unregister_ematch_module(struct ematch_module *);
extern struct rtnl_cls *nlt_alloc_cls(void);
extern void parse_dev(struct rtnl_cls *, struct nl_cache *, char *);
extern void parse_prio(struct rtnl_cls *, char *);
extern void parse_parent(struct rtnl_cls *, char *);
extern void parse_handle(struct rtnl_cls *, char *);
extern void parse_proto(struct rtnl_cls *, char *);
extern int parse_ematch_syntax(const char *, struct rtnl_ematch_tree **);
#endif

117
src/nl-cls-add.c Normal file
View File

@ -0,0 +1,117 @@
/*
* src/nl-cls-add.c Add classifier
*
* This library 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 version 2 of the License.
*
* Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch>
*/
#include "cls/utils.h"
static int quiet = 0;
static void print_usage(void)
{
printf(
"Usage: nl-cls-add [OPTION]... [CLASSIFIER] TYPE [TYPE OPTIONS]...\n"
"\n"
"Options\n"
" -q, --quiet Do not print informal notifications.\n"
" -h, --help Show this help.\n"
" -v, --version Show versioning information.\n"
"\n"
"Classifier Options\n"
" -d, --dev=DEV Device the classifier should be assigned to.\n"
" -p, --parent=HANDLE Parent QDisc\n"
" --proto=PROTO Protocol (default=IPv4)\n"
" --prio=NUM Priority (0..256)\n"
" --id=HANDLE Unique identifier\n"
);
exit(0);
}
int main(int argc, char *argv[])
{
struct nl_sock *sock;
struct rtnl_cls *cls;
struct nl_cache *link_cache;
struct rtnl_cls_ops *ops;
struct cls_module *mod;
struct nl_dump_params dp = {
.dp_type = NL_DUMP_DETAILS,
.dp_fd = stdout,
};
char *kind;
int err, nlflags = NLM_F_CREATE;
sock = nlt_alloc_socket();
nlt_connect(sock, NETLINK_ROUTE);
link_cache = nlt_alloc_link_cache(sock);
cls = nlt_alloc_cls();
for (;;) {
int c, optidx = 0;
enum {
ARG_PROTO = 257,
ARG_PRIO = 258,
ARG_ID,
};
static struct option long_opts[] = {
{ "quiet", 0, 0, 'q' },
{ "help", 0, 0, 'h' },
{ "version", 0, 0, 'v' },
{ "dev", 1, 0, 'd' },
{ "parent", 1, 0, 'p' },
{ "proto", 1, 0, ARG_PROTO },
{ "prio", 1, 0, ARG_PRIO },
{ "id", 1, 0, ARG_ID },
{ 0, 0, 0, 0 }
};
c = getopt_long(argc, argv, "+qhva:d:", long_opts, &optidx);
if (c == -1)
break;
switch (c) {
case '?': exit(NLE_INVAL);
case 'q': quiet = 1; break;
case 'h': print_usage(); break;
case 'v': nlt_print_version(); break;
case 'd': parse_dev(cls, link_cache, optarg); break;
case 'p': parse_parent(cls, optarg); break;
case ARG_PRIO: parse_prio(cls, optarg); break;
case ARG_ID: parse_handle(cls, optarg); break;
case ARG_PROTO: parse_proto(cls, optarg); break;
}
}
if (optind >= argc) {
print_usage();
fatal(EINVAL, "Missing classifier type");
}
kind = argv[optind++];
if ((err = rtnl_cls_set_kind(cls, kind)) < 0)
fatal(ENOENT, "Unknown classifier type \"%s\".", kind);
ops = rtnl_cls_get_ops(cls);
if (!(mod = lookup_cls_mod(ops)))
fatal(ENOTSUP, "Classifier type \"%s\" not supported.", kind);
mod->parse_argv(cls, argc, argv);
printf("Adding ");
nl_object_dump(OBJ_CAST(cls), &dp);
if ((err = rtnl_cls_add(sock, cls, nlflags)) < 0)
fatal(err, "Unable to add classifier: %s", nl_geterror(err));
if (!quiet) {
printf("Added ");
nl_object_dump(OBJ_CAST(cls), &dp);
}
return 0;
}

133
src/nl-cls-delete.c Normal file
View File

@ -0,0 +1,133 @@
/*
* src/nl-cls-delete.c Delete Classifier
*
* 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) 2008 Thomas Graf <tgraf@suug.ch>
*/
#include "cls/utils.h"
static int interactive = 0, default_yes = 0, quiet = 0;
static int deleted = 0;
static struct nl_sock *sock;
static void print_usage(void)
{
printf(
"Usage: nl-cls-list [OPTION]... [CLASSIFIER]\n"
"\n"
"Options\n"
" -i, --interactive Run interactively\n"
" --yes Set default answer to yes\n"
" -q, --quiet Do not print informal notifications\n"
" -h, --help Show this help\n"
" -v, --version Show versioning information\n"
"\n"
"Classifier Options\n"
" -d, --dev=DEV Device the classifier should be assigned to.\n"
" -p, --parent=HANDLE Parent qdisc/class\n"
" --proto=PROTO Protocol\n"
" --prio=NUM Priority (0..256)\n"
" --id=HANDLE Unique identifier\n"
);
exit(0);
}
static void delete_cb(struct nl_object *obj, void *arg)
{
struct rtnl_cls *cls = (struct rtnl_cls *) obj;
struct nl_dump_params params = {
.dp_type = NL_DUMP_LINE,
.dp_fd = stdout,
};
int err;
if (interactive && !nlt_confirm(obj, &params, default_yes))
return;
if ((err = rtnl_cls_delete(sock, cls, 0)) < 0)
fatal(err, "Unable to delete classifier: %s",
nl_geterror(err));
if (!quiet) {
printf("Deleted ");
nl_object_dump(obj, &params);
}
deleted++;
}
int main(int argc, char *argv[])
{
struct nl_cache *link_cache, *cls_cache;
struct rtnl_cls *cls;
int nf = 0, err;
sock = nlt_alloc_socket();
nlt_connect(sock, NETLINK_ROUTE);
link_cache = nlt_alloc_link_cache(sock);
cls = nlt_alloc_cls();
for (;;) {
int c, optidx = 0;
enum {
ARG_PRIO = 257,
ARG_PROTO = 258,
ARG_ID,
ARG_YES,
};
static struct option long_opts[] = {
{ "interactive", 0, 0, 'i' },
{ "yes", 0, 0, ARG_YES },
{ "quiet", 0, 0, 'q' },
{ "help", 0, 0, 'h' },
{ "version", 0, 0, 'v' },
{ "dev", 1, 0, 'd' },
{ "parent", 1, 0, 'p' },
{ "proto", 1, 0, ARG_PROTO },
{ "prio", 1, 0, ARG_PRIO },
{ "id", 1, 0, ARG_ID },
{ 0, 0, 0, 0 }
};
c = getopt_long(argc, argv, "iqhvd:p:", long_opts, &optidx);
if (c == -1)
break;
switch (c) {
case 'i': interactive = 1; break;
case ARG_YES: default_yes = 1; break;
case 'q': quiet = 1; break;
case 'h': print_usage(); break;
case 'v': nlt_print_version(); break;
case 'd': nf++; parse_dev(cls, link_cache, optarg); break;
case 'p': nf++; parse_parent(cls, optarg); break;
case ARG_PRIO: nf++; parse_prio(cls, optarg); break;
case ARG_ID: nf++; parse_handle(cls, optarg); break;
case ARG_PROTO: nf++; parse_proto(cls, optarg); break;
}
}
if (nf == 0 && !interactive && !default_yes) {
fprintf(stderr, "You attempted to delete all classifiers in "
"non-interactive mode, aborting.\n");
exit(0);
}
err = rtnl_cls_alloc_cache(sock, rtnl_cls_get_ifindex(cls),
rtnl_cls_get_parent(cls), &cls_cache);
if (err < 0)
fatal(err, "Unable to allocate classifier cache: %s",
nl_geterror(err));
nl_cache_foreach_filter(cls_cache, OBJ_CAST(cls), delete_cb, NULL);
if (!quiet)
printf("Deleted %d classifiers\n", deleted);
return 0;
}

113
src/nl-cls-list.c Normal file
View File

@ -0,0 +1,113 @@
/*
* src/nl-cls-list.c List classifiers
*
* 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) 2008 Thomas Graf <tgraf@suug.ch>
*/
#include "cls/utils.h"
static struct nl_sock *sock;
static struct rtnl_cls *cls;
static struct nl_dump_params params = {
.dp_type = NL_DUMP_LINE,
};
static void print_usage(void)
{
printf(
"Usage: nl-cls-list [OPTION]... [CLASSIFIER]\n"
"\n"
"Options\n"
" -f, --format=TYPE Output format { brief | details | stats }\n"
" -h, --help Show this help text.\n"
" -v, --version Show versioning information.\n"
"\n"
"Classifier Options\n"
" -d, --dev=DEV Device the classifier should be assigned to.\n"
" -p, --parent=HANDLE Parent qdisc/class\n"
" --proto=PROTO Protocol\n"
" --prio=NUM Priority\n"
" --id=NUM Identifier\n"
);
exit(0);
}
static void print_cls(struct nl_object *obj, void *arg)
{
struct nl_cache *cls_cache;
int err, ifindex;
if (obj)
ifindex = rtnl_link_get_ifindex((struct rtnl_link *) obj);
else
ifindex = rtnl_cls_get_ifindex(cls);
err = rtnl_cls_alloc_cache(sock, ifindex, rtnl_cls_get_parent(cls),
&cls_cache);
if (err < 0)
fatal(err, "Unable to allocate classifier cache: %s",
nl_geterror(err));
nl_cache_dump_filter(cls_cache, &params, OBJ_CAST(cls));
nl_cache_free(cls_cache);
}
int main(int argc, char *argv[])
{
struct nl_cache *link_cache;
int dev = 0;
params.dp_fd = stdout;
sock = nlt_alloc_socket();
nlt_connect(sock, NETLINK_ROUTE);
link_cache = nlt_alloc_link_cache(sock);
cls = nlt_alloc_cls();
for (;;) {
int c, optidx = 0;
enum {
ARG_PROTO = 257,
ARG_PRIO = 258,
ARG_ID,
};
static struct option long_opts[] = {
{ "format", 1, 0, 'f' },
{ "help", 0, 0, 'h' },
{ "version", 0, 0, 'v' },
{ "dev", 1, 0, 'd' },
{ "parent", 1, 0, 'p' },
{ "proto", 1, 0, ARG_PROTO },
{ "prio", 1, 0, ARG_PRIO },
{ "id", 1, 0, ARG_ID },
{ 0, 0, 0, 0 }
};
c = getopt_long(argc, argv, "+f:qhva:d:", long_opts, &optidx);
if (c == -1)
break;
switch (c) {
case '?': exit(NLE_INVAL);
case 'f': params.dp_type = nlt_parse_dumptype(optarg); break;
case 'h': print_usage(); break;
case 'v': nlt_print_version(); break;
case 'd': dev = 1; parse_dev(cls, link_cache, optarg); break;
case 'p': parse_parent(cls, optarg); break;
case ARG_PRIO: parse_prio(cls, optarg); break;
case ARG_ID: parse_handle(cls, optarg); break;
case ARG_PROTO: parse_proto(cls, optarg); break;
}
}
if (!dev)
nl_cache_foreach(link_cache, print_cls, NULL);
else
print_cls(NULL, NULL);
return 0;
}

View File

@ -9,8 +9,8 @@
* Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
*/
#include "utils.h"
#include <netlink-local.h>
#include "utils.h"
static void print_usage(void)
{

View File

@ -36,6 +36,7 @@
#include <netlink/route/qdisc.h>
#include <netlink/route/class.h>
#include <netlink/route/classifier.h>
#include <netlink/route/cls/ematch.h>
#include <netlink/fib_lookup/lookup.h>
#include <netlink/fib_lookup/request.h>
#include <netlink/genl/genl.h>
@ -43,6 +44,14 @@
#include <netlink/genl/mngt.h>
#include <netlink/netfilter/ct.h>
#ifndef __init
#define __init __attribute__((constructor))
#endif
#ifndef __exit
#define __exit __attribute__((destructor))
#endif
extern uint32_t parse_u32(const char *);
extern void nlt_print_version(void);

View File

@ -23,7 +23,7 @@ $(TOOLS): ../src/utils.o
test-%: test-%.c
@echo " LD $@"; \
$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) -lnl-genl
$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) -lnl-genl -lnl-route
clean:
@echo " CLEAN src"; \