char ctx[NFT_SECMARK_CTX_MAXLEN];
};
+enum tunnel_type {
+ TUNNEL_UNSPEC = 0,
+ TUNNEL_ERSPAN,
+};
+
struct tunnel {
uint32_t id;
struct expr *src;
uint16_t dport;
uint8_t tos;
uint8_t ttl;
+ enum tunnel_type type;
+ union {
+ struct {
+ uint32_t version;
+ struct {
+ uint32_t index;
+ } v1;
+ struct {
+ uint8_t direction;
+ uint8_t hwid;
+ } v2;
+ } erspan;
+ };
};
/**
return NULL;
}
+static void obj_tunnel_add_opts(struct nftnl_obj *nlo, struct tunnel *tunnel)
+{
+ struct nftnl_tunnel_opts *opts;
+ struct nftnl_tunnel_opt *opt;
+
+ switch (tunnel->type) {
+ case TUNNEL_ERSPAN:
+ opts = nftnl_tunnel_opts_alloc(NFTNL_TUNNEL_TYPE_ERSPAN);
+ if (!opts)
+ memory_allocation_error();
+
+ opt = nftnl_tunnel_opt_alloc(NFTNL_TUNNEL_TYPE_ERSPAN);
+ if (!opt)
+ memory_allocation_error();
+
+ nftnl_tunnel_opt_set(opt, NFTNL_TUNNEL_ERSPAN_VERSION,
+ &tunnel->erspan.version,
+ sizeof(tunnel->erspan.version));
+ switch (tunnel->erspan.version) {
+ case 1:
+ nftnl_tunnel_opt_set(opt, NFTNL_TUNNEL_ERSPAN_V1_INDEX,
+ &tunnel->erspan.v1.index,
+ sizeof(tunnel->erspan.v1.index));
+ break;
+ case 2:
+ nftnl_tunnel_opt_set(opt, NFTNL_TUNNEL_ERSPAN_V2_DIR,
+ &tunnel->erspan.v2.direction,
+ sizeof(tunnel->erspan.v2.direction));
+ nftnl_tunnel_opt_set(opt, NFTNL_TUNNEL_ERSPAN_V2_HWID,
+ &tunnel->erspan.v2.hwid,
+ sizeof(tunnel->erspan.v2.hwid));
+ break;
+ }
+
+ nftnl_tunnel_opts_add(opts, opt);
+ nftnl_obj_set_data(nlo, NFTNL_OBJ_TUNNEL_OPTS, &opts, sizeof(struct nftnl_tunnel_opts *));
+ break;
+ case TUNNEL_UNSPEC:
+ break;
+ }
+}
+
int mnl_nft_obj_add(struct netlink_ctx *ctx, struct cmd *cmd,
unsigned int flags)
{
nld.value, nld.len);
}
}
+ obj_tunnel_add_opts(nlo, &obj->tunnel);
break;
default:
BUG("Unknown type %d\n", obj->type);
return 0;
}
+static int tunnel_parse_opt_cb(struct nftnl_tunnel_opt *opt, void *data) {
+
+ struct obj *obj = data;
+
+ switch (nftnl_tunnel_opt_get_type(opt)) {
+ case NFTNL_TUNNEL_TYPE_ERSPAN:
+ obj->tunnel.type = TUNNEL_ERSPAN;
+ if (nftnl_tunnel_opt_get_flags(opt) & (1 << NFTNL_TUNNEL_ERSPAN_VERSION)) {
+ obj->tunnel.erspan.version =
+ nftnl_tunnel_opt_get_u32(opt,
+ NFTNL_TUNNEL_ERSPAN_VERSION);
+ }
+ if (nftnl_tunnel_opt_get_flags(opt) & (1 << NFTNL_TUNNEL_ERSPAN_V1_INDEX)) {
+ obj->tunnel.erspan.v1.index =
+ nftnl_tunnel_opt_get_u32(opt,
+ NFTNL_TUNNEL_ERSPAN_V1_INDEX);
+ }
+ if (nftnl_tunnel_opt_get_flags(opt) & (1 << NFTNL_TUNNEL_ERSPAN_V2_HWID)) {
+ obj->tunnel.erspan.v2.hwid =
+ nftnl_tunnel_opt_get_u8(opt,
+ NFTNL_TUNNEL_ERSPAN_V2_HWID);
+ }
+ if (nftnl_tunnel_opt_get_flags(opt) & (1 << NFTNL_TUNNEL_ERSPAN_V2_DIR)) {
+ obj->tunnel.erspan.v2.direction =
+ nftnl_tunnel_opt_get_u8(opt,
+ NFTNL_TUNNEL_ERSPAN_V2_DIR);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
struct obj *netlink_delinearize_obj(struct netlink_ctx *ctx,
struct nftnl_obj *nlo)
{
obj->tunnel.dst =
netlink_obj_tunnel_parse_addr(nlo, NFTNL_OBJ_TUNNEL_IPV6_DST);
}
+ if (nftnl_obj_is_set(nlo, NFTNL_OBJ_TUNNEL_OPTS)) {
+ nftnl_obj_tunnel_opts_foreach(nlo, tunnel_parse_opt_cb, obj);
+ }
break;
default:
netlink_io_error(ctx, NULL, "Unknown object type %u", type);
%token NEVER "never"
%token TUNNEL "tunnel"
+%token ERSPAN "erspan"
+%token EGRESS "egress"
+%token INGRESS "ingress"
%token COUNTERS "counters"
%token QUOTAS "quotas"
%type <flowtable> flowtable_block_alloc flowtable_block
%destructor { flowtable_free($$); } flowtable_block_alloc
-%type <obj> obj_block_alloc counter_block quota_block ct_helper_block ct_timeout_block ct_expect_block limit_block secmark_block synproxy_block tunnel_block
+%type <obj> obj_block_alloc counter_block quota_block ct_helper_block ct_timeout_block ct_expect_block limit_block secmark_block synproxy_block tunnel_block erspan_block erspan_block_alloc
%destructor { obj_free($$); } obj_block_alloc
%type <list> stmt_list stateful_stmt_list set_elem_stmt_list
}
;
+erspan_block : /* empty */ { $$ = $<obj>-1; }
+ | erspan_block common_block
+ | erspan_block stmt_separator
+ | erspan_block erspan_config stmt_separator
+ {
+ $$ = $1;
+ }
+ ;
+
+erspan_block_alloc : /* empty */
+ {
+ $$ = $<obj>-1;
+ }
+ ;
+
+erspan_config : HDRVERSION NUM
+ {
+ $<obj>0->tunnel.erspan.version = $2;
+ }
+ | INDEX NUM
+ {
+ $<obj>0->tunnel.erspan.v1.index = $2;
+ }
+ | DIRECTION INGRESS
+ {
+ $<obj>0->tunnel.erspan.v2.direction = 0;
+ }
+ | DIRECTION EGRESS
+ {
+ $<obj>0->tunnel.erspan.v2.direction = 1;
+ }
+ | ID NUM
+ {
+ $<obj>0->tunnel.erspan.v2.hwid = $2;
+ }
+ ;
+
tunnel_config : ID NUM
{
$<obj>0->tunnel.id = $2;
{
$<obj>0->tunnel.tos = $2;
}
+ | ERSPAN erspan_block_alloc '{' erspan_block '}'
+ {
+ $<obj>0->tunnel.type = TUNNEL_ERSPAN;
+ }
;
tunnel_block : /* empty */ { $$ = $<obj>-1; }
opts->nl, opts->tab, opts->tab,
obj->tunnel.ttl);
}
+ switch (obj->tunnel.type) {
+ case TUNNEL_ERSPAN:
+ nft_print(octx, "%s%s%serspan {",
+ opts->nl, opts->tab, opts->tab);
+ nft_print(octx, "%s%s%s%sversion %u",
+ opts->nl, opts->tab, opts->tab, opts->tab,
+ obj->tunnel.erspan.version);
+ if (obj->tunnel.erspan.version == 1) {
+ nft_print(octx, "%s%s%s%sindex %u",
+ opts->nl, opts->tab, opts->tab, opts->tab,
+ obj->tunnel.erspan.v1.index);
+ } else {
+ nft_print(octx, "%s%s%s%sdirection %s",
+ opts->nl, opts->tab, opts->tab, opts->tab,
+ obj->tunnel.erspan.v2.direction ? "egress"
+ : "ingress");
+ nft_print(octx, "%s%s%s%sid %u",
+ opts->nl, opts->tab, opts->tab, opts->tab,
+ obj->tunnel.erspan.v2.hwid);
+ }
+ nft_print(octx, "%s%s%s}",
+ opts->nl, opts->tab, opts->tab);
+ default:
+ break;
+ }
+
nft_print(octx, "%s", opts->stmt_separator);
break;
default:
"dport" { return DPORT; }
"ttl" { return TTL; }
"tos" { return TOS; }
+ "version" { return HDRVERSION; }
+ "direction" { return DIRECTION; }
+ "erspan" { return ERSPAN; }
+ "egress" { return EGRESS; }
+ "ingress" { return INGRESS; }
}
"notrack" { return NOTRACK; }