|
Packit |
c5a612 |
/*
|
|
Packit |
c5a612 |
* Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
|
|
Packit |
c5a612 |
* Copyright (c) 2013 Pablo Neira Ayuso <pablo@netfilter.org>
|
|
Packit |
c5a612 |
*
|
|
Packit |
c5a612 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
c5a612 |
* it under the terms of the GNU General Public License version 2 as
|
|
Packit |
c5a612 |
* published by the Free Software Foundation.
|
|
Packit |
c5a612 |
*
|
|
Packit |
c5a612 |
* Development of this code funded by Astaro AG (http://www.astaro.com/)
|
|
Packit |
c5a612 |
*/
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
#include <linux/netfilter/nf_tables.h>
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
#include <string.h>
|
|
Packit |
c5a612 |
#include <rule.h>
|
|
Packit |
c5a612 |
#include <statement.h>
|
|
Packit |
c5a612 |
#include <expression.h>
|
|
Packit |
c5a612 |
#include <netlink.h>
|
|
Packit |
c5a612 |
#include <gmputil.h>
|
|
Packit |
c5a612 |
#include <utils.h>
|
|
Packit |
c5a612 |
#include <netinet/in.h>
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
#include <linux/netfilter.h>
|
|
Packit |
c5a612 |
#include <libnftnl/udata.h>
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct netlink_linearize_ctx {
|
|
Packit |
c5a612 |
struct nftnl_rule *nlr;
|
|
Packit |
c5a612 |
unsigned int reg_low;
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_put_register(struct nftnl_expr *nle,
|
|
Packit |
c5a612 |
uint32_t attr, uint32_t reg)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
/* Convert to 128 bit register numbers if possible for compatibility */
|
|
Packit |
c5a612 |
if (reg != NFT_REG_VERDICT) {
|
|
Packit |
c5a612 |
reg -= NFT_REG_1;
|
|
Packit |
c5a612 |
if (reg % (NFT_REG_SIZE / NFT_REG32_SIZE) == 0)
|
|
Packit |
c5a612 |
reg = NFT_REG_1 + reg / (NFT_REG_SIZE / NFT_REG32_SIZE);
|
|
Packit |
c5a612 |
else
|
|
Packit |
c5a612 |
reg += NFT_REG32_00;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, attr, reg);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static enum nft_registers __get_register(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
unsigned int size)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
unsigned int reg, n;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
n = netlink_register_space(size);
|
|
Packit |
c5a612 |
if (ctx->reg_low + n > NFT_REG_1 + NFT_REG32_15 - NFT_REG32_00 + 1)
|
|
Packit |
c5a612 |
BUG("register reg_low %u invalid\n", ctx->reg_low);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
reg = ctx->reg_low;
|
|
Packit |
c5a612 |
ctx->reg_low += n;
|
|
Packit |
c5a612 |
return reg;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void __release_register(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
unsigned int size)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
unsigned int n;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
n = netlink_register_space(size);
|
|
Packit |
c5a612 |
if (ctx->reg_low < NFT_REG_1 + n)
|
|
Packit |
c5a612 |
BUG("register reg_low %u invalid\n", ctx->reg_low);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
ctx->reg_low -= n;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static enum nft_registers get_register(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *expr)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
if (expr && expr->etype == EXPR_CONCAT)
|
|
Packit |
c5a612 |
return __get_register(ctx, expr->len);
|
|
Packit |
c5a612 |
else
|
|
Packit |
c5a612 |
return __get_register(ctx, NFT_REG_SIZE * BITS_PER_BYTE);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void release_register(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *expr)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
if (expr && expr->etype == EXPR_CONCAT)
|
|
Packit |
c5a612 |
__release_register(ctx, expr->len);
|
|
Packit |
c5a612 |
else
|
|
Packit |
c5a612 |
__release_register(ctx, NFT_REG_SIZE * BITS_PER_BYTE);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_expr(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *expr,
|
|
Packit |
c5a612 |
enum nft_registers dreg);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_concat(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *expr,
|
|
Packit |
c5a612 |
enum nft_registers dreg)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
const struct expr *i;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
list_for_each_entry(i, &expr->expressions, list) {
|
|
Packit |
c5a612 |
netlink_gen_expr(ctx, i, dreg);
|
|
Packit |
c5a612 |
dreg += netlink_register_space(i->len);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_fib(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *expr,
|
|
Packit |
c5a612 |
enum nft_registers dreg)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("fib");
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_FIB_DREG, dreg);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_FIB_RESULT, expr->fib.result);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_FIB_FLAGS, expr->fib.flags);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_hash(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *expr,
|
|
Packit |
c5a612 |
enum nft_registers dreg)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
enum nft_registers sreg;
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("hash");
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (expr->hash.expr) {
|
|
Packit |
c5a612 |
sreg = get_register(ctx, expr->hash.expr);
|
|
Packit |
c5a612 |
netlink_gen_expr(ctx, expr->hash.expr, sreg);
|
|
Packit |
c5a612 |
release_register(ctx, expr->hash.expr);
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_HASH_SREG, sreg);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_HASH_LEN,
|
|
Packit |
c5a612 |
div_round_up(expr->hash.expr->len,
|
|
Packit |
c5a612 |
BITS_PER_BYTE));
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_HASH_DREG, dreg);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_HASH_MODULUS, expr->hash.mod);
|
|
Packit |
c5a612 |
if (expr->hash.seed_set)
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_HASH_SEED, expr->hash.seed);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_HASH_OFFSET, expr->hash.offset);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_HASH_TYPE, expr->hash.type);
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_payload(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *expr,
|
|
Packit |
c5a612 |
enum nft_registers dreg)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("payload");
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_PAYLOAD_DREG, dreg);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_PAYLOAD_BASE,
|
|
Packit |
c5a612 |
expr->payload.base - 1);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_PAYLOAD_OFFSET,
|
|
Packit |
c5a612 |
expr->payload.offset / BITS_PER_BYTE);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_PAYLOAD_LEN,
|
|
Packit |
c5a612 |
div_round_up(expr->len, BITS_PER_BYTE));
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_exthdr(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *expr,
|
|
Packit |
c5a612 |
enum nft_registers dreg)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
unsigned int offset = expr->exthdr.tmpl->offset + expr->exthdr.offset;
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("exthdr");
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_EXTHDR_DREG, dreg);
|
|
Packit |
c5a612 |
nftnl_expr_set_u8(nle, NFTNL_EXPR_EXTHDR_TYPE,
|
|
Packit |
c5a612 |
expr->exthdr.desc->type);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_OFFSET, offset / BITS_PER_BYTE);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_LEN,
|
|
Packit |
c5a612 |
div_round_up(expr->len, BITS_PER_BYTE));
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_OP, expr->exthdr.op);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_FLAGS, expr->exthdr.flags);
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_meta(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *expr,
|
|
Packit |
c5a612 |
enum nft_registers dreg)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("meta");
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_META_DREG, dreg);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_META_KEY, expr->meta.key);
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_rt(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *expr,
|
|
Packit |
c5a612 |
enum nft_registers dreg)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("rt");
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_RT_DREG, dreg);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_RT_KEY, expr->rt.key);
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_socket(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *expr,
|
|
Packit |
c5a612 |
enum nft_registers dreg)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("socket");
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_SOCKET_DREG, dreg);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_SOCKET_KEY, expr->socket.key);
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_osf(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *expr,
|
|
Packit |
c5a612 |
enum nft_registers dreg)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("osf");
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_OSF_DREG, dreg);
|
|
Packit |
c5a612 |
nftnl_expr_set_u8(nle, NFTNL_EXPR_OSF_TTL, expr->osf.ttl);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_OSF_FLAGS, expr->osf.flags);
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_numgen(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *expr,
|
|
Packit |
c5a612 |
enum nft_registers dreg)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("numgen");
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_NG_DREG, dreg);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_NG_TYPE, expr->numgen.type);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_NG_MODULUS, expr->numgen.mod);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_NG_OFFSET, expr->numgen.offset);
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_ct(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *expr,
|
|
Packit |
c5a612 |
enum nft_registers dreg)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("ct");
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_CT_DREG, dreg);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_CT_KEY, expr->ct.key);
|
|
Packit |
c5a612 |
if (expr->ct.direction >= 0)
|
|
Packit |
c5a612 |
nftnl_expr_set_u8(nle, NFTNL_EXPR_CT_DIR,
|
|
Packit |
c5a612 |
expr->ct.direction);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_map(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *expr,
|
|
Packit |
c5a612 |
enum nft_registers dreg)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
enum nft_registers sreg;
|
|
Packit |
c5a612 |
int regspace = 0;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
assert(expr->mappings->etype == EXPR_SET_REF);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (dreg == NFT_REG_VERDICT)
|
|
Packit |
c5a612 |
sreg = get_register(ctx, expr->map);
|
|
Packit |
c5a612 |
else
|
|
Packit |
c5a612 |
sreg = dreg;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
/* suppress assert in netlink_gen_expr */
|
|
Packit |
c5a612 |
if (expr->map->etype == EXPR_CONCAT) {
|
|
Packit |
c5a612 |
regspace = netlink_register_space(expr->map->len);
|
|
Packit |
c5a612 |
ctx->reg_low += regspace;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
netlink_gen_expr(ctx, expr->map, sreg);
|
|
Packit |
c5a612 |
ctx->reg_low -= regspace;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("lookup");
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_LOOKUP_SREG, sreg);
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_LOOKUP_DREG, dreg);
|
|
Packit |
c5a612 |
nftnl_expr_set_str(nle, NFTNL_EXPR_LOOKUP_SET,
|
|
Packit |
c5a612 |
expr->mappings->set->handle.set.name);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_LOOKUP_SET_ID,
|
|
Packit |
c5a612 |
expr->mappings->set->handle.set_id);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (dreg == NFT_REG_VERDICT)
|
|
Packit |
c5a612 |
release_register(ctx, expr->map);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_lookup(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *expr,
|
|
Packit |
c5a612 |
enum nft_registers dreg)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
enum nft_registers sreg;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
assert(expr->right->etype == EXPR_SET_REF);
|
|
Packit |
c5a612 |
assert(dreg == NFT_REG_VERDICT);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
sreg = get_register(ctx, expr->left);
|
|
Packit |
c5a612 |
netlink_gen_expr(ctx, expr->left, sreg);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("lookup");
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_LOOKUP_SREG, sreg);
|
|
Packit |
c5a612 |
nftnl_expr_set_str(nle, NFTNL_EXPR_LOOKUP_SET,
|
|
Packit |
c5a612 |
expr->right->set->handle.set.name);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_LOOKUP_SET_ID,
|
|
Packit |
c5a612 |
expr->right->set->handle.set_id);
|
|
Packit |
c5a612 |
if (expr->op == OP_NEQ)
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_LOOKUP_FLAGS, NFT_LOOKUP_F_INV);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
release_register(ctx, expr->left);
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static enum nft_cmp_ops netlink_gen_cmp_op(enum ops op)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
switch (op) {
|
|
Packit |
c5a612 |
case OP_EQ:
|
|
Packit |
c5a612 |
case OP_IMPLICIT:
|
|
Packit |
c5a612 |
return NFT_CMP_EQ;
|
|
Packit |
c5a612 |
case OP_NEQ:
|
|
Packit |
c5a612 |
return NFT_CMP_NEQ;
|
|
Packit |
c5a612 |
case OP_LT:
|
|
Packit |
c5a612 |
return NFT_CMP_LT;
|
|
Packit |
c5a612 |
case OP_GT:
|
|
Packit |
c5a612 |
return NFT_CMP_GT;
|
|
Packit |
c5a612 |
case OP_LTE:
|
|
Packit |
c5a612 |
return NFT_CMP_LTE;
|
|
Packit |
c5a612 |
case OP_GTE:
|
|
Packit |
c5a612 |
return NFT_CMP_GTE;
|
|
Packit |
c5a612 |
default:
|
|
Packit |
c5a612 |
BUG("invalid comparison operation %u\n", op);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static struct expr *netlink_gen_prefix(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *expr,
|
|
Packit |
c5a612 |
enum nft_registers sreg)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nft_data_linearize nld, zero = {};
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
mpz_t mask;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
mpz_init(mask);
|
|
Packit |
c5a612 |
mpz_prefixmask(mask, expr->right->len, expr->right->prefix_len);
|
|
Packit |
c5a612 |
netlink_gen_raw_data(mask, expr->right->byteorder,
|
|
Packit |
c5a612 |
expr->right->len / BITS_PER_BYTE, &nld);
|
|
Packit |
c5a612 |
mpz_clear(mask);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
zero.len = nld.len;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("bitwise");
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_BITWISE_SREG, sreg);
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_BITWISE_DREG, sreg);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_BITWISE_LEN, nld.len);
|
|
Packit |
c5a612 |
nftnl_expr_set(nle, NFTNL_EXPR_BITWISE_MASK, &nld.value, nld.len);
|
|
Packit |
c5a612 |
nftnl_expr_set(nle, NFTNL_EXPR_BITWISE_XOR, &zero.value, zero.len);
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return expr->right->prefix;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_range(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *expr,
|
|
Packit |
c5a612 |
enum nft_registers dreg)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct expr *range = expr->right;
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
enum nft_registers sreg;
|
|
Packit |
c5a612 |
struct nft_data_linearize nld;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
assert(dreg == NFT_REG_VERDICT);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
sreg = get_register(ctx, expr->left);
|
|
Packit |
c5a612 |
netlink_gen_expr(ctx, expr->left, sreg);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
switch (expr->op) {
|
|
Packit |
c5a612 |
case OP_NEQ:
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("range");
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_RANGE_SREG, sreg);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_RANGE_OP, NFT_RANGE_NEQ);
|
|
Packit |
c5a612 |
netlink_gen_data(range->left, &nld);
|
|
Packit |
c5a612 |
nftnl_expr_set(nle, NFTNL_EXPR_RANGE_FROM_DATA,
|
|
Packit |
c5a612 |
nld.value, nld.len);
|
|
Packit |
c5a612 |
netlink_gen_data(range->right, &nld);
|
|
Packit |
c5a612 |
nftnl_expr_set(nle, NFTNL_EXPR_RANGE_TO_DATA,
|
|
Packit |
c5a612 |
nld.value, nld.len);
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case OP_EQ:
|
|
Packit |
c5a612 |
case OP_IMPLICIT:
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("cmp");
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_CMP_SREG, sreg);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_CMP_OP,
|
|
Packit |
c5a612 |
netlink_gen_cmp_op(OP_GTE));
|
|
Packit |
c5a612 |
netlink_gen_data(range->left, &nld);
|
|
Packit |
c5a612 |
nftnl_expr_set(nle, NFTNL_EXPR_CMP_DATA, nld.value, nld.len);
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("cmp");
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_CMP_SREG, sreg);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_CMP_OP,
|
|
Packit |
c5a612 |
netlink_gen_cmp_op(OP_LTE));
|
|
Packit |
c5a612 |
netlink_gen_data(range->right, &nld);
|
|
Packit |
c5a612 |
nftnl_expr_set(nle, NFTNL_EXPR_CMP_DATA, nld.value, nld.len);
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
default:
|
|
Packit |
c5a612 |
BUG("invalid range operation %u\n", expr->op);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
release_register(ctx, expr->left);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_flagcmp(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *expr,
|
|
Packit |
c5a612 |
enum nft_registers dreg)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
struct nft_data_linearize nld, nld2;
|
|
Packit |
c5a612 |
enum nft_registers sreg;
|
|
Packit |
c5a612 |
unsigned int len;
|
|
Packit |
c5a612 |
mpz_t zero;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
assert(dreg == NFT_REG_VERDICT);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
sreg = get_register(ctx, expr->left);
|
|
Packit |
c5a612 |
netlink_gen_expr(ctx, expr->left, sreg);
|
|
Packit |
c5a612 |
len = div_round_up(expr->left->len, BITS_PER_BYTE);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
mpz_init_set_ui(zero, 0);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
netlink_gen_raw_data(zero, expr->right->byteorder, len, &nld);
|
|
Packit |
c5a612 |
netlink_gen_data(expr->right, &nld2;;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("bitwise");
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_BITWISE_SREG, sreg);
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_BITWISE_DREG, sreg);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_BITWISE_LEN, len);
|
|
Packit |
c5a612 |
nftnl_expr_set(nle, NFTNL_EXPR_BITWISE_MASK, &nld2.value, nld2.len);
|
|
Packit |
c5a612 |
nftnl_expr_set(nle, NFTNL_EXPR_BITWISE_XOR, &nld.value, nld.len);
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("cmp");
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_CMP_SREG, sreg);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_CMP_OP, NFT_CMP_NEQ);
|
|
Packit |
c5a612 |
nftnl_expr_set(nle, NFTNL_EXPR_CMP_DATA, nld.value, nld.len);
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
mpz_clear(zero);
|
|
Packit |
c5a612 |
release_register(ctx, expr->left);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_relational(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *expr,
|
|
Packit |
c5a612 |
enum nft_registers dreg)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nft_data_linearize nld;
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
enum nft_registers sreg;
|
|
Packit |
c5a612 |
struct expr *right;
|
|
Packit |
c5a612 |
int len;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
assert(dreg == NFT_REG_VERDICT);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
switch (expr->op) {
|
|
Packit |
c5a612 |
case OP_IMPLICIT:
|
|
Packit |
c5a612 |
case OP_EQ:
|
|
Packit |
c5a612 |
case OP_NEQ:
|
|
Packit |
c5a612 |
case OP_LT:
|
|
Packit |
c5a612 |
case OP_GT:
|
|
Packit |
c5a612 |
case OP_LTE:
|
|
Packit |
c5a612 |
case OP_GTE:
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
default:
|
|
Packit |
c5a612 |
BUG("invalid relational operation %u\n", expr->op);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
switch (expr->right->etype) {
|
|
Packit |
c5a612 |
case EXPR_RANGE:
|
|
Packit |
c5a612 |
return netlink_gen_range(ctx, expr, dreg);
|
|
Packit |
c5a612 |
case EXPR_SET:
|
|
Packit |
c5a612 |
case EXPR_SET_REF:
|
|
Packit |
c5a612 |
return netlink_gen_lookup(ctx, expr, dreg);
|
|
Packit |
c5a612 |
case EXPR_LIST:
|
|
Packit |
c5a612 |
return netlink_gen_flagcmp(ctx, expr, dreg);
|
|
Packit |
c5a612 |
case EXPR_PREFIX:
|
|
Packit |
c5a612 |
sreg = get_register(ctx, expr->left);
|
|
Packit |
c5a612 |
if (expr_basetype(expr->left)->type != TYPE_STRING) {
|
|
Packit |
c5a612 |
len = div_round_up(expr->right->len, BITS_PER_BYTE);
|
|
Packit |
c5a612 |
netlink_gen_expr(ctx, expr->left, sreg);
|
|
Packit |
c5a612 |
right = netlink_gen_prefix(ctx, expr, sreg);
|
|
Packit |
c5a612 |
} else {
|
|
Packit |
c5a612 |
len = div_round_up(expr->right->prefix_len, BITS_PER_BYTE);
|
|
Packit |
c5a612 |
right = expr->right->prefix;
|
|
Packit |
c5a612 |
expr->left->len = expr->right->prefix_len;
|
|
Packit |
c5a612 |
netlink_gen_expr(ctx, expr->left, sreg);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
default:
|
|
Packit |
c5a612 |
if (expr->op == OP_IMPLICIT &&
|
|
Packit |
c5a612 |
expr->right->dtype->basetype != NULL &&
|
|
Packit |
c5a612 |
expr->right->dtype->basetype->type == TYPE_BITMASK)
|
|
Packit |
c5a612 |
return netlink_gen_flagcmp(ctx, expr, dreg);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
sreg = get_register(ctx, expr->left);
|
|
Packit |
c5a612 |
len = div_round_up(expr->right->len, BITS_PER_BYTE);
|
|
Packit |
c5a612 |
right = expr->right;
|
|
Packit |
c5a612 |
netlink_gen_expr(ctx, expr->left, sreg);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("cmp");
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_CMP_SREG, sreg);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_CMP_OP,
|
|
Packit |
c5a612 |
netlink_gen_cmp_op(expr->op));
|
|
Packit |
c5a612 |
netlink_gen_data(right, &nld);
|
|
Packit |
c5a612 |
nftnl_expr_set(nle, NFTNL_EXPR_CMP_DATA, nld.value, len);
|
|
Packit |
c5a612 |
release_register(ctx, expr->left);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void combine_binop(mpz_t mask, mpz_t xor, const mpz_t m, const mpz_t x)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
/* xor = x ^ (xor & m) */
|
|
Packit |
c5a612 |
mpz_and(xor, xor, m);
|
|
Packit |
c5a612 |
mpz_xor(xor, x, xor);
|
|
Packit |
c5a612 |
/* mask &= m */
|
|
Packit |
c5a612 |
mpz_and(mask, mask, m);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_binop(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *expr,
|
|
Packit |
c5a612 |
enum nft_registers dreg)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
struct nft_data_linearize nld;
|
|
Packit |
c5a612 |
struct expr *left, *i;
|
|
Packit |
c5a612 |
struct expr *binops[16];
|
|
Packit |
c5a612 |
mpz_t mask, xor, val, tmp;
|
|
Packit |
c5a612 |
unsigned int len;
|
|
Packit |
c5a612 |
int n = 0;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
mpz_init(mask);
|
|
Packit |
c5a612 |
mpz_init(xor);
|
|
Packit |
c5a612 |
mpz_init(val);
|
|
Packit |
c5a612 |
mpz_init(tmp);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
binops[n++] = left = (void *)expr;
|
|
Packit |
c5a612 |
while (left->etype == EXPR_BINOP && left->left != NULL)
|
|
Packit |
c5a612 |
binops[n++] = left = left->left;
|
|
Packit |
c5a612 |
n--;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
netlink_gen_expr(ctx, binops[n--], dreg);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
mpz_bitmask(mask, expr->len);
|
|
Packit |
c5a612 |
mpz_set_ui(xor, 0);
|
|
Packit |
c5a612 |
for (; n >= 0; n--) {
|
|
Packit |
c5a612 |
i = binops[n];
|
|
Packit |
c5a612 |
mpz_set(val, i->right->value);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
switch (i->op) {
|
|
Packit |
c5a612 |
case OP_AND:
|
|
Packit |
c5a612 |
mpz_set_ui(tmp, 0);
|
|
Packit |
c5a612 |
combine_binop(mask, xor, val, tmp);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case OP_OR:
|
|
Packit |
c5a612 |
mpz_com(tmp, val);
|
|
Packit |
c5a612 |
combine_binop(mask, xor, tmp, val);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case OP_XOR:
|
|
Packit |
c5a612 |
mpz_bitmask(tmp, expr->len);
|
|
Packit |
c5a612 |
combine_binop(mask, xor, tmp, val);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
default:
|
|
Packit |
c5a612 |
BUG("invalid binary operation %u\n", i->op);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
len = div_round_up(expr->len, BITS_PER_BYTE);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("bitwise");
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_BITWISE_SREG, dreg);
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_BITWISE_DREG, dreg);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_BITWISE_LEN, len);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
netlink_gen_raw_data(mask, expr->byteorder, len, &nld);
|
|
Packit |
c5a612 |
nftnl_expr_set(nle, NFTNL_EXPR_BITWISE_MASK, nld.value, nld.len);
|
|
Packit |
c5a612 |
netlink_gen_raw_data(xor, expr->byteorder, len, &nld);
|
|
Packit |
c5a612 |
nftnl_expr_set(nle, NFTNL_EXPR_BITWISE_XOR, nld.value, nld.len);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
mpz_clear(tmp);
|
|
Packit |
c5a612 |
mpz_clear(val);
|
|
Packit |
c5a612 |
mpz_clear(xor);
|
|
Packit |
c5a612 |
mpz_clear(mask);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static enum nft_byteorder_ops netlink_gen_unary_op(enum ops op)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
switch (op) {
|
|
Packit |
c5a612 |
case OP_HTON:
|
|
Packit |
c5a612 |
return NFT_BYTEORDER_HTON;
|
|
Packit |
c5a612 |
case OP_NTOH:
|
|
Packit |
c5a612 |
return NFT_BYTEORDER_NTOH;
|
|
Packit |
c5a612 |
default:
|
|
Packit |
c5a612 |
BUG("invalid unary operation %u\n", op);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_unary(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *expr,
|
|
Packit |
c5a612 |
enum nft_registers dreg)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
int byte_size;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if ((expr->arg->len % 64) == 0)
|
|
Packit |
c5a612 |
byte_size = 8;
|
|
Packit |
c5a612 |
else if ((expr->arg->len % 32) == 0)
|
|
Packit |
c5a612 |
byte_size = 4;
|
|
Packit |
c5a612 |
else
|
|
Packit |
c5a612 |
byte_size = 2;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
netlink_gen_expr(ctx, expr->arg, dreg);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("byteorder");
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_BYTEORDER_SREG, dreg);
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_BYTEORDER_DREG, dreg);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_BYTEORDER_LEN,
|
|
Packit |
c5a612 |
expr->len / BITS_PER_BYTE);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_BYTEORDER_SIZE,
|
|
Packit |
c5a612 |
byte_size);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_BYTEORDER_OP,
|
|
Packit |
c5a612 |
netlink_gen_unary_op(expr->op));
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_immediate(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *expr,
|
|
Packit |
c5a612 |
enum nft_registers dreg)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
struct nft_data_linearize nld;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("immediate");
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_IMM_DREG, dreg);
|
|
Packit |
c5a612 |
netlink_gen_data(expr, &nld);
|
|
Packit |
c5a612 |
switch (expr->etype) {
|
|
Packit |
c5a612 |
case EXPR_VALUE:
|
|
Packit |
c5a612 |
nftnl_expr_set(nle, NFTNL_EXPR_IMM_DATA, nld.value, nld.len);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case EXPR_VERDICT:
|
|
Packit |
c5a612 |
if ((expr->chain != NULL) &&
|
|
Packit |
c5a612 |
!nftnl_expr_is_set(nle, NFTNL_EXPR_IMM_CHAIN)) {
|
|
Packit |
c5a612 |
nftnl_expr_set_str(nle, NFTNL_EXPR_IMM_CHAIN,
|
|
Packit |
c5a612 |
nld.chain);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_IMM_VERDICT, nld.verdict);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
default:
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_xfrm(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *expr,
|
|
Packit |
c5a612 |
enum nft_registers dreg)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("xfrm");
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_XFRM_DREG, dreg);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_XFRM_KEY, expr->xfrm.key);
|
|
Packit |
c5a612 |
nftnl_expr_set_u8(nle, NFTNL_EXPR_XFRM_DIR, expr->xfrm.direction);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_XFRM_SPNUM, expr->xfrm.spnum);
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_expr(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct expr *expr,
|
|
Packit |
c5a612 |
enum nft_registers dreg)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
assert(dreg < ctx->reg_low);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
switch (expr->etype) {
|
|
Packit |
c5a612 |
case EXPR_VERDICT:
|
|
Packit |
c5a612 |
case EXPR_VALUE:
|
|
Packit |
c5a612 |
return netlink_gen_immediate(ctx, expr, dreg);
|
|
Packit |
c5a612 |
case EXPR_UNARY:
|
|
Packit |
c5a612 |
return netlink_gen_unary(ctx, expr, dreg);
|
|
Packit |
c5a612 |
case EXPR_BINOP:
|
|
Packit |
c5a612 |
return netlink_gen_binop(ctx, expr, dreg);
|
|
Packit |
c5a612 |
case EXPR_RELATIONAL:
|
|
Packit |
c5a612 |
return netlink_gen_relational(ctx, expr, dreg);
|
|
Packit |
c5a612 |
case EXPR_CONCAT:
|
|
Packit |
c5a612 |
return netlink_gen_concat(ctx, expr, dreg);
|
|
Packit |
c5a612 |
case EXPR_MAP:
|
|
Packit |
c5a612 |
return netlink_gen_map(ctx, expr, dreg);
|
|
Packit |
c5a612 |
case EXPR_PAYLOAD:
|
|
Packit |
c5a612 |
return netlink_gen_payload(ctx, expr, dreg);
|
|
Packit |
c5a612 |
case EXPR_EXTHDR:
|
|
Packit |
c5a612 |
return netlink_gen_exthdr(ctx, expr, dreg);
|
|
Packit |
c5a612 |
case EXPR_META:
|
|
Packit |
c5a612 |
return netlink_gen_meta(ctx, expr, dreg);
|
|
Packit |
c5a612 |
case EXPR_RT:
|
|
Packit |
c5a612 |
return netlink_gen_rt(ctx, expr, dreg);
|
|
Packit |
c5a612 |
case EXPR_CT:
|
|
Packit |
c5a612 |
return netlink_gen_ct(ctx, expr, dreg);
|
|
Packit |
c5a612 |
case EXPR_SET_ELEM:
|
|
Packit |
c5a612 |
return netlink_gen_expr(ctx, expr->key, dreg);
|
|
Packit |
c5a612 |
case EXPR_NUMGEN:
|
|
Packit |
c5a612 |
return netlink_gen_numgen(ctx, expr, dreg);
|
|
Packit |
c5a612 |
case EXPR_HASH:
|
|
Packit |
c5a612 |
return netlink_gen_hash(ctx, expr, dreg);
|
|
Packit |
c5a612 |
case EXPR_FIB:
|
|
Packit |
c5a612 |
return netlink_gen_fib(ctx, expr, dreg);
|
|
Packit |
c5a612 |
case EXPR_SOCKET:
|
|
Packit |
c5a612 |
return netlink_gen_socket(ctx, expr, dreg);
|
|
Packit |
c5a612 |
case EXPR_OSF:
|
|
Packit |
c5a612 |
return netlink_gen_osf(ctx, expr, dreg);
|
|
Packit |
c5a612 |
case EXPR_XFRM:
|
|
Packit |
c5a612 |
return netlink_gen_xfrm(ctx, expr, dreg);
|
|
Packit |
c5a612 |
default:
|
|
Packit |
c5a612 |
BUG("unknown expression type %s\n", expr_name(expr));
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_objref_stmt(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct expr *expr = stmt->objref.expr;
|
|
Packit |
c5a612 |
struct nft_data_linearize nld;
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
uint32_t sreg_key;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("objref");
|
|
Packit |
c5a612 |
switch (expr->etype) {
|
|
Packit |
c5a612 |
case EXPR_MAP:
|
|
Packit |
c5a612 |
sreg_key = get_register(ctx, expr->map);
|
|
Packit |
c5a612 |
netlink_gen_expr(ctx, expr->map, sreg_key);
|
|
Packit |
c5a612 |
release_register(ctx, expr->map);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_OBJREF_SET_SREG, sreg_key);
|
|
Packit |
c5a612 |
nftnl_expr_set_str(nle, NFTNL_EXPR_OBJREF_SET_NAME,
|
|
Packit |
c5a612 |
expr->mappings->set->handle.set.name);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_OBJREF_SET_ID,
|
|
Packit |
c5a612 |
expr->mappings->set->handle.set_id);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case EXPR_VALUE:
|
|
Packit |
c5a612 |
netlink_gen_data(stmt->objref.expr, &nld);
|
|
Packit |
c5a612 |
nftnl_expr_set(nle, NFTNL_EXPR_OBJREF_IMM_NAME,
|
|
Packit |
c5a612 |
nld.value, nld.len);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_OBJREF_IMM_TYPE,
|
|
Packit |
c5a612 |
stmt->objref.type);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
default:
|
|
Packit |
c5a612 |
BUG("unsupported expression %u\n", expr->etype);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static struct nftnl_expr *
|
|
Packit |
c5a612 |
netlink_gen_connlimit_stmt(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("connlimit");
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_CONNLIMIT_COUNT,
|
|
Packit |
c5a612 |
stmt->connlimit.count);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_CONNLIMIT_FLAGS,
|
|
Packit |
c5a612 |
stmt->connlimit.flags);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return nle;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static struct nftnl_expr *
|
|
Packit |
c5a612 |
netlink_gen_counter_stmt(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("counter");
|
|
Packit |
c5a612 |
if (stmt->counter.packets) {
|
|
Packit |
c5a612 |
nftnl_expr_set_u64(nle, NFTNL_EXPR_CTR_PACKETS,
|
|
Packit |
c5a612 |
stmt->counter.packets);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
if (stmt->counter.bytes) {
|
|
Packit |
c5a612 |
nftnl_expr_set_u64(nle, NFTNL_EXPR_CTR_BYTES,
|
|
Packit |
c5a612 |
stmt->counter.bytes);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return nle;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static struct nftnl_expr *
|
|
Packit |
c5a612 |
netlink_gen_limit_stmt(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("limit");
|
|
Packit |
c5a612 |
nftnl_expr_set_u64(nle, NFTNL_EXPR_LIMIT_RATE, stmt->limit.rate);
|
|
Packit |
c5a612 |
nftnl_expr_set_u64(nle, NFTNL_EXPR_LIMIT_UNIT, stmt->limit.unit);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_LIMIT_TYPE, stmt->limit.type);
|
|
Packit |
c5a612 |
if (stmt->limit.burst > 0)
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_LIMIT_BURST,
|
|
Packit |
c5a612 |
stmt->limit.burst);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_LIMIT_FLAGS, stmt->limit.flags);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return nle;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static struct nftnl_expr *
|
|
Packit |
c5a612 |
netlink_gen_quota_stmt(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("quota");
|
|
Packit |
c5a612 |
nftnl_expr_set_u64(nle, NFTNL_EXPR_QUOTA_BYTES, stmt->quota.bytes);
|
|
Packit |
c5a612 |
nftnl_expr_set_u64(nle, NFTNL_EXPR_QUOTA_CONSUMED, stmt->quota.used);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_QUOTA_FLAGS, stmt->quota.flags);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return nle;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static struct nftnl_expr *
|
|
Packit |
c5a612 |
netlink_gen_stmt_stateful(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
switch (stmt->ops->type) {
|
|
Packit |
c5a612 |
case STMT_CONNLIMIT:
|
|
Packit |
c5a612 |
return netlink_gen_connlimit_stmt(ctx, stmt);
|
|
Packit |
c5a612 |
case STMT_COUNTER:
|
|
Packit |
c5a612 |
return netlink_gen_counter_stmt(ctx, stmt);
|
|
Packit |
c5a612 |
case STMT_LIMIT:
|
|
Packit |
c5a612 |
return netlink_gen_limit_stmt(ctx, stmt);
|
|
Packit |
c5a612 |
case STMT_QUOTA:
|
|
Packit |
c5a612 |
return netlink_gen_quota_stmt(ctx, stmt);
|
|
Packit |
c5a612 |
default:
|
|
Packit |
c5a612 |
BUG("unknown stateful statement type %s\n", stmt->ops->name);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_verdict_stmt(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
return netlink_gen_expr(ctx, stmt->expr, NFT_REG_VERDICT);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static bool payload_needs_l4csum_update_pseudohdr(const struct expr *expr,
|
|
Packit |
c5a612 |
const struct proto_desc *desc)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
int i;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
for (i = 0; i < PROTO_HDRS_MAX; i++) {
|
|
Packit |
c5a612 |
if (payload_hdr_field(expr) == desc->pseudohdr[i])
|
|
Packit |
c5a612 |
return true;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
return false;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_exthdr_stmt(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
const struct expr *expr;
|
|
Packit |
c5a612 |
enum nft_registers sreg;
|
|
Packit |
c5a612 |
unsigned int offset;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
sreg = get_register(ctx, stmt->exthdr.val);
|
|
Packit |
c5a612 |
netlink_gen_expr(ctx, stmt->exthdr.val, sreg);
|
|
Packit |
c5a612 |
release_register(ctx, stmt->exthdr.val);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
expr = stmt->exthdr.expr;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
offset = expr->exthdr.tmpl->offset + expr->exthdr.offset;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("exthdr");
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_EXTHDR_SREG, sreg);
|
|
Packit |
c5a612 |
nftnl_expr_set_u8(nle, NFTNL_EXPR_EXTHDR_TYPE,
|
|
Packit |
c5a612 |
expr->exthdr.desc->type);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_OFFSET, offset / BITS_PER_BYTE);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_LEN,
|
|
Packit |
c5a612 |
div_round_up(expr->len, BITS_PER_BYTE));
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_OP, expr->exthdr.op);
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_payload_stmt(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
const struct proto_desc *desc;
|
|
Packit |
c5a612 |
const struct expr *expr;
|
|
Packit |
c5a612 |
enum nft_registers sreg;
|
|
Packit |
c5a612 |
unsigned int csum_off;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
sreg = get_register(ctx, stmt->payload.val);
|
|
Packit |
c5a612 |
netlink_gen_expr(ctx, stmt->payload.val, sreg);
|
|
Packit |
c5a612 |
release_register(ctx, stmt->payload.val);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
expr = stmt->payload.expr;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
csum_off = 0;
|
|
Packit |
c5a612 |
desc = expr->payload.desc;
|
|
Packit |
c5a612 |
if (desc != NULL && desc->checksum_key)
|
|
Packit |
c5a612 |
csum_off = desc->templates[desc->checksum_key].offset;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("payload");
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_PAYLOAD_SREG, sreg);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_PAYLOAD_BASE,
|
|
Packit |
c5a612 |
expr->payload.base - 1);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_PAYLOAD_OFFSET,
|
|
Packit |
c5a612 |
expr->payload.offset / BITS_PER_BYTE);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_PAYLOAD_LEN,
|
|
Packit |
c5a612 |
expr->len / BITS_PER_BYTE);
|
|
Packit |
c5a612 |
if (csum_off) {
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_PAYLOAD_CSUM_TYPE,
|
|
Packit |
c5a612 |
NFT_PAYLOAD_CSUM_INET);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_PAYLOAD_CSUM_OFFSET,
|
|
Packit |
c5a612 |
csum_off / BITS_PER_BYTE);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
if (expr->payload.base == PROTO_BASE_NETWORK_HDR &&
|
|
Packit |
c5a612 |
payload_needs_l4csum_update_pseudohdr(expr, desc))
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_PAYLOAD_FLAGS,
|
|
Packit |
c5a612 |
NFT_PAYLOAD_L4CSUM_PSEUDOHDR);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_meta_stmt(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
enum nft_registers sreg;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
sreg = get_register(ctx, stmt->meta.expr);
|
|
Packit |
c5a612 |
netlink_gen_expr(ctx, stmt->meta.expr, sreg);
|
|
Packit |
c5a612 |
release_register(ctx, stmt->meta.expr);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("meta");
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_META_SREG, sreg);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_META_KEY, stmt->meta.key);
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_log_stmt(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("log");
|
|
Packit |
c5a612 |
if (stmt->log.prefix != NULL) {
|
|
Packit |
c5a612 |
nftnl_expr_set_str(nle, NFTNL_EXPR_LOG_PREFIX,
|
|
Packit |
c5a612 |
stmt->log.prefix);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
if (stmt->log.flags & STMT_LOG_GROUP) {
|
|
Packit |
c5a612 |
nftnl_expr_set_u16(nle, NFTNL_EXPR_LOG_GROUP, stmt->log.group);
|
|
Packit |
c5a612 |
if (stmt->log.flags & STMT_LOG_SNAPLEN)
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_LOG_SNAPLEN,
|
|
Packit |
c5a612 |
stmt->log.snaplen);
|
|
Packit |
c5a612 |
if (stmt->log.flags & STMT_LOG_QTHRESHOLD)
|
|
Packit |
c5a612 |
nftnl_expr_set_u16(nle, NFTNL_EXPR_LOG_QTHRESHOLD,
|
|
Packit |
c5a612 |
stmt->log.qthreshold);
|
|
Packit |
c5a612 |
} else {
|
|
Packit |
c5a612 |
if (stmt->log.flags & STMT_LOG_LEVEL)
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_LOG_LEVEL,
|
|
Packit |
c5a612 |
stmt->log.level);
|
|
Packit |
c5a612 |
if (stmt->log.logflags)
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_LOG_FLAGS,
|
|
Packit |
c5a612 |
stmt->log.logflags);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_reject_stmt(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("reject");
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_REJECT_TYPE, stmt->reject.type);
|
|
Packit |
c5a612 |
if (stmt->reject.icmp_code != -1)
|
|
Packit |
c5a612 |
nftnl_expr_set_u8(nle, NFTNL_EXPR_REJECT_CODE,
|
|
Packit |
c5a612 |
stmt->reject.icmp_code);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_nat_stmt(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
enum nft_registers amin_reg, amax_reg;
|
|
Packit |
c5a612 |
enum nft_registers pmin_reg, pmax_reg;
|
|
Packit |
c5a612 |
int registers = 0;
|
|
Packit |
c5a612 |
int family;
|
|
Packit |
c5a612 |
int nftnl_flag_attr;
|
|
Packit |
c5a612 |
int nftnl_reg_pmin, nftnl_reg_pmax;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
switch (stmt->nat.type) {
|
|
Packit |
c5a612 |
case NFT_NAT_SNAT:
|
|
Packit |
c5a612 |
case NFT_NAT_DNAT:
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("nat");
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_NAT_TYPE, stmt->nat.type);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
family = stmt->nat.family;
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_NAT_FAMILY, family);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_flag_attr = NFTNL_EXPR_NAT_FLAGS;
|
|
Packit |
c5a612 |
nftnl_reg_pmin = NFTNL_EXPR_NAT_REG_PROTO_MIN;
|
|
Packit |
c5a612 |
nftnl_reg_pmax = NFTNL_EXPR_NAT_REG_PROTO_MAX;
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFT_NAT_MASQ:
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("masq");
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_flag_attr = NFTNL_EXPR_MASQ_FLAGS;
|
|
Packit |
c5a612 |
nftnl_reg_pmin = NFTNL_EXPR_MASQ_REG_PROTO_MIN;
|
|
Packit |
c5a612 |
nftnl_reg_pmax = NFTNL_EXPR_MASQ_REG_PROTO_MAX;
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFT_NAT_REDIR:
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("redir");
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_flag_attr = NFTNL_EXPR_REDIR_FLAGS;
|
|
Packit |
c5a612 |
nftnl_reg_pmin = NFTNL_EXPR_REDIR_REG_PROTO_MIN;
|
|
Packit |
c5a612 |
nftnl_reg_pmax = NFTNL_EXPR_REDIR_REG_PROTO_MAX;
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
default:
|
|
Packit |
c5a612 |
BUG("unknown nat type %d\n", stmt->nat.type);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (stmt->nat.flags != 0)
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, nftnl_flag_attr, stmt->nat.flags);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (stmt->nat.addr) {
|
|
Packit |
c5a612 |
amin_reg = get_register(ctx, NULL);
|
|
Packit |
c5a612 |
registers++;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (stmt->nat.addr->etype == EXPR_RANGE) {
|
|
Packit |
c5a612 |
amax_reg = get_register(ctx, NULL);
|
|
Packit |
c5a612 |
registers++;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
netlink_gen_expr(ctx, stmt->nat.addr->left, amin_reg);
|
|
Packit |
c5a612 |
netlink_gen_expr(ctx, stmt->nat.addr->right, amax_reg);
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_NAT_REG_ADDR_MIN,
|
|
Packit |
c5a612 |
amin_reg);
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_NAT_REG_ADDR_MAX,
|
|
Packit |
c5a612 |
amax_reg);
|
|
Packit |
c5a612 |
} else {
|
|
Packit |
c5a612 |
netlink_gen_expr(ctx, stmt->nat.addr, amin_reg);
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_NAT_REG_ADDR_MIN,
|
|
Packit |
c5a612 |
amin_reg);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (stmt->nat.proto) {
|
|
Packit |
c5a612 |
pmin_reg = get_register(ctx, NULL);
|
|
Packit |
c5a612 |
registers++;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (stmt->nat.proto->etype == EXPR_RANGE) {
|
|
Packit |
c5a612 |
pmax_reg = get_register(ctx, NULL);
|
|
Packit |
c5a612 |
registers++;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
netlink_gen_expr(ctx, stmt->nat.proto->left, pmin_reg);
|
|
Packit |
c5a612 |
netlink_gen_expr(ctx, stmt->nat.proto->right, pmax_reg);
|
|
Packit |
c5a612 |
netlink_put_register(nle, nftnl_reg_pmin, pmin_reg);
|
|
Packit |
c5a612 |
netlink_put_register(nle, nftnl_reg_pmax, pmax_reg);
|
|
Packit |
c5a612 |
} else {
|
|
Packit |
c5a612 |
netlink_gen_expr(ctx, stmt->nat.proto, pmin_reg);
|
|
Packit |
c5a612 |
netlink_put_register(nle, nftnl_reg_pmin, pmin_reg);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
while (registers > 0) {
|
|
Packit |
c5a612 |
release_register(ctx, NULL);
|
|
Packit |
c5a612 |
registers--;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_tproxy_stmt(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
enum nft_registers addr_reg;
|
|
Packit |
c5a612 |
enum nft_registers port_reg;
|
|
Packit |
c5a612 |
int registers = 0;
|
|
Packit |
c5a612 |
const int family = stmt->tproxy.family;
|
|
Packit |
c5a612 |
int nftnl_reg_port;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("tproxy");
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_TPROXY_FAMILY, family);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_reg_port = NFTNL_EXPR_TPROXY_REG_PORT;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (stmt->tproxy.addr) {
|
|
Packit |
c5a612 |
addr_reg = get_register(ctx, NULL);
|
|
Packit |
c5a612 |
registers++;
|
|
Packit |
c5a612 |
netlink_gen_expr(ctx, stmt->tproxy.addr, addr_reg);
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_TPROXY_REG_ADDR,
|
|
Packit |
c5a612 |
addr_reg);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (stmt->tproxy.port) {
|
|
Packit |
c5a612 |
port_reg = get_register(ctx, NULL);
|
|
Packit |
c5a612 |
registers++;
|
|
Packit |
c5a612 |
netlink_gen_expr(ctx, stmt->tproxy.port, port_reg);
|
|
Packit |
c5a612 |
netlink_put_register(nle, nftnl_reg_port, port_reg);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
while (registers > 0) {
|
|
Packit |
c5a612 |
release_register(ctx, NULL);
|
|
Packit |
c5a612 |
registers--;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_synproxy_stmt(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("synproxy");
|
|
Packit |
c5a612 |
nftnl_expr_set_u16(nle, NFTNL_EXPR_SYNPROXY_MSS, stmt->synproxy.mss);
|
|
Packit |
c5a612 |
nftnl_expr_set_u8(nle, NFTNL_EXPR_SYNPROXY_WSCALE,
|
|
Packit |
c5a612 |
stmt->synproxy.wscale);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_SYNPROXY_FLAGS,
|
|
Packit |
c5a612 |
stmt->synproxy.flags);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_dup_stmt(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
enum nft_registers sreg1, sreg2;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("dup");
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (stmt->dup.to != NULL) {
|
|
Packit |
c5a612 |
if (stmt->dup.to->dtype == &ifindex_type) {
|
|
Packit |
c5a612 |
sreg1 = get_register(ctx, stmt->dup.to);
|
|
Packit |
c5a612 |
netlink_gen_expr(ctx, stmt->dup.to, sreg1);
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_DUP_SREG_DEV, sreg1);
|
|
Packit |
c5a612 |
} else {
|
|
Packit |
c5a612 |
sreg1 = get_register(ctx, stmt->dup.to);
|
|
Packit |
c5a612 |
netlink_gen_expr(ctx, stmt->dup.to, sreg1);
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_DUP_SREG_ADDR, sreg1);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
if (stmt->dup.dev != NULL) {
|
|
Packit |
c5a612 |
sreg2 = get_register(ctx, stmt->dup.dev);
|
|
Packit |
c5a612 |
netlink_gen_expr(ctx, stmt->dup.dev, sreg2);
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_DUP_SREG_DEV, sreg2);
|
|
Packit |
c5a612 |
release_register(ctx, stmt->dup.dev);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
if (stmt->dup.to != NULL)
|
|
Packit |
c5a612 |
release_register(ctx, stmt->dup.to);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_fwd_stmt(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
enum nft_registers sreg1, sreg2;
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("fwd");
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
sreg1 = get_register(ctx, stmt->fwd.dev);
|
|
Packit |
c5a612 |
netlink_gen_expr(ctx, stmt->fwd.dev, sreg1);
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_FWD_SREG_DEV, sreg1);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (stmt->fwd.addr != NULL) {
|
|
Packit |
c5a612 |
sreg2 = get_register(ctx, stmt->fwd.addr);
|
|
Packit |
c5a612 |
netlink_gen_expr(ctx, stmt->fwd.addr, sreg2);
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_FWD_SREG_ADDR, sreg2);
|
|
Packit |
c5a612 |
release_register(ctx, stmt->fwd.addr);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
release_register(ctx, stmt->fwd.dev);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (stmt->fwd.family)
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_FWD_NFPROTO,
|
|
Packit |
c5a612 |
stmt->fwd.family);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_queue_stmt(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
uint16_t total_queues;
|
|
Packit |
c5a612 |
mpz_t low, high;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
mpz_init2(low, 16);
|
|
Packit |
c5a612 |
mpz_init2(high, 16);
|
|
Packit |
c5a612 |
if (stmt->queue.queue != NULL) {
|
|
Packit |
c5a612 |
range_expr_value_low(low, stmt->queue.queue);
|
|
Packit |
c5a612 |
range_expr_value_high(high, stmt->queue.queue);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
total_queues = mpz_get_uint16(high) - mpz_get_uint16(low) + 1;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("queue");
|
|
Packit |
c5a612 |
nftnl_expr_set_u16(nle, NFTNL_EXPR_QUEUE_NUM, mpz_get_uint16(low));
|
|
Packit |
c5a612 |
nftnl_expr_set_u16(nle, NFTNL_EXPR_QUEUE_TOTAL, total_queues);
|
|
Packit |
c5a612 |
if (stmt->queue.flags)
|
|
Packit |
c5a612 |
nftnl_expr_set_u16(nle, NFTNL_EXPR_QUEUE_FLAGS,
|
|
Packit |
c5a612 |
stmt->queue.flags);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
mpz_clear(low);
|
|
Packit |
c5a612 |
mpz_clear(high);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_ct_stmt(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
enum nft_registers sreg;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
sreg = get_register(ctx, stmt->ct.expr);
|
|
Packit |
c5a612 |
netlink_gen_expr(ctx, stmt->ct.expr, sreg);
|
|
Packit |
c5a612 |
release_register(ctx, stmt->ct.expr);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("ct");
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_CT_SREG, sreg);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_CT_KEY, stmt->ct.key);
|
|
Packit |
c5a612 |
if (stmt->ct.direction >= 0)
|
|
Packit |
c5a612 |
nftnl_expr_set_u8(nle, NFTNL_EXPR_CT_DIR,
|
|
Packit |
c5a612 |
stmt->ct.direction);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_notrack_stmt(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("notrack");
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_flow_offload_stmt(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("flow_offload");
|
|
Packit |
c5a612 |
nftnl_expr_set_str(nle, NFTNL_EXPR_FLOW_TABLE_NAME,
|
|
Packit |
c5a612 |
stmt->flow.table_name);
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_set_stmt(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct set *set = stmt->meter.set->set;
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
enum nft_registers sreg_key;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
sreg_key = get_register(ctx, stmt->set.key->key);
|
|
Packit |
c5a612 |
netlink_gen_expr(ctx, stmt->set.key->key, sreg_key);
|
|
Packit |
c5a612 |
release_register(ctx, stmt->set.key->key);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("dynset");
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_DYNSET_SREG_KEY, sreg_key);
|
|
Packit |
c5a612 |
if (stmt->set.key->timeout > 0)
|
|
Packit |
c5a612 |
nftnl_expr_set_u64(nle, NFTNL_EXPR_DYNSET_TIMEOUT,
|
|
Packit |
c5a612 |
stmt->set.key->timeout);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_DYNSET_OP, stmt->set.op);
|
|
Packit |
c5a612 |
nftnl_expr_set_str(nle, NFTNL_EXPR_DYNSET_SET_NAME, set->handle.set.name);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_DYNSET_SET_ID, set->handle.set_id);
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (stmt->set.stmt)
|
|
Packit |
c5a612 |
nftnl_expr_set(nle, NFTNL_EXPR_DYNSET_EXPR,
|
|
Packit |
c5a612 |
netlink_gen_stmt_stateful(ctx, stmt->set.stmt), 0);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_map_stmt(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct set *set = stmt->map.set->set;
|
|
Packit |
c5a612 |
enum nft_registers sreg_data;
|
|
Packit |
c5a612 |
enum nft_registers sreg_key;
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
sreg_key = get_register(ctx, stmt->map.key);
|
|
Packit |
c5a612 |
netlink_gen_expr(ctx, stmt->map.key, sreg_key);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
sreg_data = get_register(ctx, stmt->map.data);
|
|
Packit |
c5a612 |
netlink_gen_expr(ctx, stmt->map.data, sreg_data);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
release_register(ctx, stmt->map.key);
|
|
Packit |
c5a612 |
release_register(ctx, stmt->map.data);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("dynset");
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_DYNSET_SREG_KEY, sreg_key);
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_DYNSET_SREG_DATA, sreg_data);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_DYNSET_OP, stmt->map.op);
|
|
Packit |
c5a612 |
nftnl_expr_set_str(nle, NFTNL_EXPR_DYNSET_SET_NAME, set->handle.set.name);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_DYNSET_SET_ID, set->handle.set_id);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (stmt->map.stmt)
|
|
Packit |
c5a612 |
nftnl_expr_set(nle, NFTNL_EXPR_DYNSET_EXPR,
|
|
Packit |
c5a612 |
netlink_gen_stmt_stateful(ctx, stmt->map.stmt), 0);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_meter_stmt(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
enum nft_registers sreg_key;
|
|
Packit |
c5a612 |
enum nft_dynset_ops op;
|
|
Packit |
c5a612 |
struct set *set;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
sreg_key = get_register(ctx, stmt->meter.key->key);
|
|
Packit |
c5a612 |
netlink_gen_expr(ctx, stmt->meter.key->key, sreg_key);
|
|
Packit |
c5a612 |
release_register(ctx, stmt->meter.key->key);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
set = stmt->meter.set->set;
|
|
Packit |
c5a612 |
if (stmt->meter.key->timeout)
|
|
Packit |
c5a612 |
op = NFT_DYNSET_OP_UPDATE;
|
|
Packit |
c5a612 |
else
|
|
Packit |
c5a612 |
op = NFT_DYNSET_OP_ADD;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nle = alloc_nft_expr("dynset");
|
|
Packit |
c5a612 |
netlink_put_register(nle, NFTNL_EXPR_DYNSET_SREG_KEY, sreg_key);
|
|
Packit |
c5a612 |
if (stmt->meter.key->timeout)
|
|
Packit |
c5a612 |
nftnl_expr_set_u64(nle, NFTNL_EXPR_DYNSET_TIMEOUT,
|
|
Packit |
c5a612 |
stmt->meter.key->timeout);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_DYNSET_OP, op);
|
|
Packit |
c5a612 |
nftnl_expr_set_str(nle, NFTNL_EXPR_DYNSET_SET_NAME, set->handle.set.name);
|
|
Packit |
c5a612 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_DYNSET_SET_ID, set->handle.set_id);
|
|
Packit |
c5a612 |
nftnl_expr_set(nle, NFTNL_EXPR_DYNSET_EXPR,
|
|
Packit |
c5a612 |
netlink_gen_stmt_stateful(ctx, stmt->meter.stmt), 0);
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx,
|
|
Packit |
c5a612 |
const struct stmt *stmt)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_expr *nle;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
switch (stmt->ops->type) {
|
|
Packit |
c5a612 |
case STMT_EXPRESSION:
|
|
Packit |
c5a612 |
return netlink_gen_expr(ctx, stmt->expr, NFT_REG_VERDICT);
|
|
Packit |
c5a612 |
case STMT_VERDICT:
|
|
Packit |
c5a612 |
return netlink_gen_verdict_stmt(ctx, stmt);
|
|
Packit |
c5a612 |
case STMT_METER:
|
|
Packit |
c5a612 |
return netlink_gen_meter_stmt(ctx, stmt);
|
|
Packit |
c5a612 |
case STMT_EXTHDR:
|
|
Packit |
c5a612 |
return netlink_gen_exthdr_stmt(ctx, stmt);
|
|
Packit |
c5a612 |
case STMT_PAYLOAD:
|
|
Packit |
c5a612 |
return netlink_gen_payload_stmt(ctx, stmt);
|
|
Packit |
c5a612 |
case STMT_META:
|
|
Packit |
c5a612 |
return netlink_gen_meta_stmt(ctx, stmt);
|
|
Packit |
c5a612 |
case STMT_LOG:
|
|
Packit |
c5a612 |
return netlink_gen_log_stmt(ctx, stmt);
|
|
Packit |
c5a612 |
case STMT_REJECT:
|
|
Packit |
c5a612 |
return netlink_gen_reject_stmt(ctx, stmt);
|
|
Packit |
c5a612 |
case STMT_NAT:
|
|
Packit |
c5a612 |
return netlink_gen_nat_stmt(ctx, stmt);
|
|
Packit |
c5a612 |
case STMT_TPROXY:
|
|
Packit |
c5a612 |
return netlink_gen_tproxy_stmt(ctx, stmt);
|
|
Packit |
c5a612 |
case STMT_SYNPROXY:
|
|
Packit |
c5a612 |
return netlink_gen_synproxy_stmt(ctx, stmt);
|
|
Packit |
c5a612 |
case STMT_DUP:
|
|
Packit |
c5a612 |
return netlink_gen_dup_stmt(ctx, stmt);
|
|
Packit |
c5a612 |
case STMT_QUEUE:
|
|
Packit |
c5a612 |
return netlink_gen_queue_stmt(ctx, stmt);
|
|
Packit |
c5a612 |
case STMT_CT:
|
|
Packit |
c5a612 |
return netlink_gen_ct_stmt(ctx, stmt);
|
|
Packit |
c5a612 |
case STMT_SET:
|
|
Packit |
c5a612 |
return netlink_gen_set_stmt(ctx, stmt);
|
|
Packit |
c5a612 |
case STMT_FWD:
|
|
Packit |
c5a612 |
return netlink_gen_fwd_stmt(ctx, stmt);
|
|
Packit |
c5a612 |
case STMT_CONNLIMIT:
|
|
Packit |
c5a612 |
case STMT_COUNTER:
|
|
Packit |
c5a612 |
case STMT_LIMIT:
|
|
Packit |
c5a612 |
case STMT_QUOTA:
|
|
Packit |
c5a612 |
nle = netlink_gen_stmt_stateful(ctx, stmt);
|
|
Packit |
c5a612 |
nftnl_rule_add_expr(ctx->nlr, nle);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case STMT_NOTRACK:
|
|
Packit |
c5a612 |
return netlink_gen_notrack_stmt(ctx, stmt);
|
|
Packit |
c5a612 |
case STMT_FLOW_OFFLOAD:
|
|
Packit |
c5a612 |
return netlink_gen_flow_offload_stmt(ctx, stmt);
|
|
Packit |
c5a612 |
case STMT_OBJREF:
|
|
Packit |
c5a612 |
return netlink_gen_objref_stmt(ctx, stmt);
|
|
Packit |
c5a612 |
case STMT_MAP:
|
|
Packit |
c5a612 |
return netlink_gen_map_stmt(ctx, stmt);
|
|
Packit |
c5a612 |
default:
|
|
Packit |
c5a612 |
BUG("unknown statement type %s\n", stmt->ops->name);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
void netlink_linearize_rule(struct netlink_ctx *ctx, struct nftnl_rule *nlr,
|
|
Packit |
c5a612 |
const struct rule *rule)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct netlink_linearize_ctx lctx;
|
|
Packit |
c5a612 |
const struct stmt *stmt;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
memset(&lctx, 0, sizeof(lctx));
|
|
Packit |
c5a612 |
lctx.reg_low = NFT_REG_1;
|
|
Packit |
c5a612 |
lctx.nlr = nlr;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
list_for_each_entry(stmt, &rule->stmts, list)
|
|
Packit |
c5a612 |
netlink_gen_stmt(&lctx, stmt);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (rule->comment) {
|
|
Packit |
c5a612 |
struct nftnl_udata_buf *udata;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
udata = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN);
|
|
Packit |
c5a612 |
if (!udata)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (!nftnl_udata_put_strz(udata, NFTNL_UDATA_RULE_COMMENT,
|
|
Packit |
c5a612 |
rule->comment))
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
nftnl_rule_set_data(nlr, NFTNL_RULE_USERDATA,
|
|
Packit |
c5a612 |
nftnl_udata_buf_data(udata),
|
|
Packit |
c5a612 |
nftnl_udata_buf_len(udata));
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_udata_buf_free(udata);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
netlink_dump_rule(nlr, ctx);
|
|
Packit |
c5a612 |
}
|