struct nftnl_obj_list *mnl_nft_obj_dump(struct mnl_socket *nf_sock, int family,
const char *table);
+int mnl_nft_obj_batch_add(struct nftnl_obj *nln, unsigned int flags,
+ uint32_t seqnum);
+int mnl_nft_obj_batch_del(struct nftnl_obj *nln, unsigned int flags,
+ uint32_t seqnum);
+
struct nftnl_ruleset *mnl_nft_ruleset_dump(struct mnl_socket *nf_sock,
uint32_t family);
int mnl_nft_event_listener(struct mnl_socket *nf_sock,
extern int netlink_list_objs(struct netlink_ctx *ctx, const struct handle *h,
const struct location *loc);
+extern int netlink_add_obj(struct netlink_ctx *ctx, const struct handle *h,
+ struct obj *obj, bool excl);
+extern int netlink_delete_obj(struct netlink_ctx *ctx, const struct handle *h,
+ struct location *loc, enum stmt_types type);
extern void netlink_dump_table(const struct nftnl_table *nlt);
extern void netlink_dump_chain(const struct nftnl_chain *nlc);
extern void netlink_dump_rule(const struct nftnl_rule *nlr);
extern void netlink_dump_expr(const struct nftnl_expr *nle);
extern void netlink_dump_set(const struct nftnl_set *nls);
+extern void netlink_dump_obj(struct nftnl_obj *nlo);
extern int netlink_batch_send(struct list_head *err_list);
void obj_free(struct obj *obj);
void obj_add_hash(struct obj *obj, struct table *table);
void obj_print(const struct obj *n);
-const char *obj_type_name(enum stmt_types type);
+const char *obj_type_name(uint32_t type);
/**
* enum cmd_ops - command operations
struct table *table;
struct monitor *monitor;
struct export *export;
+ struct obj *object;
};
const void *arg;
};
return chain_evaluate(ctx, cmd->chain);
case CMD_OBJ_TABLE:
return table_evaluate(ctx, cmd->table);
+ case CMD_OBJ_COUNTER:
+ case CMD_OBJ_QUOTA:
+ return 0;
default:
BUG("invalid command object type %u\n", cmd->obj);
}
case CMD_OBJ_RULE:
case CMD_OBJ_CHAIN:
case CMD_OBJ_TABLE:
+ case CMD_OBJ_COUNTER:
+ case CMD_OBJ_QUOTA:
return 0;
default:
BUG("invalid command object type %u\n", cmd->obj);
return NULL;
}
+int mnl_nft_obj_batch_add(struct nftnl_obj *nln, unsigned int flags,
+ uint32_t seqnum)
+{
+ struct nlmsghdr *nlh;
+
+ nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(batch),
+ NFT_MSG_NEWOBJ,
+ nftnl_obj_get_u32(nln, NFTNL_OBJ_FAMILY),
+ NLM_F_CREATE | flags, seqnum);
+ nftnl_obj_nlmsg_build_payload(nlh, nln);
+ mnl_nft_batch_continue();
+
+ return 0;
+}
+
+int mnl_nft_obj_batch_del(struct nftnl_obj *nln, unsigned int flags,
+ uint32_t seqnum)
+{
+ struct nlmsghdr *nlh;
+
+ nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(batch),
+ NFT_MSG_DELOBJ,
+ nftnl_obj_get_u32(nln, NFTNL_OBJ_FAMILY),
+ flags, seqnum);
+ nftnl_obj_nlmsg_build_payload(nlh, nln);
+ mnl_nft_batch_continue();
+
+ return 0;
+}
+
static int obj_cb(const struct nlmsghdr *nlh, void *data)
{
struct nftnl_obj_list *nln_list = data;
#include <libnftnl/trace.h>
#include <libnftnl/chain.h>
#include <libnftnl/expr.h>
+#include <libnftnl/object.h>
#include <libnftnl/set.h>
#include <libnftnl/udata.h>
#include <libnftnl/common.h>
return nlse;
}
+static struct nftnl_obj *
+__alloc_nftnl_obj(const struct handle *h, uint32_t type)
+{
+ struct nftnl_obj *nlo;
+
+ nlo = nftnl_obj_alloc();
+ if (nlo == NULL)
+ memory_allocation_error();
+
+ nftnl_obj_set_u32(nlo, NFTNL_OBJ_FAMILY, h->family);
+ nftnl_obj_set_str(nlo, NFTNL_OBJ_TABLE, h->table);
+ if (h->obj != NULL)
+ nftnl_obj_set_str(nlo, NFTNL_OBJ_NAME, h->obj);
+
+ nftnl_obj_set_u32(nlo, NFTNL_OBJ_TYPE, type);
+
+ return nlo;
+}
+
+static struct nftnl_obj *
+alloc_nftnl_obj(const struct handle *h, struct obj *obj)
+{
+ struct nftnl_obj *nlo;
+
+ nlo = __alloc_nftnl_obj(h, obj->type);
+
+ switch (obj->type) {
+ case NFT_OBJECT_COUNTER:
+ nftnl_obj_set_u64(nlo, NFTNL_OBJ_CTR_PKTS,
+ obj->counter.packets);
+ nftnl_obj_set_u64(nlo, NFTNL_OBJ_CTR_BYTES,
+ obj->counter.bytes);
+ break;
+ case NFT_OBJECT_QUOTA:
+ nftnl_obj_set_u64(nlo, NFTNL_OBJ_QUOTA_BYTES,
+ obj->quota.bytes);
+ nftnl_obj_set_u64(nlo, NFTNL_OBJ_QUOTA_CONSUMED,
+ obj->quota.used);
+ nftnl_obj_set_u32(nlo, NFTNL_OBJ_QUOTA_FLAGS,
+ obj->quota.flags);
+ break;
+ }
+ return nlo;
+}
+
void netlink_gen_raw_data(const mpz_t value, enum byteorder byteorder,
unsigned int len, struct nft_data_linearize *data)
{
return err;
}
+void netlink_dump_obj(struct nftnl_obj *nln)
+{
+#ifdef DEBUG
+ char buf[4096];
+
+ if (!(debug_level & DEBUG_NETLINK))
+ return;
+
+ nftnl_obj_snprintf(buf, sizeof(buf), nln, 0, 0);
+ fprintf(stdout, "%s\n", buf);
+#endif
+}
+
+int netlink_add_obj(struct netlink_ctx *ctx, const struct handle *h,
+ struct obj *obj, bool excl)
+{
+ struct nftnl_obj *nlo;
+ int err;
+
+ nlo = alloc_nftnl_obj(h, obj);
+ netlink_dump_obj(nlo);
+
+ err = mnl_nft_obj_batch_add(nlo, excl ? NLM_F_EXCL : 0, ctx->seqnum);
+ if (err < 0)
+ netlink_io_error(ctx, &obj->location, "Could not add %s: %s",
+ obj_type_name(obj->type), strerror(errno));
+ nftnl_obj_free(nlo);
+
+ return err;
+}
+
+int netlink_delete_obj(struct netlink_ctx *ctx, const struct handle *h,
+ struct location *loc, uint32_t type)
+{
+ struct nftnl_obj *nlo;
+ int err;
+
+ nlo = __alloc_nftnl_obj(h, type);
+ netlink_dump_obj(nlo);
+
+ err = mnl_nft_obj_batch_del(nlo, 0, ctx->seqnum);
+ if (err < 0)
+ netlink_io_error(ctx, loc, "Could not delete %s: %s",
+ obj_type_name(type), strerror(errno));
+ nftnl_obj_free(nlo);
+
+ return err;
+}
+
static struct obj *netlink_delinearize_obj(struct netlink_ctx *ctx,
struct nftnl_obj *nlo)
{
struct stmt *stmt;
struct expr *expr;
struct set *set;
+ struct obj *obj;
+ struct counter *counter;
+ struct quota *quota;
const struct datatype *datatype;
struct handle_spec handle_spec;
struct position_spec position_spec;
%type <handle> table_spec chain_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec
%destructor { handle_free(&$$); } table_spec chain_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec
-%type <handle> set_spec set_identifier obj_spec
-%destructor { handle_free(&$$); } set_spec set_identifier obj_spec
+%type <handle> set_spec set_identifier obj_spec obj_identifier
+%destructor { handle_free(&$$); } set_spec set_identifier obj_spec obj_identifier
%type <val> family_spec family_spec_explicit chain_policy prio_spec
%type <string> dev_spec quota_unit
%type <set> map_block_alloc map_block
%destructor { set_free($$); } map_block_alloc
+%type <obj> obj_block_alloc counter_block quota_block
+%destructor { obj_free($$); } obj_block_alloc
+
%type <list> stmt_list
%destructor { stmt_list_free($$); xfree($$); } stmt_list
%type <stmt> stmt match_stmt verdict_stmt
%type <expr> and_rhs_expr exclusive_or_rhs_expr inclusive_or_rhs_expr
%destructor { expr_free($$); } and_rhs_expr exclusive_or_rhs_expr inclusive_or_rhs_expr
+%type <obj> counter_obj quota_obj
+%destructor { obj_free($$); } counter_obj quota_obj
%type <expr> relational_expr
%destructor { expr_free($$); } relational_expr
%destructor { xfree($$); } monitor_event
%type <val> monitor_object monitor_format
+%type <counter> counter_config
+%destructor { xfree($$); } counter_config
+%type <quota> quota_config
+%destructor { xfree($$); } quota_config
+
%%
input : /* empty */
{
$$ = cmd_alloc(CMD_ADD, CMD_OBJ_SETELEM, &$2, &@$, $3);
}
+ | COUNTER obj_spec
+ {
+ struct obj *obj;
+
+ obj = obj_alloc(&@$);
+ obj->type = NFT_OBJECT_COUNTER;
+ handle_merge(&obj->handle, &$2);
+ $$ = cmd_alloc(CMD_ADD, CMD_OBJ_COUNTER, &$2, &@$, obj);
+ }
+ | COUNTER obj_spec counter_obj
+ {
+ $$ = cmd_alloc(CMD_ADD, CMD_OBJ_COUNTER, &$2, &@$, $3);
+ }
+ | QUOTA obj_spec quota_obj
+ {
+ $$ = cmd_alloc(CMD_ADD, CMD_OBJ_QUOTA, &$2, &@$, $3);
+ }
;
replace_cmd : RULE ruleid_spec rule
{
$$ = cmd_alloc(CMD_CREATE, CMD_OBJ_SETELEM, &$2, &@$, $3);
}
+ | COUNTER obj_spec
+ {
+ struct obj *obj;
+
+ obj = obj_alloc(&@$);
+ obj->type = NFT_OBJECT_COUNTER;
+ handle_merge(&obj->handle, &$2);
+ $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_COUNTER, &$2, &@$, obj);
+ }
+ | COUNTER obj_spec counter_obj
+ {
+ $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_COUNTER, &$2, &@$, $3);
+ }
+ | QUOTA obj_spec quota_obj
+ {
+ $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_QUOTA, &$2, &@$, $3);
+ }
;
insert_cmd : RULE rule_position rule
{
$$ = cmd_alloc(CMD_DELETE, CMD_OBJ_SETELEM, &$2, &@$, $3);
}
+ | COUNTER obj_spec
+ {
+ $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_COUNTER, &$2, &@$, NULL);
+ }
+ | QUOTA obj_spec
+ {
+ $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_QUOTA, &$2, &@$, NULL);
+ }
;
list_cmd : TABLE table_spec
list_add_tail(&$4->list, &$1->sets);
$$ = $1;
}
+ | table_block COUNTER obj_identifier
+ obj_block_alloc '{' counter_block '}'
+ stmt_seperator
+ {
+ $4->location = @3;
+ $4->type = NFT_OBJECT_COUNTER;
+ handle_merge(&$4->handle, &$3);
+ handle_free(&$3);
+ list_add_tail(&$4->list, &$1->objs);
+ $$ = $1;
+ }
+ | table_block QUOTA obj_identifier
+ obj_block_alloc '{' quota_block '}'
+ stmt_seperator
+ {
+ $4->location = @3;
+ $4->type = NFT_OBJECT_QUOTA;
+ handle_merge(&$4->handle, &$3);
+ handle_free(&$3);
+ list_add_tail(&$4->list, &$1->objs);
+ $$ = $1;
+ }
;
chain_block_alloc : /* empty */
}
;
+obj_block_alloc : /* empty */
+ {
+ $$ = obj_alloc(NULL);
+ }
+ ;
+
+counter_block : /* empty */ { $$ = $<obj>-1; }
+ | counter_block common_block
+ | counter_block stmt_seperator
+ | counter_block counter_config
+ {
+ $1->counter = *$2;
+ $$ = $1;
+ }
+ ;
+
+quota_block : /* empty */ { $$ = $<obj>-1; }
+ | quota_block common_block
+ | quota_block stmt_seperator
+ | quota_block quota_config
+ {
+ $1->quota = *$2;
+ $$ = $1;
+ }
+ ;
+
type_identifier : STRING { $$ = $1; }
| MARK { $$ = xstrdup("mark"); }
| DSCP { $$ = xstrdup("dscp"); }
}
;
+obj_identifier : identifier
+ {
+ memset(&$$, 0, sizeof($$));
+ $$.obj = $1;
+ }
+ ;
+
handle_spec : HANDLE NUM
{
memset(&$$, 0, sizeof($$));
| list_rhs_expr
;
+counter_config : PACKETS NUM BYTES NUM
+ {
+ struct counter *counter;
+
+ counter = xzalloc(sizeof(*counter));
+ counter->packets = $2;
+ counter->bytes = $4;
+ $$ = counter;
+ }
+ ;
+
+counter_obj : counter_config
+ {
+ $$ = obj_alloc(&@$);
+ $$->type = NFT_OBJECT_COUNTER;
+ $$->counter = *$1;
+ }
+ ;
+
+quota_config : quota_mode NUM quota_unit quota_used
+ {
+ struct error_record *erec;
+ struct quota *quota;
+ uint64_t rate;
+
+ erec = data_unit_parse(&@$, $3, &rate);
+ if (erec != NULL) {
+ erec_queue(erec, state->msgs);
+ YYERROR;
+ }
+
+ quota = xzalloc(sizeof(*quota));
+ quota->bytes = $2 * rate;
+ quota->used = $4;
+ quota->flags = $1;
+ $$ = quota;
+ }
+ ;
+
+quota_obj : quota_config
+ {
+ $$ = obj_alloc(&@$);
+ $$->type = NFT_OBJECT_QUOTA;
+ $$->quota = *$1;
+ }
+ ;
+
relational_expr : expr /* implicit */ rhs_expr
{
$$ = relational_expr_alloc(&@$, OP_IMPLICIT, $1, $2);
dst->chain = xstrdup(src->chain);
if (dst->set == NULL && src->set != NULL)
dst->set = xstrdup(src->set);
+ if (dst->obj == NULL && src->obj != NULL)
+ dst->obj = xstrdup(src->obj);
if (dst->handle.id == 0)
dst->handle = src->handle;
if (dst->position.id == 0)
case CMD_OBJ_EXPORT:
export_free(cmd->export);
break;
+ case CMD_OBJ_COUNTER:
+ case CMD_OBJ_QUOTA:
+ obj_free(cmd->object);
+ break;
default:
BUG("invalid command object type %u\n", cmd->obj);
}
bool excl)
{
struct chain *chain;
+ struct obj *obj;
struct set *set;
if (netlink_add_table(ctx, h, loc, table, excl) < 0)
excl) < 0)
return -1;
}
+ list_for_each_entry(obj, &table->objs, list) {
+ handle_merge(&obj->handle, &table->handle);
+ if (netlink_add_obj(ctx, &obj->handle, obj, excl) < 0)
+ return -1;
+ }
list_for_each_entry(set, &table->sets, list) {
handle_merge(&set->handle, &table->handle);
if (do_add_set(ctx, &set->handle, set, excl) < 0)
return do_add_set(ctx, &cmd->handle, cmd->set, excl);
case CMD_OBJ_SETELEM:
return do_add_setelems(ctx, &cmd->handle, cmd->expr, excl);
+ case CMD_OBJ_COUNTER:
+ case CMD_OBJ_QUOTA:
+ return netlink_add_obj(ctx, &cmd->handle, cmd->object, excl);
default:
BUG("invalid command object type %u\n", cmd->obj);
}
return netlink_delete_set(ctx, &cmd->handle, &cmd->location);
case CMD_OBJ_SETELEM:
return do_delete_setelems(ctx, &cmd->handle, cmd->expr);
+ case CMD_OBJ_COUNTER:
+ return netlink_delete_obj(ctx, &cmd->handle, &cmd->location,
+ NFT_OBJECT_COUNTER);
+ case CMD_OBJ_QUOTA:
+ return netlink_delete_obj(ctx, &cmd->handle, &cmd->location,
+ NFT_OBJECT_QUOTA);
default:
BUG("invalid command object type %u\n", cmd->obj);
}