- 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:
parent
7d249fc2e1
commit
ef858fb492
31 changed files with 2047 additions and 201 deletions
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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))
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
33
include/netlink/route/cls/basic.h
Normal file
33
include/netlink/route/cls/basic.h
Normal 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
|
31
include/netlink/route/cls/cgroup.h
Normal file
31
include/netlink/route/cls/cgroup.h
Normal 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
|
73
include/netlink/route/cls/ematch.h
Normal file
73
include/netlink/route/cls/ematch.h
Normal 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
|
31
include/netlink/route/cls/ematch/cmp.h
Normal file
31
include/netlink/route/cls/ematch/cmp.h
Normal 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
|
|
@ -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)
|
||||
|
|
|
@ -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
211
lib/route/cls/basic.c
Normal 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
141
lib/route/cls/cgroup.c
Normal 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
410
lib/route/cls/ematch.c
Normal 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
116
lib/route/cls/ematch/cmp.c
Normal 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);
|
||||
}
|
||||
|
||||
/** @} */
|
39
lib/route/cls/ematch/container.c
Normal file
39
lib/route/cls/ematch/container.c
Normal 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);
|
||||
}
|
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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
90
src/cls/basic.c
Normal 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
78
src/cls/cgroup.c
Normal 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
105
src/cls/utils.c
Normal 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
51
src/cls/utils.h
Normal 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
117
src/nl-cls-add.c
Normal 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
133
src/nl-cls-delete.c
Normal 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, ¶ms, 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, ¶ms);
|
||||
}
|
||||
|
||||
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
113
src/nl-cls-list.c
Normal 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, ¶ms, 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;
|
||||
}
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"; \
|
||||
|
|
Loading…
Add table
Reference in a new issue