TUNNEL_UNSPEC = 0,
TUNNEL_ERSPAN,
TUNNEL_VXLAN,
+ TUNNEL_GENEVE,
+};
+
+struct tunnel_geneve {
+ struct list_head list;
+ uint16_t geneve_class;
+ uint8_t type;
+ uint8_t data[NFTNL_TUNNEL_GENEVE_DATA_MAXLEN];
+ uint32_t data_len;
};
struct tunnel {
struct {
uint32_t gbp;
} vxlan;
+ struct list_head geneve_opts;
};
};
+int tunnel_geneve_data_str2array(const char *hexstr,
+ uint8_t *out_data,
+ uint32_t *out_len);
+
/**
* struct obj - nftables stateful object statement
*
nftnl_tunnel_opts_add(opts, opt);
nftnl_obj_set_data(nlo, NFTNL_OBJ_TUNNEL_OPTS, &opts, sizeof(struct nftnl_tunnel_opts *));
break;
+ case TUNNEL_GENEVE:
+ struct tunnel_geneve *geneve;
+
+ opts = nftnl_tunnel_opts_alloc(NFTNL_TUNNEL_TYPE_GENEVE);
+ if (!opts)
+ memory_allocation_error();
+
+ list_for_each_entry(geneve, &tunnel->geneve_opts, list) {
+ opt = nftnl_tunnel_opt_alloc(NFTNL_TUNNEL_TYPE_GENEVE);
+ if (!opt)
+ memory_allocation_error();
+
+ nftnl_tunnel_opt_set(opt,
+ NFTNL_TUNNEL_GENEVE_TYPE,
+ &geneve->type, sizeof(geneve->type));
+ nftnl_tunnel_opt_set(opt,
+ NFTNL_TUNNEL_GENEVE_CLASS,
+ &geneve->geneve_class, sizeof(geneve->geneve_class));
+ nftnl_tunnel_opt_set(opt,
+ NFTNL_TUNNEL_GENEVE_DATA,
+ &geneve->data, geneve->data_len);
+ 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;
}
obj->tunnel.vxlan.gbp = nftnl_tunnel_opt_get_u32(opt, NFTNL_TUNNEL_VXLAN_GBP);
}
break;
+ case NFTNL_TUNNEL_TYPE_GENEVE:
+ struct tunnel_geneve *geneve;
+ const void *data;
+
+ if (!obj->tunnel.type) {
+ init_list_head(&obj->tunnel.geneve_opts);
+ obj->tunnel.type = TUNNEL_GENEVE;
+ }
+
+ geneve = xmalloc(sizeof(struct tunnel_geneve));
+ if (!geneve)
+ memory_allocation_error();
+
+ if (nftnl_tunnel_opt_get_flags(opt) & (1 << NFTNL_TUNNEL_GENEVE_TYPE))
+ geneve->type = nftnl_tunnel_opt_get_u8(opt, NFTNL_TUNNEL_GENEVE_TYPE);
+
+ if (nftnl_tunnel_opt_get_flags(opt) & (1 << NFTNL_TUNNEL_GENEVE_CLASS))
+ geneve->geneve_class = nftnl_tunnel_opt_get_u16(opt, NFTNL_TUNNEL_GENEVE_CLASS);
+
+ if (nftnl_tunnel_opt_get_flags(opt) & (1 << NFTNL_TUNNEL_GENEVE_DATA)) {
+ data = nftnl_tunnel_opt_get_data(opt, NFTNL_TUNNEL_GENEVE_DATA,
+ &geneve->data_len);
+ if (!data)
+ return -1;
+ memcpy(&geneve->data, data, geneve->data_len);
+ }
+
+ list_add_tail(&geneve->list, &obj->tunnel.geneve_opts);
+ break;
default:
break;
}
%token EGRESS "egress"
%token INGRESS "ingress"
%token GBP "gbp"
+%token CLASS "class"
+%token OPTTYPE "opt-type"
%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 erspan_block erspan_block_alloc vxlan_block vxlan_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 erspan_block erspan_block_alloc vxlan_block vxlan_block_alloc geneve_block geneve_block_alloc
%destructor { obj_free($$); } obj_block_alloc
%type <list> stmt_list stateful_stmt_list set_elem_stmt_list
}
;
+geneve_block : /* empty */ { $$ = $<obj>-1; }
+ | geneve_block common_block
+ | geneve_block stmt_separator
+ | geneve_block geneve_config stmt_separator
+ {
+ $$ = $1;
+ }
+ ;
+
+geneve_block_alloc : /* empty */
+ {
+ $$ = $<obj>-1;
+ }
+ ;
+
+geneve_config : CLASS NUM OPTTYPE NUM DATA string
+ {
+ struct tunnel_geneve *geneve;
+
+ geneve = xmalloc(sizeof(struct tunnel_geneve));
+ geneve->geneve_class = $2;
+ geneve->type = $4;
+ if (tunnel_geneve_data_str2array($6, geneve->data, &geneve->data_len)) {
+ erec_queue(error(&@6, "Invalid data array %s\n", $6), state->msgs);
+ free_const($6);
+ free(geneve);
+ YYERROR;
+ }
+
+ if (!$<obj>0->tunnel.type) {
+ $<obj>0->tunnel.type = TUNNEL_GENEVE;
+ init_list_head(&$<obj>0->tunnel.geneve_opts);
+ }
+ list_add_tail(&geneve->list, &$<obj>0->tunnel.geneve_opts);
+ free_const($6);
+ }
+ ;
+
vxlan_block : /* empty */ { $$ = $<obj>-1; }
| vxlan_block common_block
| vxlan_block stmt_separator
{
$<obj>0->tunnel.type = TUNNEL_VXLAN;
}
+ | GENEVE geneve_block_alloc '{' geneve_block '}'
;
tunnel_block : /* empty */ { $$ = $<obj>-1; }
case NFT_OBJECT_TUNNEL:
expr_free(obj->tunnel.src);
expr_free(obj->tunnel.dst);
+ if (obj->tunnel.type == TUNNEL_GENEVE) {
+ struct tunnel_geneve *geneve, *next;
+
+ list_for_each_entry_safe(geneve, next, &obj->tunnel.geneve_opts, list) {
+ list_del(&geneve->list);
+ free(geneve);
+ }
+ }
break;
default:
break;
return "";
}
+int tunnel_geneve_data_str2array(const char *hexstr,
+ uint8_t *out_data,
+ uint32_t *out_len)
+{
+ char bytestr[3] = {0};
+ size_t len;
+
+ if (hexstr[0] == '0' && (hexstr[1] == 'x' || hexstr[1] == 'X'))
+ hexstr += 2;
+ else
+ return -1;
+
+ len = strlen(hexstr);
+ if (len % 4 != 0)
+ return -1;
+
+ len = len / 2;
+ if (len > NFTNL_TUNNEL_GENEVE_DATA_MAXLEN)
+ return -1;
+
+ for (size_t i = 0; i < len; i++) {
+ uint32_t value;
+ char *endptr;
+
+ bytestr[0] = hexstr[i * 2];
+ bytestr[1] = hexstr[i * 2 + 1];
+
+ value = strtoul(bytestr, &endptr, 16);
+ if (*endptr != '\0')
+ return -1;
+
+ out_data[i] = (uint8_t) value;
+ }
+ *out_len = (uint8_t) len;
+
+ return 0;
+}
+
static void obj_print_comment(const struct obj *obj,
struct print_fmt_options *opts,
struct output_ctx *octx)
nft_print(octx, "%s%s%s}",
opts->nl, opts->tab, opts->tab);
break;
+ case TUNNEL_GENEVE:
+ struct tunnel_geneve *geneve;
+
+ nft_print(octx, "%s%s%sgeneve {", opts->nl, opts->tab, opts->tab);
+ list_for_each_entry(geneve, &obj->tunnel.geneve_opts, list) {
+ char data_str[256];
+ int offset = 0;
+
+ for (uint32_t i = 0; i < geneve->data_len; i++) {
+ offset += snprintf(data_str + offset,
+ geneve->data_len,
+ "%x",
+ geneve->data[i]);
+ }
+ nft_print(octx, "%s%s%s%sclass 0x%x opt-type 0x%x data \"0x%s\"",
+ opts->nl, opts->tab, opts->tab, opts->tab,
+ geneve->geneve_class, geneve->type, data_str);
+
+ }
+ nft_print(octx, "%s%s%s}", opts->nl, opts->tab, opts->tab);
+ break;
default:
break;
}
"ingress" { return INGRESS; }
"path" { return PATH; }
"gbp" { return GBP; }
+ "class" { return CLASS; }
+ "opt-type" { return OPTTYPE; }
+ "data" { return DATA; }
}
"notrack" { return NOTRACK; }