summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/rule.h14
-rw-r--r--src/mnl.c25
-rw-r--r--src/netlink.c29
-rw-r--r--src/parser_bison.y43
-rw-r--r--src/rule.c67
-rw-r--r--src/scanner.l3
6 files changed, 180 insertions, 1 deletions
diff --git a/include/rule.h b/include/rule.h
index c52af2c4..498a88bf 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -496,6 +496,15 @@ enum tunnel_type {
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 {
@@ -521,9 +530,14 @@ 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
*
diff --git a/src/mnl.c b/src/mnl.c
index 0949a694..273cefe8 100644
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -1532,6 +1532,31 @@ static void obj_tunnel_add_opts(struct nftnl_obj *nlo, struct tunnel *tunnel)
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;
}
diff --git a/src/netlink.c b/src/netlink.c
index e132362b..5bae3b82 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -1843,6 +1843,35 @@ static int tunnel_parse_opt_cb(struct nftnl_tunnel_opt *opt, void *data) {
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;
}
diff --git a/src/parser_bison.y b/src/parser_bison.y
index ca93a658..13eb6027 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -613,6 +613,8 @@ int nft_lex(void *, void *, void *);
%token EGRESS "egress"
%token INGRESS "ingress"
%token GBP "gbp"
+%token CLASS "class"
+%token OPTTYPE "opt-type"
%token COUNTERS "counters"
%token QUOTAS "quotas"
@@ -771,7 +773,7 @@ int nft_lex(void *, void *, void *);
%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
@@ -5012,6 +5014,44 @@ erspan_config : HDRVERSION NUM
}
;
+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
@@ -5081,6 +5121,7 @@ tunnel_config : ID NUM
{
$<obj>0->tunnel.type = TUNNEL_VXLAN;
}
+ | GENEVE geneve_block_alloc '{' geneve_block '}'
;
tunnel_block : /* empty */ { $$ = $<obj>-1; }
diff --git a/src/rule.c b/src/rule.c
index 0450851c..e6216bca 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -1707,6 +1707,14 @@ void obj_free(struct obj *obj)
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;
@@ -1787,6 +1795,44 @@ static const char *synproxy_timestamp_to_str(const uint32_t flags)
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)
@@ -2053,6 +2099,27 @@ static void obj_print_data(const struct obj *obj,
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;
}
diff --git a/src/scanner.l b/src/scanner.l
index 74ebca3b..8085c93b 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -828,6 +828,9 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"ingress" { return INGRESS; }
"path" { return PATH; }
"gbp" { return GBP; }
+ "class" { return CLASS; }
+ "opt-type" { return OPTTYPE; }
+ "data" { return DATA; }
}
"notrack" { return NOTRACK; }