This patch adds support for adding, listing and deleting ct timeout
objects which can be assigned via rule to assign connection tracking
timeout policies via objref infrastructure.
%nft add table filter
%nft add chain filter output
%nft add ct timeout filter test-tcp { protocol tcp \; policy = {
established: 132, close: 13, close_wait: 17 } \; }
%nft add rule filter output ct timeout set test-tcp
%nft list ruleset
table ip filter {
ct timeout test-tcp {
protocol tcp;
policy = {established: 132, close_wait: 17, close: 13}
}
chain output {
ct timeout set "test-tcp"
}
}
%nft delete rule filter output handle <handle>
%nft delete ct timeout filter test-tcp
Signed-off-by: Harsha Sharma <[email protected]>
---
Changes in v4:
- updated syntax and log message
- fix parser_bison to parse input from files for ct timeout obj
- output similar to output
Changes in v3:
- parse multiple timeout policies
- return error for invalid timeout state name
- change in log message
Changes in v2:
- Change in syntax for addition of ct timeout objects
- remove tokens from scanner and parser_bison for timeout states
- list only updated timeout values
- change in log message accordingly
- other minor changes
include/linux/netfilter/nf_tables.h | 14 ++++-
include/rule.h | 25 ++++++++
src/evaluate.c | 4 ++
src/netlink.c | 21 +++++++
src/parser_bison.y | 109 +++++++++++++++++++++++++++++++++-
src/rule.c | 113 +++++++++++++++++++++++++++++++++++-
src/statement.c | 4 ++
7 files changed, 286 insertions(+), 4 deletions(-)
diff --git a/include/linux/netfilter/nf_tables.h
b/include/linux/netfilter/nf_tables.h
index 63b9054..0948987 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -971,6 +971,7 @@ enum nft_osf_attributes {
* @NFT_CT_DST_IP: conntrack layer 3 protocol destination (IPv4 address)
* @NFT_CT_SRC_IP6: conntrack layer 3 protocol source (IPv6 address)
* @NFT_CT_DST_IP6: conntrack layer 3 protocol destination (IPv6 address)
+ * @NFT_CT_TIMEOUT: connection tracking timeout policy assigned to conntrack
*/
enum nft_ct_keys {
NFT_CT_STATE,
@@ -996,6 +997,7 @@ enum nft_ct_keys {
NFT_CT_DST_IP,
NFT_CT_SRC_IP6,
NFT_CT_DST_IP6,
+ NFT_CT_TIMEOUT,
__NFT_CT_MAX
};
#define NFT_CT_MAX (__NFT_CT_MAX - 1)
@@ -1402,13 +1404,23 @@ enum nft_ct_helper_attributes {
};
#define NFTA_CT_HELPER_MAX (__NFTA_CT_HELPER_MAX - 1)
+enum nft_ct_timeout_attributes {
+ NFTA_CT_TIMEOUT_L3PROTO,
+ NFTA_CT_TIMEOUT_L4PROTO,
+ NFTA_CT_TIMEOUT_DATA,
+ __NFTA_CT_TIMEOUT_MAX,
+};
+#define NFTA_CT_TIMEOUT_MAX (__NFTA_CT_TIMEOUT_MAX - 1)
+
#define NFT_OBJECT_UNSPEC 0
#define NFT_OBJECT_COUNTER 1
#define NFT_OBJECT_QUOTA 2
#define NFT_OBJECT_CT_HELPER 3
#define NFT_OBJECT_LIMIT 4
#define NFT_OBJECT_CONNLIMIT 5
-#define __NFT_OBJECT_MAX 6
+#define NFT_OBJECT_TUNNEL 6
+#define NFT_OBJECT_CT_TIMEOUT 7
+#define __NFT_OBJECT_MAX 8
#define NFT_OBJECT_MAX (__NFT_OBJECT_MAX - 1)
/**
diff --git a/include/rule.h b/include/rule.h
index 909ff36..2068887 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -4,6 +4,8 @@
#include <stdint.h>
#include <nftables.h>
#include <list.h>
+#include <libnftnl/cttimeout.h>
+#include <netinet/in.h>
/**
* struct handle_spec - handle ID
@@ -308,6 +310,18 @@ struct ct_helper {
uint8_t l4proto;
};
+struct ct_timeout {
+ uint16_t l3proto;
+ uint8_t l4proto;
+ uint32_t *timeout;
+ struct timeout_state {
+ uint8_t timeout_index;
+ uint32_t timeout_value;
+ uint8_t l4;
+ struct list_head timeout_list;
+ } timeout_state;
+};
+
struct limit {
uint64_t rate;
uint64_t unit;
@@ -336,6 +350,7 @@ struct obj {
struct quota quota;
struct ct_helper ct_helper;
struct limit limit;
+ struct ct_timeout ct_timeout;
};
};
@@ -462,6 +477,7 @@ enum cmd_obj {
CMD_OBJ_LIMITS,
CMD_OBJ_FLOWTABLE,
CMD_OBJ_FLOWTABLES,
+ CMD_OBJ_CT_TIMEOUT,
};
struct markup {
@@ -617,4 +633,13 @@ enum udata_set_elem_flags {
SET_ELEM_F_INTERVAL_OPEN = 0x1,
};
+struct timeout_protocol {
+ uint32_t attr_max;
+ const char *const *state_to_name;
+ uint32_t *dflt_timeout;
+};
+
+extern struct timeout_protocol timeout_protocol[IPPROTO_MAX];
+extern void timeout_str2num(const char *timeout_state, struct timeout_state
*ts);
+
#endif /* NFTABLES_RULE_H */
diff --git a/src/evaluate.c b/src/evaluate.c
index 1fc861f..304990e 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -3224,6 +3224,7 @@ static int cmd_evaluate_add(struct eval_ctx *ctx, struct
cmd *cmd)
case CMD_OBJ_COUNTER:
case CMD_OBJ_QUOTA:
case CMD_OBJ_CT_HELPER:
+ case CMD_OBJ_CT_TIMEOUT:
case CMD_OBJ_LIMIT:
return 0;
default:
@@ -3251,6 +3252,7 @@ static int cmd_evaluate_delete(struct eval_ctx *ctx,
struct cmd *cmd)
case CMD_OBJ_COUNTER:
case CMD_OBJ_QUOTA:
case CMD_OBJ_CT_HELPER:
+ case CMD_OBJ_CT_TIMEOUT:
case CMD_OBJ_LIMIT:
return 0;
default:
@@ -3383,6 +3385,8 @@ static int cmd_evaluate_list(struct eval_ctx *ctx, struct
cmd *cmd)
return cmd_evaluate_list_obj(ctx, cmd, NFT_OBJECT_COUNTER);
case CMD_OBJ_CT_HELPER:
return cmd_evaluate_list_obj(ctx, cmd, NFT_OBJECT_CT_HELPER);
+ case CMD_OBJ_CT_TIMEOUT:
+ return cmd_evaluate_list_obj(ctx, cmd, NFT_OBJECT_CT_TIMEOUT);
case CMD_OBJ_LIMIT:
return cmd_evaluate_list_obj(ctx, cmd, NFT_OBJECT_LIMIT);
case CMD_OBJ_COUNTERS:
diff --git a/src/netlink.c b/src/netlink.c
index 394af2f..967d9cc 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -28,6 +28,7 @@
#include <libnftnl/udata.h>
#include <libnftnl/ruleset.h>
#include <libnftnl/common.h>
+#include <libnftnl/cttimeout.h>
#include <linux/netfilter/nfnetlink.h>
#include <linux/netfilter/nf_tables.h>
#include <linux/netfilter.h>
@@ -41,6 +42,7 @@
#include <utils.h>
#include <erec.h>
#include <iface.h>
+#include <rule.h>
#define nft_mon_print(monh, ...) nft_print(monh->ctx->octx, __VA_ARGS__)
@@ -334,6 +336,20 @@ alloc_nftnl_obj(const struct handle *h, struct obj *obj)
nftnl_obj_set_u16(nlo, NFTNL_OBJ_CT_HELPER_L3PROTO,
obj->ct_helper.l3proto);
break;
+ case NFT_OBJECT_CT_TIMEOUT:
+ nftnl_obj_set_u8(nlo, NFTNL_OBJ_CT_TIMEOUT_L4PROTO,
+ obj->ct_timeout.l4proto);
+ if (obj->ct_timeout.l3proto)
+ nftnl_obj_set_u16(nlo, NFTNL_OBJ_CT_TIMEOUT_L3PROTO,
+ obj->ct_timeout.l3proto);
+ else
+ nftnl_obj_set_u16(nlo, NFTNL_OBJ_CT_TIMEOUT_L3PROTO,
+ NFPROTO_IPV4);
+ for (unsigned int i = 0; i <
timeout_protocol[obj->ct_timeout.l4proto].attr_max; ++i) {
+ if (obj->ct_timeout.timeout[i])
+ nftnl_timeout_policy_attr_set_u32(nlo, i,
obj->ct_timeout.timeout[i]);
+ }
+ break;
case NFT_OBJECT_LIMIT:
nftnl_obj_set_u64(nlo, NFTNL_OBJ_LIMIT_RATE, obj->limit.rate);
nftnl_obj_set_u64(nlo, NFTNL_OBJ_LIMIT_UNIT, obj->limit.unit);
@@ -1437,6 +1453,11 @@ struct obj *netlink_delinearize_obj(struct netlink_ctx
*ctx,
obj->ct_helper.l3proto = nftnl_obj_get_u16(nlo,
NFTNL_OBJ_CT_HELPER_L3PROTO);
obj->ct_helper.l4proto = nftnl_obj_get_u8(nlo,
NFTNL_OBJ_CT_HELPER_L4PROTO);
break;
+ case NFT_OBJECT_CT_TIMEOUT:
+ obj->ct_timeout.l3proto = nftnl_obj_get_u16(nlo,
NFTNL_OBJ_CT_TIMEOUT_L3PROTO);
+ obj->ct_timeout.l4proto = nftnl_obj_get_u8(nlo,
NFTNL_OBJ_CT_TIMEOUT_L4PROTO);
+ obj->ct_timeout.timeout = nftnl_obj_get_void(nlo,
NFTNL_OBJ_CT_TIMEOUT_DATA);
+ break;
case NFT_OBJECT_LIMIT:
obj->limit.rate =
nftnl_obj_get_u64(nlo, NFTNL_OBJ_LIMIT_RATE);
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 9a75120..a2592ab 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -550,7 +550,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 limit_block
+%type <obj> obj_block_alloc counter_block quota_block
ct_helper_block ct_timeout_block limit_block
%destructor { obj_free($$); } obj_block_alloc
%type <list> stmt_list
@@ -753,6 +753,10 @@ int nft_lex(void *, void *, void *);
%type <val> ct_l4protoname ct_obj_type
+%type <list> timeout_states timeout_state
+%destructor { xfree($$); } timeout_states timeout_state
+
+
%%
input : /* empty */
@@ -960,6 +964,10 @@ add_cmd : TABLE
table_spec
$$ = cmd_alloc_obj_ct(CMD_ADD,
NFT_OBJECT_CT_HELPER, &$3, &@$, $4);
}
+ | CT TIMEOUT obj_spec ct_obj_alloc
'{' ct_timeout_block '}' stmt_separator
+ {
+ $$ = cmd_alloc_obj_ct(CMD_ADD,
NFT_OBJECT_CT_TIMEOUT, &$3, &@$, $4);
+ }
| LIMIT obj_spec limit_obj
{
$$ = cmd_alloc(CMD_ADD, CMD_OBJ_LIMIT, &$2,
&@$, $3);
@@ -1041,6 +1049,10 @@ create_cmd : TABLE
table_spec
{
$$ = cmd_alloc_obj_ct(CMD_CREATE,
NFT_OBJECT_CT_HELPER, &$3, &@$, $4);
}
+ | CT TIMEOUT obj_spec ct_obj_alloc
'{' ct_timeout_block '}' stmt_separator
+ {
+ $$ = cmd_alloc_obj_ct(CMD_CREATE,
NFT_OBJECT_CT_TIMEOUT, &$3, &@$, $4);
+ }
| LIMIT obj_spec limit_obj
{
$$ = cmd_alloc(CMD_CREATE, CMD_OBJ_LIMIT, &$2,
&@$, $3);
@@ -1233,6 +1245,10 @@ list_cmd : TABLE table_spec
{
$$ = cmd_alloc(CMD_LIST, CMD_OBJ_CT_HELPERS,
&$4, &@$, NULL);
}
+ | CT TIMEOUT TABLE
table_spec
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_CT_TIMEOUT,
&$4, &@$, NULL);
+ }
;
reset_cmd : COUNTERS ruleset_spec
@@ -1464,6 +1480,15 @@ table_block : /* empty */ { $$ =
$<table>-1; }
list_add_tail(&$5->list, &$1->objs);
$$ = $1;
}
+ | table_block CT TIMEOUT obj_identifier
obj_block_alloc '{' ct_timeout_block '}' stmt_separator
+ {
+ $5->location = @4;
+ $5->type = NFT_OBJECT_CT_TIMEOUT;
+ handle_merge(&$5->handle, &$4);
+ handle_free(&$4);
+ list_add_tail(&$5->list, &$1->objs);
+ $$ = $1;
+ }
| table_block LIMIT obj_identifier
obj_block_alloc '{' limit_block
'}'
stmt_separator
@@ -1759,6 +1784,15 @@ ct_helper_block : /* empty */ { $$ =
$<obj>-1; }
}
;
+ct_timeout_block : /*empty */ { $$ = $<obj>-1; }
+ | ct_timeout_block common_block
+ | ct_timeout_block stmt_separator
+ | ct_timeout_block ct_timeout_config
+ {
+ $$ = $1;
+ }
+ ;
+
limit_block : /* empty */ { $$ = $<obj>-1; }
| limit_block common_block
| limit_block stmt_separator
@@ -3228,12 +3262,43 @@ quota_obj : quota_config
;
ct_obj_type : HELPER { $$ = NFT_OBJECT_CT_HELPER; }
+ | TIMEOUT { $$ = NFT_OBJECT_CT_TIMEOUT; }
;
ct_l4protoname : TCP { $$ = IPPROTO_TCP; }
| UDP { $$ = IPPROTO_UDP; }
;
+timeout_states : timeout_state
+ {
+ $$ = xmalloc(sizeof(*$$));
+ init_list_head($$);
+ list_add_tail($1, $$);
+ }
+ | timeout_states COMMA timeout_state
+ {
+ list_add_tail($3, $1);
+ $$ = $1;
+ }
+ ;
+
+timeout_state : STRING COLON NUM
+
+ {
+ struct timeout_state *ts;
+
+ ts = xzalloc(sizeof(*ts));
+ timeout_str2num($1, ts);
+ if (!ts) {
+ erec_queue(error(&@2, "invalid timeout
state name '%s'\n", $1), state->msgs);
+ YYERROR;
+ }
+ ts->timeout_value = $3;
+ init_list_head(&ts->timeout_list);
+ $$ = &ts->timeout_list;
+ }
+ ;
+
ct_helper_config : TYPE QUOTED_STRING PROTOCOL
ct_l4protoname stmt_separator
{
struct ct_helper *ct;
@@ -3255,6 +3320,42 @@ ct_helper_config : TYPE QUOTED_STRING
PROTOCOL ct_l4protoname stmt_separator
}
;
+ct_timeout_config : PROTOCOL ct_l4protoname SEMICOLON
+ {
+ struct ct_timeout *ct;
+ int l4proto = $2;
+
+ ct = &$<obj>0->ct_timeout;
+ ct->l4proto = l4proto;
+ }
+ | POLICY '=' '{' timeout_states '}'
stmt_separator
+ {
+ int l4proto = IPPROTO_TCP;
+ size_t timeout_array_size;
+ struct timeout_state *ts;
+ struct ct_timeout *ct;
+ uint32_t *timeout;
+
+ ct = &$<obj>0->ct_timeout;
+ init_list_head(&ct->timeout_state.timeout_list);
+ timeout_array_size = sizeof(uint32_t) *
(timeout_protocol[l4proto].attr_max);
+ timeout = xzalloc(timeout_array_size);
+ list_for_each_entry(ts, $4, timeout_list) {
+ if (ct->l4proto == ts->l4) {
+ timeout[ts->timeout_index] =
ts->timeout_value;
+ } else {
+ erec_queue(error(&@2, "invalid
timeout state name for given l4proto\n"), state->msgs);
+ YYERROR;
+ }
+ }
+ ct->timeout = timeout;
+ }
+ | L3PROTOCOL family_spec_explicit
stmt_separator
+ {
+ $<obj>0->ct_timeout.l3proto = $2;
+ }
+ ;
+
ct_obj_alloc :
{
$$ = obj_alloc(&@$);
@@ -3730,6 +3831,7 @@ ct_key : L3PROTOCOL { $$ =
NFT_CT_L3PROTOCOL; }
| PROTO_DST { $$ = NFT_CT_PROTO_DST; }
| LABEL { $$ = NFT_CT_LABELS; }
| EVENT { $$ = NFT_CT_EVENTMASK; }
+ | TIMEOUT { $$ = NFT_CT_TIMEOUT; }
| ct_key_dir_optional
;
@@ -3778,6 +3880,11 @@ ct_stmt : CT ct_key
SET stmt_expr
$$->objref.type = NFT_OBJECT_CT_HELPER;
$$->objref.expr = $4;
break;
+ case NFT_CT_TIMEOUT:
+ $$ = objref_stmt_alloc(&@$);
+ $$->objref.type = NFT_OBJECT_CT_TIMEOUT;
+ $$->objref.expr = $4;
+ break;
default:
$$ = ct_stmt_alloc(&@$, $2, -1, $4);
break;
diff --git a/src/rule.c b/src/rule.c
index 7a7ac73..99b0dc4 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -29,6 +29,72 @@
#include <linux/netfilter.h>
#include <linux/netfilter_arp.h>
+const char *const tcp_state_to_name[] = {
+ [NFTA_CT_TIMEOUT_ATTR_TCP_SYN_SENT] = "syn_sent",
+ [NFTA_CT_TIMEOUT_ATTR_TCP_SYN_RECV] = "syn_recv",
+ [NFTA_CT_TIMEOUT_ATTR_TCP_ESTABLISHED] = "established",
+ [NFTA_CT_TIMEOUT_ATTR_TCP_FIN_WAIT] = "fin_wait",
+ [NFTA_CT_TIMEOUT_ATTR_TCP_CLOSE_WAIT] = "close_wait",
+ [NFTA_CT_TIMEOUT_ATTR_TCP_LAST_ACK] = "last_ack",
+ [NFTA_CT_TIMEOUT_ATTR_TCP_TIME_WAIT] = "time_wait",
+ [NFTA_CT_TIMEOUT_ATTR_TCP_CLOSE] = "close",
+ [NFTA_CT_TIMEOUT_ATTR_TCP_SYN_SENT2] = "syn_sent2",
+ [NFTA_CT_TIMEOUT_ATTR_TCP_RETRANS] = "retrans",
+ [NFTA_CT_TIMEOUT_ATTR_TCP_UNACK] = "unack",
+};
+
+const char *const udp_state_to_name[] = {
+ [NFTA_CT_TIMEOUT_ATTR_UDP_UNREPLIED] = "unreplied",
+ [NFTA_CT_TIMEOUT_ATTR_UDP_REPLIED] = "replied",
+};
+
+uint32_t tcp_dflt_timeout[] = {
+ [NFTA_CT_TIMEOUT_ATTR_TCP_SYN_SENT] = 120,
+ [NFTA_CT_TIMEOUT_ATTR_TCP_SYN_RECV] = 60,
+ [NFTA_CT_TIMEOUT_ATTR_TCP_ESTABLISHED] = 432000,
+ [NFTA_CT_TIMEOUT_ATTR_TCP_FIN_WAIT] = 120,
+ [NFTA_CT_TIMEOUT_ATTR_TCP_CLOSE_WAIT] = 60,
+ [NFTA_CT_TIMEOUT_ATTR_TCP_LAST_ACK] = 30,
+ [NFTA_CT_TIMEOUT_ATTR_TCP_TIME_WAIT] = 120,
+ [NFTA_CT_TIMEOUT_ATTR_TCP_CLOSE] = 10,
+ [NFTA_CT_TIMEOUT_ATTR_TCP_SYN_SENT2] = 120,
+ [NFTA_CT_TIMEOUT_ATTR_TCP_RETRANS] = 300,
+ [NFTA_CT_TIMEOUT_ATTR_TCP_UNACK] = 300,
+
+};
+
+uint32_t udp_dflt_timeout[] = {
+ [NFTA_CT_TIMEOUT_ATTR_UDP_UNREPLIED] = 30,
+ [NFTA_CT_TIMEOUT_ATTR_UDP_REPLIED] = 180,
+};
+
+struct timeout_protocol timeout_protocol[IPPROTO_MAX] = {
+ [IPPROTO_TCP] = {
+ .attr_max = NFTA_CT_TIMEOUT_ATTR_TCP_MAX,
+ .state_to_name = tcp_state_to_name,
+ .dflt_timeout = tcp_dflt_timeout,
+ },
+ [IPPROTO_UDP] = {
+ .attr_max = NFTA_CT_TIMEOUT_ATTR_UDP_MAX,
+ .state_to_name = udp_state_to_name,
+ .dflt_timeout = udp_dflt_timeout,
+ },
+};
+
+void timeout_str2num(const char *timeout_state, struct timeout_state *ts)
+{
+ unsigned int i, l4;
+
+ for (l4 = 0; l4 < IPPROTO_MAX; l4++) {
+ for (i = 0; i < timeout_protocol[l4].attr_max; i++) {
+ if (!strcmp(timeout_protocol[l4].state_to_name[i],
timeout_state)) {
+ ts->timeout_index = i;
+ ts->l4 = l4;
+ }
+ }
+ }
+}
+
void handle_free(struct handle *h)
{
xfree(h->table.name);
@@ -1093,6 +1159,7 @@ void cmd_free(struct cmd *cmd)
case CMD_OBJ_COUNTER:
case CMD_OBJ_QUOTA:
case CMD_OBJ_CT_HELPER:
+ case CMD_OBJ_CT_TIMEOUT:
case CMD_OBJ_LIMIT:
obj_free(cmd->object);
break;
@@ -1187,6 +1254,7 @@ static int do_command_add(struct netlink_ctx *ctx, struct
cmd *cmd, bool excl)
case CMD_OBJ_COUNTER:
case CMD_OBJ_QUOTA:
case CMD_OBJ_CT_HELPER:
+ case CMD_OBJ_CT_TIMEOUT:
case CMD_OBJ_LIMIT:
return netlink_add_obj(ctx, cmd, flags);
case CMD_OBJ_FLOWTABLE:
@@ -1272,6 +1340,9 @@ static int do_command_delete(struct netlink_ctx *ctx,
struct cmd *cmd)
return netlink_delete_obj(ctx, cmd, NFT_OBJECT_QUOTA);
case CMD_OBJ_CT_HELPER:
return netlink_delete_obj(ctx, cmd, NFT_OBJECT_CT_HELPER);
+ case CMD_OBJ_CT_TIMEOUT:
+ return netlink_delete_obj(ctx, cmd,
+ NFT_OBJECT_CT_TIMEOUT);
case CMD_OBJ_LIMIT:
return netlink_delete_obj(ctx, cmd, NFT_OBJECT_LIMIT);
case CMD_OBJ_FLOWTABLE:
@@ -1417,9 +1488,28 @@ static void print_proto_name_proto(uint8_t l4, struct
output_ctx *octx)
const struct protoent *p = getprotobynumber(l4);
if (p)
- nft_print(octx, "%s\n", p->p_name);
+ nft_print(octx, "%s", p->p_name);
else
- nft_print(octx, "%d\n", l4);
+ nft_print(octx, "%d", l4);
+}
+
+static void print_proto_timeout_policy(uint8_t l4, uint32_t *timeout,
+ struct output_ctx *octx)
+{
+ unsigned int i, b = 0;
+
+ nft_print(octx, "\t\tpolicy = {");
+ for (i = 0; i < timeout_protocol[l4].attr_max; i++) {
+ if (timeout[i] != timeout_protocol[l4].dflt_timeout[i]) {
+ if (b)
+ nft_print(octx, ", ");
+ nft_print(octx, "%s: %u",
+ timeout_protocol[l4].state_to_name[i],
+ timeout[i]);
+ b = 1;
+ }
+ }
+ nft_print(octx, "}");
}
static void obj_print_data(const struct obj *obj,
@@ -1466,9 +1556,21 @@ static void obj_print_data(const struct obj *obj,
nft_print(octx, "\t\ttype \"%s\" protocol ",
obj->ct_helper.name);
print_proto_name_proto(obj->ct_helper.l4proto, octx);
+ nft_print(octx, "\n");
nft_print(octx, "\t\tl3proto %s",
family2str(obj->ct_helper.l3proto));
break;
+ case NFT_OBJECT_CT_TIMEOUT:
+ nft_print(octx, "ct timeout %s {", obj->handle.obj.name);
+ if (octx->handle > 0)
+ nft_print(octx, " # handle %" PRIu64,
obj->handle.handle.id);
+ nft_print(octx, "%s", opts->nl);
+ nft_print(octx, "\t\tprotocol ");
+ print_proto_name_proto(obj->ct_timeout.l4proto, octx);
+ nft_print(octx, ";%s", opts->nl);
+ print_proto_timeout_policy(obj->ct_timeout.l4proto,
+ obj->ct_timeout.timeout, octx);
+ break;
case NFT_OBJECT_LIMIT: {
bool inv = obj->limit.flags & NFT_LIMIT_F_INV;
const char *data_unit;
@@ -1515,6 +1617,7 @@ static const char * const obj_type_name_array[] = {
[NFT_OBJECT_QUOTA] = "quota",
[NFT_OBJECT_CT_HELPER] = "",
[NFT_OBJECT_LIMIT] = "limit",
+ [NFT_OBJECT_CT_TIMEOUT] = "",
};
const char *obj_type_name(enum stmt_types type)
@@ -1529,6 +1632,7 @@ static uint32_t obj_type_cmd_array[NFT_OBJECT_MAX + 1] = {
[NFT_OBJECT_QUOTA] = CMD_OBJ_QUOTA,
[NFT_OBJECT_CT_HELPER] = CMD_OBJ_CT_HELPER,
[NFT_OBJECT_LIMIT] = CMD_OBJ_LIMIT,
+ [NFT_OBJECT_CT_TIMEOUT] = CMD_OBJ_CT_TIMEOUT,
};
uint32_t obj_type_to_cmd(uint32_t type)
@@ -1877,6 +1981,8 @@ static int do_command_list(struct netlink_ctx *ctx,
struct cmd *cmd)
case CMD_OBJ_CT_HELPER:
case CMD_OBJ_CT_HELPERS:
return do_list_obj(ctx, cmd, NFT_OBJECT_CT_HELPER);
+ case CMD_OBJ_CT_TIMEOUT:
+ return do_list_obj(ctx, cmd, NFT_OBJECT_CT_TIMEOUT);
case CMD_OBJ_LIMIT:
case CMD_OBJ_LIMITS:
return do_list_obj(ctx, cmd, NFT_OBJECT_LIMIT);
@@ -2094,6 +2200,9 @@ struct cmd *cmd_alloc_obj_ct(enum cmd_ops op, int type,
const struct handle *h,
case NFT_OBJECT_CT_HELPER:
cmd_obj = CMD_OBJ_CT_HELPER;
break;
+ case NFT_OBJECT_CT_TIMEOUT:
+ cmd_obj = CMD_OBJ_CT_TIMEOUT;
+ break;
default:
BUG("missing type mapping");
}
diff --git a/src/statement.c b/src/statement.c
index 3040476..25d75e9 100644
--- a/src/statement.c
+++ b/src/statement.c
@@ -203,6 +203,7 @@ static const char *objref_type[NFT_OBJECT_MAX + 1] = {
[NFT_OBJECT_QUOTA] = "quota",
[NFT_OBJECT_CT_HELPER] = "ct helper",
[NFT_OBJECT_LIMIT] = "limit",
+ [NFT_OBJECT_CT_TIMEOUT] = "ct timeout",
};
const char *objref_type_name(uint32_t type)
@@ -219,6 +220,9 @@ static void objref_stmt_print(const struct stmt *stmt,
struct output_ctx *octx)
case NFT_OBJECT_CT_HELPER:
nft_print(octx, "ct helper set ");
break;
+ case NFT_OBJECT_CT_TIMEOUT:
+ nft_print(octx, "ct timeout set ");
+ break;
default:
nft_print(octx, "%s name ",
objref_type_name(stmt->objref.type));
--
2.14.1
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html