]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
add support for new set API and standalone sets
authorPatrick McHardy <kaber@trash.net>
Tue, 28 Jul 2009 12:17:35 +0000 (14:17 +0200)
committerPatrick McHardy <kaber@trash.net>
Tue, 28 Jul 2009 12:17:35 +0000 (14:17 +0200)
Signed-off-by: Patrick McHardy <kaber@trash.net>
13 files changed:
files/examples/sets_and_maps [new file with mode: 0755]
include/expression.h
include/linux/netfilter/nf_tables.h
include/netlink.h
include/rule.h
src/evaluate.c
src/expression.c
src/netlink.c
src/netlink_delinearize.c
src/netlink_linearize.c
src/parser.y
src/rule.c
src/scanner.l

diff --git a/files/examples/sets_and_maps b/files/examples/sets_and_maps
new file mode 100755 (executable)
index 0000000..8dfe9f8
--- /dev/null
@@ -0,0 +1,53 @@
+#! /sbin/nft -nf
+#
+# Examples of set and map usage
+#
+
+# symbolic anonymous set definition built from symbolic singleton definitions
+define int_if1  = eth0
+define int_if2  = eth1
+define int_ifs  = { $int_if1, $int_if2 }
+
+define ext_if1  = eth2
+define ext_if2  = eth3
+define ext_ifs  = { $ext_if1, $ext_if2 }
+
+# recursive symbolic anonymous set definition
+define local_ifs = { $int_ifs, $ext_ifs }
+
+# symbolic anonymous set definition
+define tcp_ports = { ssh, domain, https, 123-125 }
+
+delete table filter
+table filter {
+       # named set of type ifindex
+       set local_ifs {
+               type ifindex
+       }
+
+       # named map of type ifindex => ipv4_address
+       map nat_map {
+               type ifindex => ipv4_address
+       }
+
+       map jump_map {
+               type ifindex => verdict
+       }
+
+       chain input_1 { counter; }
+       chain input_2 { counter; }
+       chain input {
+               hook NF_INET_LOCAL_IN 0
+
+               # symbolic anonymous sets
+               meta iif $local_ifs tcp dport $tcp_ports counter
+
+               # literal anonymous set
+               meta iif { eth0, eth1 } counter
+
+               meta iif @local_ifs counter
+               meta iif vmap @jump_map
+
+               #meta iif vmap { eth0 => jump input1, eth1 => jump input2 }
+       }
+}
index 471033e7193be930a7287503b35e6282b429a039..88042846855a11e7a2180593824ba08764c20b86 100644 (file)
@@ -26,6 +26,7 @@
  * @EXPR_CONCAT:       concatenation
  * @EXPR_LIST:         list of expressions
  * @EXPR_SET:          literal set
+ * @EXPR_SET_REF:      set reference
  * @EXPR_MAPPING:      a single mapping (key => value)
  * @EXPR_MAP:          map operation (expr map { EXPR_MAPPING, ... })
  * @EXPR_UNARY:                byteorder conversion, generated during evaluation
@@ -46,6 +47,7 @@ enum expr_types {
        EXPR_CONCAT,
        EXPR_LIST,
        EXPR_SET,
+       EXPR_SET_REF,
        EXPR_MAPPING,
        EXPR_MAP,
        EXPR_UNARY,
@@ -82,6 +84,12 @@ enum ops {
 
 extern const char *expr_op_symbols[];
 
+enum symbol_types {
+       SYMBOL_VALUE,
+       SYMBOL_DEFINE,
+       SYMBOL_SET,
+};
+
 /**
  * struct expr_ctx - type context for symbol parsing during evaluation
  *
@@ -129,14 +137,12 @@ struct expr_ops {
  * @EXPR_F_CONSTANT:           constant expression
  * @EXPR_F_SINGLETON:          singleton (implies primary and constant)
  * @EXPR_F_INTERVAL_END:       set member ends an open interval
- * @SET_F_INTERVAL:            set includes ranges and/or prefix expressions
  */
 enum expr_flags {
        EXPR_F_PRIMARY          = 0x1,
        EXPR_F_CONSTANT         = 0x2,
        EXPR_F_SINGLETON        = 0x4,
        EXPR_F_INTERVAL_END     = 0x8,
-       SET_F_INTERVAL          = 0x10,
 };
 
 #include <payload.h>
@@ -176,6 +182,7 @@ struct expr {
                        /* EXPR_SYMBOL */
                        const struct scope      *scope;
                        const char              *identifier;
+                       enum symbol_types       symtype;
                };
                struct {
                        /* EXPR_VERDICT */
@@ -195,6 +202,11 @@ struct expr {
                        /* EXPR_CONCAT, EXPR_LIST, EXPR_SET */
                        struct list_head        expressions;
                        unsigned int            size;
+                       uint32_t                set_flags;
+               };
+               struct {
+                       /* EXPR_SET_REF */
+                       struct set              *set;
                };
                struct {
                        /* EXPR_UNARY */
@@ -285,6 +297,7 @@ extern struct expr *verdict_expr_alloc(const struct location *loc,
                                       int verdict, const char *chain);
 
 extern struct expr *symbol_expr_alloc(const struct location *loc,
+                                     enum symbol_types type, struct scope *scope,
                                      const char *identifier);
 
 static inline void symbol_expr_set_type(struct expr *expr,
@@ -324,4 +337,7 @@ extern struct expr *mapping_expr_alloc(const struct location *loc,
 extern struct expr *map_expr_alloc(const struct location *loc,
                                   struct expr *arg, struct expr *list);
 
+extern struct expr *set_ref_expr_alloc(const struct location *loc,
+                                      struct set *set);
+
 #endif /* NFTABLES_EXPRESSION_H */
index 0309b9dc42ab674329cb7217bfdf4b5672c2ab61..1c2307301e4b6a61e4c75284fd46e215aff074ae 100644 (file)
@@ -11,6 +11,17 @@ enum nft_registers {
 };
 #define NFT_REG_MAX    (__NFT_REG_MAX - 1)
 
+/**
+ * enum nft_verdicts - nf_tables internal verdicts
+ *
+ * @NFT_CONTINUE: continue evaluation of the current rule
+ * @NFT_BREAK: terminate evaluation of the current rule
+ * @NFT_JUMP: push the current chain on the jump stack and jump to a chain
+ * @NFT_GOTO: jump to a chain without pushing the current chain on the jump stack
+ * @NFT_RETURN: return to the topmost chain on the jump stack
+ *
+ * The nf_tables verdicts share their numeric space with the netfilter verdicts.
+ */
 enum nft_verdicts {
        NFT_CONTINUE    = -1,
        NFT_BREAK       = -2,
@@ -29,9 +40,20 @@ enum nf_tables_msg_types {
        NFT_MSG_NEWRULE,
        NFT_MSG_GETRULE,
        NFT_MSG_DELRULE,
+       NFT_MSG_NEWSET,
+       NFT_MSG_GETSET,
+       NFT_MSG_DELSET,
+       NFT_MSG_NEWSETELEM,
+       NFT_MSG_GETSETELEM,
+       NFT_MSG_DELSETELEM,
        NFT_MSG_MAX,
 };
 
+/**
+ * enum nft_list_attributes - nf_tables generic list netlink attributes
+ *
+ * @NFTA_LIST_ELEM: list element (NLA_NESTED)
+ */
 enum nft_list_attributes {
        NFTA_LIST_UNPEC,
        NFTA_LIST_ELEM,
@@ -39,6 +61,12 @@ enum nft_list_attributes {
 };
 #define NFTA_LIST_MAX          (__NFTA_LIST_MAX - 1)
 
+/**
+ * enum nft_hook_attributes - nf_tables netfilter hook netlink attributes
+ *
+ * @NFTA_HOOK_HOOKNUM: netfilter hook number (NLA_U32)
+ * @NFTA_HOOK_PRIORITY: netfilter hook priority (NLA_U32)
+ */
 enum nft_hook_attributes {
        NFTA_HOOK_UNSPEC,
        NFTA_HOOK_HOOKNUM,
@@ -47,6 +75,11 @@ enum nft_hook_attributes {
 };
 #define NFTA_HOOK_MAX          (__NFTA_HOOK_MAX - 1)
 
+/**
+ * enum nft_table_attributes - nf_tables table netlink attributes
+ *
+ * @NFTA_TABLE_NAME: name of the table (NLA_STRING)
+ */
 enum nft_table_attributes {
        NFTA_TABLE_UNSPEC,
        NFTA_TABLE_NAME,
@@ -54,6 +87,13 @@ enum nft_table_attributes {
 };
 #define NFTA_TABLE_MAX         (__NFTA_TABLE_MAX - 1)
 
+/**
+ * enum nft_chain_attributes - nf_tables chain netlink attributes
+ *
+ * @NFTA_CHAIN_TABLE: name of the table containing the chain (NLA_STRING)
+ * @NFTA_CHAIN_NAME: name of the chain (NLA_STRING)
+ * @NFTA_CHAIN_HOOK: hook specification for basechains (NLA_NESTED: nft_hook_attributes)
+ */
 enum nft_chain_attributes {
        NFTA_CHAIN_UNSPEC,
        NFTA_CHAIN_TABLE,
@@ -63,6 +103,14 @@ enum nft_chain_attributes {
 };
 #define NFTA_CHAIN_MAX         (__NFTA_CHAIN_MAX - 1)
 
+/**
+ * enum nft_rule_attributes - nf_tables rule netlink attributes
+ *
+ * @NFTA_RULE_TABLE: name of the table containing the rule (NLA_STRING)
+ * @NFTA_RULE_CHAIN: name of the chain containing the rule (NLA_STRING)
+ * @NFTA_RULE_HANDLE: numeric handle of the rule (NLA_U16)
+ * @NFTA_RULE_EXPRESSIONS: list of expressions (NLA_NESTED: nft_expr_attributes)
+ */
 enum nft_rule_attributes {
        NFTA_RULE_UNSPEC,
        NFTA_RULE_TABLE,
@@ -73,6 +121,113 @@ enum nft_rule_attributes {
 };
 #define NFTA_RULE_MAX          (__NFTA_RULE_MAX - 1)
 
+/**
+ * enum nft_set_flags - nf_tables set flags
+ *
+ * @NFT_SET_ANONYMOUS: name allocation, automatic cleanup on unlink
+ * @NFT_SET_CONSTANT: set contents may not change while bound
+ * @NFT_SET_INTERVAL: set contains intervals
+ * @NFT_SET_MAP: set is used as a dictionary
+ */
+enum nft_set_flags {
+       NFT_SET_ANONYMOUS               = 0x1,
+       NFT_SET_CONSTANT                = 0x2,
+       NFT_SET_INTERVAL                = 0x4,
+       NFT_SET_MAP                     = 0x8,
+};
+
+/**
+ * enum nft_set_attributes - nf_tables set netlink attributes
+ *
+ * @NFTA_SET_TABLE: table name (NLA_STRING)
+ * @NFTA_SET_NAME: set name (NLA_STRING)
+ * @NFTA_SET_FLAGS: bitmask of enum nft_set_flags (NLA_U32)
+ * @NFTA_SET_KEY_TYPE: key data type, informational purpose only (NLA_U32)
+ * @NFTA_SET_KEY_LEN: key data length (NLA_U32)
+ * @NFTA_SET_DATA_TYPE: mapping data type (NLA_U32)
+ * @NFTA_SET_DATA_LEN: mapping data length (NLA_U32)
+ */
+enum nft_set_attributes {
+       NFTA_SET_UNSPEC,
+       NFTA_SET_TABLE,
+       NFTA_SET_NAME,
+       NFTA_SET_FLAGS,
+       NFTA_SET_KEY_TYPE,
+       NFTA_SET_KEY_LEN,
+       NFTA_SET_DATA_TYPE,
+       NFTA_SET_DATA_LEN,
+       __NFTA_SET_MAX
+};
+#define NFTA_SET_MAX           (__NFTA_SET_MAX - 1)
+
+/**
+ * enum nft_set_elem_flags - nf_tables set element flags
+ *
+ * @NFT_SET_ELEM_INTERVAL_END: element ends the previous interval
+ */
+enum nft_set_elem_flags {
+       NFT_SET_ELEM_INTERVAL_END       = 0x1,
+};
+
+/**
+ * enum nft_set_elem_attributes - nf_tables set element netlink attributes
+ *
+ * @NFTA_SET_ELEM_KEY: key value (NLA_NESTED: nft_data)
+ * @NFTA_SET_ELEM_DATA: data value of mapping (NLA_NESTED: nft_data_attributes)
+ * @NFTA_SET_ELEM_FLAGS: bitmask of nft_set_elem_flags (NLA_U32)
+ */
+enum nft_set_elem_attributes {
+       NFTA_SET_ELEM_UNSPEC,
+       NFTA_SET_ELEM_KEY,
+       NFTA_SET_ELEM_DATA,
+       NFTA_SET_ELEM_FLAGS,
+       __NFTA_SET_ELEM_MAX
+};
+#define NFTA_SET_ELEM_MAX      (__NFTA_SET_ELEM_MAX - 1)
+
+/**
+ * enum nft_set_elem_list_attributes - nf_tables set element list netlink attributes
+ *
+ * @NFTA_SET_ELEM_LIST_TABLE: table of the set to be changed (NLA_STRING)
+ * @NFTA_SET_ELEM_LIST_SET: name of the set to be changed (NLA_STRING)
+ * @NFTA_SET_ELEM_LIST_ELEMENTS: list of set elements (NLA_NESTED: nft_set_elem_attributes)
+ */
+enum nft_set_elem_list_attributes {
+       NFTA_SET_ELEM_LIST_UNSPEC,
+       NFTA_SET_ELEM_LIST_TABLE,
+       NFTA_SET_ELEM_LIST_SET,
+       NFTA_SET_ELEM_LIST_ELEMENTS,
+       __NFTA_SET_ELEM_LIST_MAX
+};
+#define NFTA_SET_ELEM_LIST_MAX (__NFTA_SET_ELEM_LIST_MAX - 1)
+
+/**
+ * enum nft_data_types - nf_tables data types
+ *
+ * @NFT_DATA_VALUE: generic data
+ * @NFT_DATA_VERDICT: netfilter verdict
+ *
+ * The type of data is usually determined by the kernel directly and is not
+ * explicitly specified by userspace. The only difference are sets, where
+ * userspace specifies the key and mapping data types.
+ *
+ * The values 0xffffff00-0xffffffff are reserved for internally used types.
+ * The remaining range can be freely used by userspace to encode types, all
+ * values are equivalent to NFT_DATA_VALUE.
+ */
+enum nft_data_types {
+       NFT_DATA_VALUE,
+       NFT_DATA_VERDICT        = 0xffffff00U,
+};
+
+#define NFT_DATA_RESERVED_MASK 0xffffff00U
+
+/**
+ * enum nft_data_attributes - nf_tables data netlink attributes
+ *
+ * @NFTA_DATA_VALUE: generic data (NLA_BINARY)
+ * @NFTA_DATA_VERDICT: nf_tables verdict (NLA_NESTED: nft_verdict_attributes)
+ */
 enum nft_data_attributes {
        NFTA_DATA_UNSPEC,
        NFTA_DATA_VALUE,
@@ -81,6 +236,12 @@ enum nft_data_attributes {
 };
 #define NFTA_DATA_MAX          (__NFTA_DATA_MAX - 1)
 
+/**
+ * enum nft_verdict_attributes - nf_tables verdict netlink attributes
+ *
+ * @NFTA_VERDICT_CODE: nf_tables verdict (NLA_U32: enum nft_verdicts)
+ * @NFTA_VERDICT_CHAIN: jump target chain name (NLA_STRING)
+ */
 enum nft_verdict_attributes {
        NFTA_VERDICT_UNSPEC,
        NFTA_VERDICT_CODE,
@@ -89,6 +250,12 @@ enum nft_verdict_attributes {
 };
 #define NFTA_VERDICT_MAX       (__NFTA_VERDICT_MAX - 1)
 
+/**
+ * enum nft_expr_attributes - nf_tables expression netlink attributes
+ *
+ * @NFTA_EXPR_NAME: name of the expression type (NLA_STRING)
+ * @NFTA_EXPR_DATA: type specific data (NLA_NESTED)
+ */
 enum nft_expr_attributes {
        NFTA_EXPR_UNSPEC,
        NFTA_EXPR_NAME,
@@ -97,6 +264,12 @@ enum nft_expr_attributes {
 };
 #define NFTA_EXPR_MAX          (__NFTA_EXPR_MAX - 1)
 
+/**
+ * enum nft_immediate_attributes - nf_tables immediate expression netlink attributes
+ *
+ * @NFTA_IMMEDIATE_DREG: destination register to load data into (NLA_U32)
+ * @NFTA_IMMEDIATE_DATA: data to load (NLA_NESTED: nft_data_attributes)
+ */
 enum nft_immediate_attributes {
        NFTA_IMMEDIATE_UNSPEC,
        NFTA_IMMEDIATE_DREG,
@@ -105,6 +278,27 @@ enum nft_immediate_attributes {
 };
 #define NFTA_IMMEDIATE_MAX     (__NFTA_IMMEDIATE_MAX - 1)
 
+/**
+ * enum nft_bitwise_attributes - nf_tables bitwise expression netlink attributes
+ *
+ * @NFTA_BITWISE_SREG: source register (NLA_U32: nft_registers)
+ * @NFTA_BITWISE_DREG: destination register (NLA_U32: nft_registers)
+ * @NFTA_BITWISE_LEN: length of operands (NLA_U32)
+ * @NFTA_BITWISE_MASK: mask value (NLA_NESTED: nft_data_attributes)
+ * @NFTA_BITWISE_XOR: xor value (NLA_NESTED: nft_data_attributes)
+ *
+ * The bitwise expression performs the following operation:
+ *
+ * dreg = (sreg & mask) ^ xor
+ *
+ * which allow to express all bitwise operations:
+ *
+ *             mask    xor
+ * NOT:                1       1
+ * OR:         0       x
+ * XOR:                1       x
+ * AND:                x       0
+ */
 enum nft_bitwise_attributes {
        NFTA_BITWISE_UNSPEC,
        NFTA_BITWISE_SREG,
@@ -141,6 +335,13 @@ enum nft_cmp_ops {
        NFT_CMP_GTE,
 };
 
+/**
+ * enum nft_cmp_attributes - nf_tables cmp expression netlink attributes
+ *
+ * @NFTA_CMP_SREG: source register of data to compare (NLA_U32: nft_registers)
+ * @NFTA_CMP_OP: cmp operation (NLA_U32: nft_cmp_ops)
+ * @NFTA_CMP_DATA: data to compare against (NLA_NESTED: nft_data_attributes)
+ */
 enum nft_cmp_attributes {
        NFTA_CMP_UNSPEC,
        NFTA_CMP_SREG,
@@ -150,65 +351,36 @@ enum nft_cmp_attributes {
 };
 #define NFTA_CMP_MAX           (__NFTA_CMP_MAX - 1)
 
-enum nft_set_elem_flags {
-       NFT_SE_INTERVAL_END     = 0x1,
-};
-
-enum nft_set_elem_attributes {
-       NFTA_SE_UNSPEC,
-       NFTA_SE_KEY,
-       NFTA_SE_DATA,
-       NFTA_SE_FLAGS,
-       __NFTA_SE_MAX
-};
-#define NFTA_SE_MAX            (__NFTA_SE_MAX - 1)
-
-enum nft_set_flags {
-       NFT_SET_INTERVAL        = 0x1,
-       NFT_SET_MAP             = 0x2,
-};
-
-enum nft_set_attributes {
-       NFTA_SET_UNSPEC,
-       NFTA_SET_FLAGS,
-       NFTA_SET_SREG,
-       NFTA_SET_DREG,
-       NFTA_SET_KLEN,
-       NFTA_SET_DLEN,
-       NFTA_SET_ELEMENTS,
-       __NFTA_SET_MAX
-};
-#define NFTA_SET_MAX           (__NFTA_SET_MAX - 1)
-
-enum nft_hash_flags {
-       NFT_HASH_MAP            = 0x1,
-};
-
-enum nft_hash_elem_attributes {
-       NFTA_HE_UNSPEC,
-       NFTA_HE_KEY,
-       NFTA_HE_DATA,
-       __NFTA_HE_MAX
-};
-#define NFTA_HE_MAX            (__NFTA_HE_MAX - 1)
-
-enum nft_hash_attributes {
-       NFTA_HASH_UNSPEC,
-       NFTA_HASH_FLAGS,
-       NFTA_HASH_SREG,
-       NFTA_HASH_DREG,
-       NFTA_HASH_KLEN,
-       NFTA_HASH_ELEMENTS,
-       __NFTA_HASH_MAX
-};
-#define NFTA_HASH_MAX          (__NFTA_HASH_MAX - 1)
-
+enum nft_lookup_attributes {
+       NFTA_LOOKUP_UNSPEC,
+       NFTA_LOOKUP_SET,
+       NFTA_LOOKUP_SREG,
+       NFTA_LOOKUP_DREG,
+       __NFTA_LOOKUP_MAX
+};
+#define NFTA_LOOKUP_MAX                (__NFTA_LOOKUP_MAX - 1)
+
+/**
+ * enum nft_payload_bases - nf_tables payload expression offset bases
+ *
+ * @NFT_PAYLOAD_LL_HEADER: link layer header
+ * @NFT_PAYLOAD_NETWORK_HEADER: network header
+ * @NFT_PAYLOAD_TRANSPORT_HEADER: transport header
+ */
 enum nft_payload_bases {
        NFT_PAYLOAD_LL_HEADER,
        NFT_PAYLOAD_NETWORK_HEADER,
        NFT_PAYLOAD_TRANSPORT_HEADER,
 };
 
+/**
+ * enum nft_payload_attributes - nf_tables payload expression netlink attributes
+ *
+ * @NFTA_PAYLOAD_DREG: destination register to load data into (NLA_U32: nft_registers)
+ * @NFTA_PAYLOAD_BASE: payload base (NLA_U32: nft_payload_bases)
+ * @NFTA_PAYLOAD_OFFSET: payload offset relative to base (NLA_U32)
+ * @NFTA_PAYLOAD_LEN: payload length (NLA_U32)
+ */
 enum nft_payload_attributes {
        NFTA_PAYLOAD_UNSPEC,
        NFTA_PAYLOAD_DREG,
@@ -229,6 +401,25 @@ enum nft_exthdr_attributes {
 };
 #define NFTA_EXTHDR_MAX                (__NFTA_EXTHDR_MAX - 1)
 
+/**
+ * enum nft_meta_keys - nf_tables meta expression keys
+ *
+ * @NFT_META_LEN: packet length (skb->len)
+ * @NFT_META_PROTOCOL: packet ethertype protocol (skb->protocol), invalid in OUTPUT
+ * @NFT_META_PRIORITY: packet priority (skb->priority)
+ * @NFT_META_MARK: packet mark (skb->mark)
+ * @NFT_META_IIF: packet input interface index (dev->ifindex)
+ * @NFT_META_OIF: packet output interface index (dev->ifindex)
+ * @NFT_META_IIFNAME: packet input interface name (dev->name)
+ * @NFT_META_OIFNAME: packet output interface name (dev->name)
+ * @NFT_META_IIFTYPE: packet input interface type (dev->type)
+ * @NFT_META_OIFTYPE: packet output interface type (dev->type)
+ * @NFT_META_SKUID: originating socket UID (fsuid)
+ * @NFT_META_SKGID: originating socket GID (fsgid)
+ * @NFT_META_NFTRACE: packet nftrace bit
+ * @NFT_META_RTCLASSID: realm value of packet's route (skb->dst->tclassid)
+ * @NFT_META_SECMARK: packet secmark (skb->secmark)
+ */
 enum nft_meta_keys {
        NFT_META_LEN,
        NFT_META_PROTOCOL,
@@ -247,6 +438,12 @@ enum nft_meta_keys {
        NFT_META_SECMARK,
 };
 
+/**
+ * enum nft_meta_attributes - nf_tables meta expression netlink attributes
+ *
+ * @NFTA_META_DREG: destination register (NLA_U32)
+ * @NFTA_META_KEY: meta data item to load (NLA_U32: nft_meta_keys)
+ */
 enum nft_meta_attributes {
        NFTA_META_UNSPEC,
        NFTA_META_DREG,
@@ -255,6 +452,23 @@ enum nft_meta_attributes {
 };
 #define NFTA_META_MAX          (__NFTA_META_MAX - 1)
 
+/**
+ * enum nft_ct_keys - nf_tables ct expression keys
+ *
+ * @NFT_CT_STATE: conntrack state (bitmask of enum ip_conntrack_info)
+ * @NFT_CT_DIRECTION: conntrack direction (enum ip_conntrack_dir)
+ * @NFT_CT_STATUS: conntrack status (bitmask of enum ip_conntrack_status)
+ * @NFT_CT_MARK: conntrack mark value
+ * @NFT_CT_SECMARK: conntrack secmark value
+ * @NFT_CT_EXPIRATION: relative conntrack expiration time in ms
+ * @NFT_CT_HELPER: connection tracking helper assigned to conntrack
+ * @NFT_CT_L3PROTOCOL: conntrack layer 3 protocol
+ * @NFT_CT_SRC: conntrack layer 3 protocol source (IPv4/IPv6 address)
+ * @NFT_CT_DST: conntrack layer 3 protocol destination (IPv4/IPv6 address)
+ * @NFT_CT_PROTOCOL: conntrack layer 4 protocol
+ * @NFT_CT_PROTO_SRC: conntrack layer 4 protocol source
+ * @NFT_CT_PROTO_DST: conntrack layer 4 protocol destination
+ */
 enum nft_ct_keys {
        NFT_CT_STATE,
        NFT_CT_DIRECTION,
@@ -271,6 +485,13 @@ enum nft_ct_keys {
        NFT_CT_PROTO_DST,
 };
 
+/**
+ * enum nft_ct_attributes - nf_tables ct expression netlink attributes
+ *
+ * @NFTA_CT_DREG: destination register (NLA_U32)
+ * @NFTA_CT_KEY: conntrack data item to load (NLA_U32: nft_ct_keys)
+ * @NFTA_CT_DIRECTION: direction in case of directional keys (NLA_U8)
+ */
 enum nft_ct_attributes {
        NFTA_CT_UNSPEC,
        NFTA_CT_DREG,
@@ -280,6 +501,12 @@ enum nft_ct_attributes {
 };
 #define NFTA_CT_MAX            (__NFTA_CT_MAX - 1)
 
+/**
+ * enum nft_limit_attributes - nf_tables limit expression netlink attributes
+ *
+ * @NFTA_LIMIT_RATE: refill rate (NLA_U64)
+ * @NFTA_LIMIT_DEPTH: bucket depth (NLA_U64)
+ */
 enum nft_limit_attributes {
        NFTA_LIMIT_UNSPEC,
        NFTA_LIMIT_RATE,
@@ -288,6 +515,12 @@ enum nft_limit_attributes {
 };
 #define NFTA_LIMIT_MAX         (__NFTA_LIMIT_MAX - 1)
 
+/**
+ * enum nft_counter_attributes - nf_tables counter expression netlink attributes
+ *
+ * @NFTA_COUNTER_BYTES: number of bytes (NLA_U64)
+ * @NFTA_COUNTER_PACKETS: number of packets (NLA_U64)
+ */
 enum nft_counter_attributes {
        NFTA_COUNTER_UNSPEC,
        NFTA_COUNTER_BYTES,
@@ -296,6 +529,14 @@ enum nft_counter_attributes {
 };
 #define NFTA_COUNTER_MAX       (__NFTA_COUNTER_MAX - 1)
 
+/**
+ * enum nft_log_attributes - nf_tables log expression netlink attributes
+ *
+ * @NFTA_LOG_GROUP: netlink group to send messages to (NLA_U32)
+ * @NFTA_LOG_PREFIX: prefix to prepend to log messages (NLA_STRING)
+ * @NFTA_LOG_SNAPLEN: length of payload to include in netlink message (NLA_U32)
+ * @NFTA_LOG_QTHRESHOLD: queue threshold (NLA_U32)
+ */
 enum nft_log_attributes {
        NFTA_LOG_UNSPEC,
        NFTA_LOG_GROUP,
@@ -306,11 +547,23 @@ enum nft_log_attributes {
 };
 #define NFTA_LOG_MAX           (__NFTA_LOG_MAX - 1)
 
+/**
+ * enum nft_reject_types - nf_tables reject expression reject types
+ *
+ * @NFT_REJECT_ICMP_UNREACH: reject using ICMP unreachable
+ * @NFT_REJECT_TCP_RST: reject using TCP RST
+ */
 enum nft_reject_types {
        NFT_REJECT_ICMP_UNREACH,
        NFT_REJECT_TCP_RST,
 };
 
+/**
+ * enum nft_reject_attributes - nf_tables reject expression netlink attributes
+ *
+ * @NFTA_REJECT_TYPE: packet type to use (NLA_U32: nft_reject_types)
+ * @NFTA_REJECT_ICMP_CODE: ICMP code to use (NLA_U8)
+ */
 enum nft_reject_attributes {
        NFTA_REJECT_UNSPEC,
        NFTA_REJECT_TYPE,
@@ -319,11 +572,26 @@ enum nft_reject_attributes {
 };
 #define NFTA_REJECT_MAX                (__NFTA_REJECT_MAX - 1)
 
+/**
+ * enum nft_nat_types - nf_tables nat expression NAT types
+ *
+ * @NFT_NAT_SNAT: source NAT
+ * @NFT_NAT_DNAT: destination NAT
+ */
 enum nft_nat_types {
        NFT_NAT_SNAT,
        NFT_NAT_DNAT,
 };
 
+/**
+ * enum nft_nat_attributes - nf_tables nat expression netlink attributes
+ *
+ * @NFTA_NAT_TYPE: NAT type (NLA_U32: nft_nat_types)
+ * @NFTA_NAT_ADDR_MIN: source register of address range start (NLA_U32: nft_registers)
+ * @NFTA_NAT_ADDR_MAX: source register of address range end (NLA_U32: nft_registers)
+ * @NFTA_NAT_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers)
+ * @NFTA_NAT_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers)
+ */
 enum nft_nat_attributes {
        NFTA_NAT_UNSPEC,
        NFTA_NAT_TYPE,
index ec9a614281f98b71615861eee87b1cc45edee2f1..22ef489c9f744dcaa74b58aca07d418d82d0b505 100644 (file)
  *
  * @msgs:      message queue
  * @list:      list of parsed rules/chains/tables
+ * @set:       current set
  */
 struct netlink_ctx {
        struct list_head        *msgs;
        struct list_head        list;
+       struct set              *set;
 };
 
 extern void netlink_dump_object(struct nl_object *obj);
@@ -28,6 +30,7 @@ extern struct nfnl_nft_table *alloc_nft_table(const struct handle *h);
 extern struct nfnl_nft_chain *alloc_nft_chain(const struct handle *h);
 extern struct nfnl_nft_rule *alloc_nft_rule(const struct handle *h);
 extern struct nfnl_nft_expr *alloc_nft_expr(int (*init)(struct nfnl_nft_expr *));
+extern struct nfnl_nft_set *alloc_nft_set(const struct handle *h);
 extern struct nfnl_nft_data *alloc_nft_data(const void *data, unsigned int len);
 
 extern struct nfnl_nft_data *netlink_gen_data(const struct expr *expr);
@@ -68,4 +71,17 @@ extern int netlink_get_table(struct netlink_ctx *ctx, const struct handle *h);
 extern int netlink_list_table(struct netlink_ctx *ctx, const struct handle *h);
 extern int netlink_flush_table(struct netlink_ctx *ctx, const struct handle *h);
 
+extern int netlink_add_set(struct netlink_ctx *ctx, const struct handle *h,
+                          struct set *set);
+extern int netlink_delete_set(struct netlink_ctx *ctx, const struct handle *h);
+extern int netlink_list_sets(struct netlink_ctx *ctx, const struct handle *h);
+extern int netlink_get_set(struct netlink_ctx *ctx, const struct handle *h);
+
+extern int netlink_add_setelems(struct netlink_ctx *ctx, const struct handle *h,
+                               const struct expr *expr);
+extern int netlink_delete_setelems(struct netlink_ctx *ctx, const struct handle *h,
+                                  const struct expr *expr);
+extern int netlink_get_setelems(struct netlink_ctx *ctx, const struct handle *h,
+                               struct set *set);
+
 #endif /* NFTABLES_NETLINK_H */
index 01eeb2102a89faa529cadfcee5a88c729f14c66d..9754307274ef5f51a859bb7e741e291d2f57f9b7 100644 (file)
@@ -6,17 +6,19 @@
 #include <list.h>
 
 /**
- * struct handle - handle for tables, chains and rules
+ * struct handle - handle for tables, chains, rules and sets
  *
  * @family:    protocol family
  * @table:     table name
  * @chain:     chain name (chains and rules only)
+ * @set:       set name (sets only)
  * @handle:    rule handle (rules only)
  */
 struct handle {
        int                     family;
        const char              *table;
        const char              *chain;
+       const char              *set;
        uint32_t                handle;
 };
 
@@ -61,12 +63,14 @@ extern struct symbol *symbol_lookup(const struct scope *scope,
  * @list:      list node
  * @handle:    table handle
  * @chains:    chains contained in the table
+ * @sets:      sets contained in the table
  */
 struct table {
        struct list_head        list;
        struct handle           handle;
        struct scope            scope;
        struct list_head        chains;
+       struct list_head        sets;
 };
 
 extern struct table *table_alloc(void);
@@ -120,6 +124,53 @@ extern struct rule *rule_alloc(const struct location *loc,
 extern void rule_free(struct rule *rule);
 extern void rule_print(const struct rule *rule);
 
+/**
+ * enum set_flags
+ *
+ * @SET_F_CONSTANT:            Set content is constant
+ * @SET_F_INTERVAL:            set includes ranges and/or prefix expressions
+ */
+enum set_flags {
+       SET_F_ANONYMOUS         = 0x1,
+       SET_F_CONSTANT          = 0x2,
+       SET_F_INTERVAL          = 0x4,
+       SET_F_MAP               = 0x8,
+};
+
+/**
+ * struct set - nftables set
+ *
+ * @list:      table set list node
+ * @handle:    set handle
+ * @location:  location the set was defined/declared at
+ * @refcnt:    reference count
+ * @flags:     bitmask of set flags
+ * @keytype:   key data type
+ * @keylen:    key length
+ * @datatype:  mapping data type
+ * @datalen:   mapping data len
+ * @init:      initializer
+ */
+struct set {
+       struct list_head        list;
+       struct handle           handle;
+       struct location         location;
+       unsigned int            refcnt;
+       uint32_t                flags;
+       const struct datatype   *keytype;
+       unsigned int            keylen;
+       const struct datatype   *datatype;
+       unsigned int            datalen;
+       struct expr             *init;
+};
+
+extern struct set *set_alloc(const struct location *loc);
+extern struct set *set_get(struct set *set);
+extern void set_free(struct set *set);
+extern void set_add_hash(struct set *set, struct table *table);
+extern struct set *set_lookup(const struct table *table, const char *name);
+extern void set_print(const struct set *set);
+
 /**
  * enum cmd_ops - command operations
  *
@@ -141,12 +192,18 @@ enum cmd_ops {
  * enum cmd_obj - command objects
  *
  * @CMD_OBJ_INVALID:   invalid
+ * @CMD_OBJ_SETELEM:   set element(s)
+ * @CMD_OBJ_SET:       set
+ * @CMD_OBJ_SETS:      multiple sets
  * @CMD_OBJ_RULE:      rule
  * @CMD_OBJ_CHAIN:     chain
  * @CMD_OBJ_TABLE:     table
  */
 enum cmd_obj {
        CMD_OBJ_INVALID,
+       CMD_OBJ_SETELEM,
+       CMD_OBJ_SET,
+       CMD_OBJ_SETS,
        CMD_OBJ_RULE,
        CMD_OBJ_CHAIN,
        CMD_OBJ_TABLE,
@@ -170,6 +227,8 @@ struct cmd {
        struct handle           handle;
        union {
                void            *data;
+               struct expr     *expr;
+               struct set      *set;
                struct rule     *rule;
                struct chain    *chain;
                struct table    *table;
@@ -187,12 +246,18 @@ extern void cmd_free(struct cmd *cmd);
  * struct eval_ctx - evaluation context
  *
  * @msgs:      message queue
+ * @cmd:       current command
+ * @table:     current table
+ * @set:       current set
  * @stmt:      current statement
  * @ectx:      expression context
  * @pctx:      payload context
  */
 struct eval_ctx {
        struct list_head        *msgs;
+       struct cmd              *cmd;
+       struct table            *table;
+       struct set              *set;
        struct stmt             *stmt;
        struct expr_ctx         ectx;
        struct payload_ctx      pctx;
index ed3c688c3be8015b3355c86ae25a5e6d92fe7bb6..f3723779d13b1537fbad37b8df257d410dc5174f 100644 (file)
@@ -52,6 +52,78 @@ static int __fmtstring(4, 5) stmt_binary_error(struct eval_ctx *ctx,
        return -1;
 }
 
+static int __fmtstring(3, 4) set_error(struct eval_ctx *ctx,
+                                      const struct set *set,
+                                      const char *fmt, ...)
+{
+       struct error_record *erec;
+       va_list ap;
+
+       va_start(ap, fmt);
+       erec = erec_vcreate(EREC_ERROR, &set->location, fmt, ap);
+       va_end(ap);
+       erec_queue(erec, ctx->msgs);
+       return -1;
+}
+
+static struct expr *implicit_set_declaration(struct eval_ctx *ctx,
+                                            const struct datatype *keytype,
+                                            unsigned int keylen,
+                                            struct expr *expr)
+{
+       struct cmd *cmd;
+       struct set *set;
+
+       set = set_alloc(&expr->location);
+       set->flags      = SET_F_CONSTANT | SET_F_ANONYMOUS | expr->set_flags;
+       set->handle.set = xstrdup(set->flags & SET_F_MAP ? "map%d" : "set%d");
+       set->keytype    = keytype;
+       set->keylen     = keylen;
+       set->init       = expr;
+
+       if (ctx->table != NULL)
+               list_add_tail(&set->list, &ctx->table->sets);
+       else {
+               handle_merge(&set->handle, &ctx->cmd->handle);
+               cmd = cmd_alloc(CMD_ADD, CMD_OBJ_SET, &set->handle, set);
+               cmd->location = set->location;
+               list_add_tail(&cmd->list, &ctx->cmd->list);
+       }
+
+       return set_ref_expr_alloc(&expr->location, set);
+}
+
+// FIXME
+#include <netlink.h>
+static struct set *get_set(struct eval_ctx *ctx, const struct handle *h,
+                          const char *identifier)
+{
+       struct netlink_ctx nctx = {
+               .msgs = ctx->msgs,
+       };
+       struct handle handle;
+       struct set *set;
+       int err;
+
+       if (ctx->table != NULL) {
+               set = set_lookup(ctx->table, identifier);
+               if (set != NULL)
+                       return set;
+       }
+
+       init_list_head(&nctx.list);
+
+       memset(&handle, 0, sizeof(handle));
+       handle_merge(&handle, h);
+       handle.set = xstrdup(identifier);
+       err = netlink_get_set(&nctx, &handle);
+       handle_free(&handle);
+
+       if (err < 0)
+               return NULL;
+       return list_first_entry(&nctx.list, struct set, list);
+}
+
 static enum ops byteorder_conversion_op(struct expr *expr,
                                        enum byteorder byteorder)
 {
@@ -103,23 +175,32 @@ static int expr_evaluate_symbol(struct eval_ctx *ctx, struct expr **expr)
 {
        struct error_record *erec;
        struct symbol *sym;
+       struct set *set;
        struct expr *new;
 
-       (*expr)->dtype = ctx->ectx.dtype;
-
-       if ((*expr)->scope != NULL) {
+       switch ((*expr)->symtype) {
+       case SYMBOL_VALUE:
+               (*expr)->dtype = ctx->ectx.dtype;
+               erec = symbol_parse(*expr, &new);
+               if (erec != NULL) {
+                       erec_queue(erec, ctx->msgs);
+                       return -1;
+               }
+               break;
+       case SYMBOL_DEFINE:
                sym = symbol_lookup((*expr)->scope, (*expr)->identifier);
                if (sym == NULL)
                        return expr_error(ctx, *expr,
                                          "undefined identifier '%s'",
                                          (*expr)->identifier);
                new = expr_clone(sym->expr);
-       } else {
-               erec = symbol_parse(*expr, &new);
-               if (erec != NULL) {
-                       erec_queue(erec, ctx->msgs);
+               break;
+       case SYMBOL_SET:
+               set = get_set(ctx, &ctx->cmd->handle, (*expr)->identifier);
+               if (set == NULL)
                        return -1;
-               }
+               new = set_ref_expr_alloc(&(*expr)->location, set);
+               break;
        }
 
        expr_free(*expr);
@@ -548,10 +629,18 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr)
        list_for_each_entry_safe(i, next, &set->expressions, list) {
                if (list_member_evaluate(ctx, &i) < 0)
                        return -1;
+
                if (!expr_is_constant(i))
                        return expr_error(ctx, i, "Set member is not constant");
-               if (!expr_is_singleton(i))
-                       set->flags |= SET_F_INTERVAL;
+
+               if (i->ops->type == EXPR_SET) {
+                       /* Merge recursive set definitions */
+                       list_splice_tail_init(&i->expressions, &i->list);
+                       list_del(&i->list);
+                       set->set_flags |= i->set_flags;
+                       expr_free(i);
+               } else if (!expr_is_singleton(i))
+                       set->set_flags |= SET_F_INTERVAL;
        }
 
        set->dtype = ctx->ectx.dtype;
@@ -563,7 +652,7 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr)
 static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
 {
        struct expr_ctx ectx = ctx->ectx;
-       struct expr *map = *expr, *i;
+       struct expr *map = *expr, *mappings;
 
        if (expr_evaluate(ctx, &map->expr) < 0)
                return -1;
@@ -571,39 +660,71 @@ static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
                return expr_error(ctx, map->expr,
                                  "Map expression can not be constant");
 
-       /* FIXME: segtree needs to know the dimension of the *key*.
-        * The len should actually be the value of the mapping. */
-       map->mappings->dtype = ctx->ectx.dtype;
-       map->mappings->len   = ctx->ectx.len;
+       mappings = map->mappings;
+       mappings->set_flags |= SET_F_MAP;
 
-       list_for_each_entry(i, &map->mappings->expressions, list) {
-               expr_set_context(&ctx->ectx, map->expr->dtype, map->expr->len);
-               if (expr_evaluate(ctx, &i->left) < 0)
+       switch (map->mappings->ops->type) {
+       case EXPR_SET:
+               mappings = implicit_set_declaration(ctx, ctx->ectx.dtype,
+                                                   ctx->ectx.len, mappings);
+               mappings->set->datatype = ectx.dtype;
+               mappings->set->datalen  = ectx.len;
+
+               map->mappings = mappings;
+
+               ctx->set = mappings->set;
+               if (expr_evaluate(ctx, &map->mappings->set->init) < 0)
                        return -1;
-               if (!expr_is_constant(i->left))
-                       return expr_error(ctx, i->left,
-                                         "Key must be a constant");
-               if (!expr_is_singleton(i->left))
-                       map->mappings->flags |= SET_F_INTERVAL;
-
-               expr_set_context(&ctx->ectx, ectx.dtype, ectx.len);
-               if (expr_evaluate(ctx, &i->right) < 0)
+               ctx->set = NULL;
+               break;
+       case EXPR_SYMBOL:
+               if (expr_evaluate(ctx, &map->mappings) < 0)
                        return -1;
-               if (!expr_is_constant(i->right))
-                       return expr_error(ctx, i->right,
-                                         "Mapping must be a constant");
-               if (!expr_is_singleton(i->right))
-                       return expr_error(ctx, i->right,
-                                         "Mapping must be a singleton");
+               if (map->mappings->ops->type != EXPR_SET_REF)
+                       return expr_error(ctx, map->mappings,
+                                         "Expression is not a map");
+               break;
+       default:
+               BUG();
        }
 
        map->dtype = ctx->ectx.dtype;
        map->flags |= EXPR_F_CONSTANT;
 
        /* Data for range lookups needs to be in big endian order */
-       if (map->mappings->flags & SET_F_INTERVAL &&
+       if (map->mappings->set_flags & SET_F_INTERVAL &&
            byteorder_conversion(ctx, &map->expr, BYTEORDER_BIG_ENDIAN) < 0)
                return -1;
+
+       return 0;
+}
+
+static int expr_evaluate_mapping(struct eval_ctx *ctx, struct expr **expr)
+{
+       struct expr *mapping = *expr;
+       struct set *set = ctx->set;
+
+       if (set == NULL)
+               return expr_error(ctx, mapping, "mapping outside of map context");
+       if (!(set->flags & SET_F_MAP))
+               return set_error(ctx, set, "set is not a map");
+
+       expr_set_context(&ctx->ectx, set->keytype, set->keylen);
+       if (expr_evaluate(ctx, &mapping->left) < 0)
+               return -1;
+       if (!expr_is_constant(mapping->left))
+               return expr_error(ctx, mapping->left, "Key must be a constant");
+       mapping->flags |= mapping->left->flags & EXPR_F_SINGLETON;
+
+       expr_set_context(&ctx->ectx, set->datatype, set->datalen);
+       if (expr_evaluate(ctx, &mapping->right) < 0)
+               return -1;
+       if (!expr_is_constant(mapping->right))
+               return expr_error(ctx, mapping->right, "Value must be a constant");
+       if (!expr_is_singleton(mapping->right))
+               return expr_error(ctx, mapping->right, "Value must be a singleton");
+
+       mapping->flags |= EXPR_F_CONSTANT;
        return 0;
 }
 
@@ -719,6 +840,7 @@ static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr)
                        rel->op = OP_RANGE;
                        break;
                case EXPR_SET:
+               case EXPR_SET_REF:
                        rel->op = OP_LOOKUP;
                        break;
                case EXPR_LIST:
@@ -732,10 +854,21 @@ static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr)
 
        switch (rel->op) {
        case OP_LOOKUP:
+               /* A literal set expression implicitly declares the set */
+               if (right->ops->type == EXPR_SET)
+                       right = rel->right =
+                               implicit_set_declaration(ctx, left->dtype, left->len, right);
+               else if (left->dtype != right->dtype)
+                       return expr_binary_error(ctx, right, left,
+                                                "datatype mismatch, expected %s, "
+                                                "set has type %s",
+                                                left->dtype->desc,
+                                                right->dtype->desc);
+
                /* Data for range lookups needs to be in big endian order */
-               if (right->flags & SET_F_INTERVAL &&
+               if (right->set->flags & SET_F_INTERVAL &&
                    byteorder_conversion(ctx, &rel->left,
-                                        BYTEORDER_BIG_ENDIAN) < 0)
+                                        BYTEORDER_BIG_ENDIAN) < 0)
                        return -1;
                left = rel->left;
                break;
@@ -839,6 +972,8 @@ static int expr_evaluate(struct eval_ctx *ctx, struct expr **expr)
        switch ((*expr)->ops->type) {
        case EXPR_SYMBOL:
                return expr_evaluate_symbol(ctx, expr);
+       case EXPR_SET_REF:
+               return 0;
        case EXPR_VALUE:
                return expr_evaluate_value(ctx, expr);
        case EXPR_VERDICT:
@@ -864,6 +999,8 @@ static int expr_evaluate(struct eval_ctx *ctx, struct expr **expr)
                return expr_evaluate_set(ctx, expr);
        case EXPR_MAP:
                return expr_evaluate_map(ctx, expr);
+       case EXPR_MAPPING:
+               return expr_evaluate_mapping(ctx, expr);
        case EXPR_RELATIONAL:
                return expr_evaluate_relational(ctx, expr);
        default:
@@ -879,6 +1016,7 @@ static int stmt_evaluate_expr(struct eval_ctx *ctx, struct stmt *stmt)
 
 static int stmt_evaluate_verdict(struct eval_ctx *ctx, struct stmt *stmt)
 {
+       expr_set_context(&ctx->ectx, &verdict_type, 0);
        if (expr_evaluate(ctx, &stmt->expr) < 0)
                return -1;
 
@@ -962,6 +1100,52 @@ static int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt)
        }
 }
 
+static int setelem_evaluate(struct eval_ctx *ctx, struct expr **expr)
+{
+       struct set *set;
+
+       set = get_set(ctx, &ctx->cmd->handle, ctx->cmd->handle.set);
+       if (set == NULL)
+               return -1;
+
+       ctx->set = set;
+       expr_set_context(&ctx->ectx, set->keytype, set->keylen);
+       if (expr_evaluate(ctx, expr) < 0)
+               return -1;
+       ctx->set = NULL;
+       return 0;
+}
+
+static int set_evaluate(struct eval_ctx *ctx, struct set *set)
+{
+       const char *type;
+
+       type = set->flags & SET_F_MAP ? "map" : "set";
+
+       if (set->keytype == NULL)
+               return set_error(ctx, set, "%s definition does not specify "
+                                "key data type", type);
+
+       set->keylen = set->keytype->size;
+       if (set->keylen == 0)
+               return set_error(ctx, set, "unqualified key data type "
+                                "specified in %s definition", type);
+
+       if (!(set->flags & SET_F_MAP))
+               return 0;
+
+       if (set->datatype == NULL)
+               return set_error(ctx, set, "map definition does not specify "
+                                "mapping data type");
+
+       set->datalen = set->datatype->size;
+       if (set->datalen == 0 && set->datatype->type != TYPE_VERDICT)
+               return set_error(ctx, set, "unqualified mapping data type "
+                                "specified in map definition");
+
+       return 0;
+}
+
 static int rule_evaluate(struct eval_ctx *ctx, struct rule *rule)
 {
        struct stmt *stmt, *tstmt = NULL;
@@ -999,18 +1183,31 @@ static int chain_evaluate(struct eval_ctx *ctx, struct chain *chain)
 static int table_evaluate(struct eval_ctx *ctx, struct table *table)
 {
        struct chain *chain;
+       struct set *set;
 
+       ctx->table = table;
+       list_for_each_entry(set, &table->sets, list) {
+               handle_merge(&set->handle, &table->handle);
+               if (set_evaluate(ctx, set) < 0)
+                       return -1;
+       }
        list_for_each_entry(chain, &table->chains, list) {
                handle_merge(&chain->handle, &table->handle);
                if (chain_evaluate(ctx, chain) < 0)
                        return -1;
        }
+       ctx->table = NULL;
        return 0;
 }
 
 static int cmd_evaluate_add(struct eval_ctx *ctx, struct cmd *cmd)
 {
        switch (cmd->obj) {
+       case CMD_OBJ_SETELEM:
+               return setelem_evaluate(ctx, &cmd->expr);
+       case CMD_OBJ_SET:
+               handle_merge(&cmd->set->handle, &cmd->handle);
+               return set_evaluate(ctx, cmd->set);
        case CMD_OBJ_RULE:
                handle_merge(&cmd->rule->handle, &cmd->handle);
                return rule_evaluate(ctx, cmd->rule);
@@ -1027,6 +1224,21 @@ static int cmd_evaluate_add(struct eval_ctx *ctx, struct cmd *cmd)
        }
 }
 
+static int cmd_evaluate_delete(struct eval_ctx *ctx, struct cmd *cmd)
+{
+       switch (cmd->obj) {
+       case CMD_OBJ_SETELEM:
+               return setelem_evaluate(ctx, &cmd->expr);
+       case CMD_OBJ_SET:
+       case CMD_OBJ_RULE:
+       case CMD_OBJ_CHAIN:
+       case CMD_OBJ_TABLE:
+               return 0;
+       default:
+               BUG();
+       }
+}
+
 static int cmd_evaluate(struct eval_ctx *ctx, struct cmd *cmd)
 {
 #if TRACE
@@ -1035,10 +1247,12 @@ static int cmd_evaluate(struct eval_ctx *ctx, struct cmd *cmd)
        erec_print(stdout, erec); printf("\n\n");
 #endif
 
+       ctx->cmd = cmd;
        switch (cmd->op) {
        case CMD_ADD:
                return cmd_evaluate_add(ctx, cmd);
        case CMD_DELETE:
+               return cmd_evaluate_delete(ctx, cmd);
        case CMD_LIST:
        case CMD_FLUSH:
                return 0;
index d854eb29267e940225c8d3fabcbbe03348e701f3..dffe7a8beaa54eca6fc7f74972bf92ac4a5cfe2c 100644 (file)
@@ -188,6 +188,7 @@ static void symbol_expr_print(const struct expr *expr)
 
 static void symbol_expr_clone(struct expr *new, const struct expr *expr)
 {
+       new->symtype    = expr->symtype;
        new->scope      = expr->scope;
        new->identifier = xstrdup(expr->identifier);
 }
@@ -206,12 +207,15 @@ static const struct expr_ops symbol_expr_ops = {
 };
 
 struct expr *symbol_expr_alloc(const struct location *loc,
+                              enum symbol_types type, struct scope *scope,
                               const char *identifier)
 {
        struct expr *expr;
 
        expr = expr_alloc(loc, &symbol_expr_ops, &invalid_type,
                          BYTEORDER_INVALID, 0);
+       expr->symtype    = type;
+       expr->scope      = scope;
        expr->identifier = xstrdup(identifier);
        return expr;
 }
@@ -702,14 +706,42 @@ static const struct expr_ops map_expr_ops = {
 };
 
 struct expr *map_expr_alloc(const struct location *loc, struct expr *arg,
-                           struct expr *list)
+                           struct expr *mappings)
 {
        struct expr *expr;
 
-       assert(list->ops->type == EXPR_SET);
-       expr = expr_alloc(loc, &map_expr_ops, list->dtype,
-                         list->byteorder, list->len);
+       expr = expr_alloc(loc, &map_expr_ops, &invalid_type, BYTEORDER_INVALID, 0);
        expr->expr     = arg;
-       expr->mappings = list;
+       expr->mappings = mappings;
+       return expr;
+}
+
+static void set_ref_expr_print(const struct expr *expr)
+{
+       if (expr->set->flags & SET_F_ANONYMOUS)
+               expr_print(expr->set->init);
+       else
+               printf("@%s", expr->set->handle.set);
+}
+
+static void set_ref_expr_destroy(struct expr *expr)
+{
+       set_free(expr->set);
+}
+
+static const struct expr_ops set_ref_expr_ops = {
+       .type           = EXPR_SET_REF,
+       .name           = "set reference",
+       .print          = set_ref_expr_print,
+       .destroy        = set_ref_expr_destroy,
+};
+
+struct expr *set_ref_expr_alloc(const struct location *loc, struct set *set)
+{
+       struct expr *expr;
+
+       expr = expr_alloc(loc, &set_ref_expr_ops, set->keytype, 0, 0);
+       expr->set = set_get(set);
+       expr->flags |= EXPR_F_CONSTANT;
        return expr;
 }
index 8ef140112ff6bd0aaae85e957d46f49d0c9f43a1..3798154235cf194ef70f9e884521112266c276c0 100644 (file)
@@ -15,6 +15,8 @@
 #include <netlink/netfilter/nft_rule.h>
 #include <netlink/netfilter/nft_expr.h>
 #include <netlink/netfilter/nft_data.h>
+#include <netlink/netfilter/nft_setelem.h>
+#include <netlink/netfilter/nft_set.h>
 #include <linux/netfilter/nf_tables.h>
 
 #include <nftables.h>
@@ -30,10 +32,13 @@ static struct nl_sock *nf_sock;
 
 static void __init netlink_open_sock(void)
 {
-       // FIXME: should be done dynamically by nft_set and based on set members
        nlmsg_set_default_size(65536);
        nf_sock = nl_socket_alloc();
+       if (nf_sock == NULL)
+               memory_allocation_error();
+
        nfnl_connect(nf_sock);
+       nl_socket_set_nonblocking(nf_sock);
 }
 
 static void __exit netlink_close_sock(void)
@@ -123,6 +128,42 @@ struct nfnl_nft_expr *alloc_nft_expr(int (*init)(struct nfnl_nft_expr *))
        return nle;
 }
 
+struct nfnl_nft_set *alloc_nft_set(const struct handle *h)
+{
+       struct nfnl_nft_set *nls;
+
+       nls = nfnl_nft_set_alloc();
+       if (nls == NULL)
+               memory_allocation_error();
+       nfnl_nft_set_set_family(nls, h->family);
+       nfnl_nft_set_set_table(nls, h->table, strlen(h->table) + 1);
+       if (h->set != NULL)
+               nfnl_nft_set_set_name(nls, h->set, strlen(h->set) + 1);
+       return nls;
+}
+
+static struct nfnl_nft_setelem *alloc_nft_setelem(const struct expr *expr)
+{
+       struct nfnl_nft_setelem *nlse;
+
+       nlse = nfnl_nft_setelem_alloc();
+       if (nlse == NULL)
+               memory_allocation_error();
+
+       if (expr->ops->type == EXPR_VALUE || expr->flags & EXPR_F_INTERVAL_END)
+               nfnl_nft_setelem_set_key(nlse, netlink_gen_data(expr));
+       else {
+               assert(expr->ops->type == EXPR_MAPPING);
+               nfnl_nft_setelem_set_key(nlse, netlink_gen_data(expr->left));
+               nfnl_nft_setelem_set_data(nlse, netlink_gen_data(expr->right));
+       }
+
+       if (expr->flags & EXPR_F_INTERVAL_END)
+               nfnl_nft_setelem_set_flags(nlse, NFT_SET_ELEM_INTERVAL_END);
+
+       return nlse;
+}
+
 struct nfnl_nft_data *alloc_nft_data(const void *data, unsigned int len)
 {
        struct nfnl_nft_data *nld;
@@ -585,3 +626,326 @@ int netlink_flush_table(struct netlink_ctx *ctx, const struct handle *h)
 {
        return netlink_flush_rules(ctx, h);
 }
+
+static enum nft_data_types dtype_map_to_kernel(const struct datatype *dtype)
+{
+       switch (dtype->type) {
+       case TYPE_VERDICT:
+               return NFT_DATA_VERDICT;
+       default:
+               return dtype->type;
+       }
+}
+
+static const struct datatype *dtype_map_from_kernel(enum nft_data_types type)
+{
+       switch (type) {
+       case NFT_DATA_VERDICT:
+               return &verdict_type;
+       default:
+               return datatype_lookup(type);
+       }
+}
+
+static void add_set_cb(struct nl_object *obj, void *arg)
+{
+       struct nfnl_nft_set *nls = (struct nfnl_nft_set *)obj;
+       struct netlink_ctx *ctx = arg;
+       struct set *set = ctx->set;
+
+#if TRACE
+       netlink_dump_object(OBJ_CAST(nls));
+#endif
+       set->handle.set = xstrdup(nfnl_nft_set_get_name(nls));
+}
+
+static int netlink_add_set_cb(struct nl_msg *msg, void *arg)
+{
+       return nl_msg_parse(msg, add_set_cb, arg);
+}
+
+int netlink_add_set(struct netlink_ctx *ctx, const struct handle *h,
+                   struct set *set)
+{
+       struct nfnl_nft_set *nls;
+       int err;
+
+       nls = alloc_nft_set(h);
+       nfnl_nft_set_set_flags(nls, set->flags);
+       nfnl_nft_set_set_keytype(nls, dtype_map_to_kernel(set->keytype));
+       nfnl_nft_set_set_keylen(nls, set->keylen / BITS_PER_BYTE);
+       if (set->flags & NFT_SET_MAP) {
+               nfnl_nft_set_set_datatype(nls, dtype_map_to_kernel(set->datatype));
+               nfnl_nft_set_set_datalen(nls, set->datalen / BITS_PER_BYTE);
+       }
+#if TRACE
+       netlink_dump_object(OBJ_CAST(nls));
+#endif
+
+       ctx->set = set;
+       netlink_set_callback(netlink_add_set_cb, ctx);
+       err = nfnl_nft_set_add(nf_sock, nls, NLM_F_EXCL | NLM_F_ECHO);
+       if (err == 0)
+               err = nl_recvmsgs_default(nf_sock);
+       netlink_set_callback(NULL, NULL);
+       nfnl_nft_set_put(nls);
+       ctx->set = NULL;
+
+       if (err < 0)
+               netlink_io_error(ctx, NULL, "Could not add set: %s",
+                                nl_geterror(err));
+       return err;
+}
+
+int netlink_delete_set(struct netlink_ctx *ctx, const struct handle *h)
+{
+       struct nfnl_nft_set *nls;
+       int err;
+
+       nls = alloc_nft_set(h);
+       err = nfnl_nft_set_delete(nf_sock, nls, 0);
+       nfnl_nft_set_put(nls);
+
+       if (err < 0)
+               netlink_io_error(ctx, NULL, "Could not delete set: %s",
+                                nl_geterror(err));
+       return err;
+}
+
+static void list_set_cb(struct nl_object *obj, void *arg)
+{
+       struct nfnl_nft_set *nls = (struct nfnl_nft_set *)obj;
+       struct netlink_ctx *ctx = arg;
+       const struct datatype *keytype, *datatype;
+       uint32_t flags;
+       struct set *set;
+#if TRACE
+       netlink_dump_object(obj);
+#endif
+       if (!nfnl_nft_set_test_family(nls) ||
+           !nfnl_nft_set_test_table(nls) ||
+           !nfnl_nft_set_test_name(nls) ||
+           !nfnl_nft_set_test_keytype(nls) ||
+           !nfnl_nft_set_test_keylen(nls)) {
+               netlink_io_error(ctx, NULL, "Incomplete set received");
+               return;
+       }
+
+       keytype = dtype_map_from_kernel(nfnl_nft_set_get_keytype(nls));
+       if (keytype == NULL) {
+               netlink_io_error(ctx, NULL, "Unknown data type in set key %u",
+                                nfnl_nft_set_get_keytype(nls));
+               return;
+       }
+
+       flags = nfnl_nft_set_get_flags(nls);
+       if (flags & NFT_SET_MAP) {
+               datatype = dtype_map_from_kernel(nfnl_nft_set_get_datatype(nls));
+               if (datatype == NULL) {
+                       netlink_io_error(ctx, NULL, "Unknown data type in set key %u",
+                                        nfnl_nft_set_get_datatype(nls));
+                       return;
+               }
+       } else
+               datatype = NULL;
+
+       set = set_alloc(&internal_location);
+       set->handle.family = nfnl_nft_set_get_family(nls);
+       set->handle.table  = xstrdup(nfnl_nft_set_get_table(nls));
+       set->handle.set    = xstrdup(nfnl_nft_set_get_name(nls));
+       set->keytype       = keytype;
+       set->keylen        = nfnl_nft_set_get_keylen(nls) * BITS_PER_BYTE;
+       set->flags         = flags;
+       set->datatype      = datatype;
+       set->datalen       = nfnl_nft_set_get_datalen(nls) * BITS_PER_BYTE;
+       list_add_tail(&set->list, &ctx->list);
+}
+
+int netlink_list_sets(struct netlink_ctx *ctx, const struct handle *h)
+{
+       struct nl_cache *set_cache;
+       int err;
+
+       err = nfnl_nft_set_alloc_cache(nf_sock, h->family, h->table, &set_cache);
+       if (err < 0)
+               return netlink_io_error(ctx, NULL,
+                                       "Could not receive sets from kernel: %s",
+                                       nl_geterror(err));
+
+       nl_cache_foreach(set_cache, list_set_cb, ctx);
+       nl_cache_free(set_cache);
+       return 0;
+}
+
+static int netlink_get_set_cb(struct nl_msg *msg, void *arg)
+{
+       return nl_msg_parse(msg, list_set_cb, arg);
+}
+
+int netlink_get_set(struct netlink_ctx *ctx, const struct handle *h)
+{
+       struct nfnl_nft_set *nls;
+       int err;
+
+       nls = alloc_nft_set(h);
+#if TRACE
+       netlink_dump_object(OBJ_CAST(nls));
+#endif
+       netlink_set_callback(netlink_get_set_cb, ctx);
+       err = nfnl_nft_set_query(nf_sock, nls, 0);
+       if (err == 0)
+               err = nl_recvmsgs_default(nf_sock);
+       netlink_set_callback(NULL, NULL);
+
+       nfnl_nft_set_put(nls);
+
+       if (err < 0)
+               return netlink_io_error(ctx, NULL,
+                                       "Could not receive set from kernel: %s",
+                                       nl_geterror(err));
+       return err;
+}
+
+static int alloc_setelem_cache(const struct expr *set, struct nl_cache **res)
+{
+       struct nfnl_nft_setelem *nlse;
+       struct nl_cache *elements;
+       const struct expr *expr;
+       int err;
+
+       err = nl_cache_alloc_name("netfilter/nft_setelem", &elements);
+       if (err < 0)
+               return err;
+       list_for_each_entry(expr, &set->expressions, list) {
+               nlse = alloc_nft_setelem(expr);
+               nl_cache_add(elements, OBJ_CAST(nlse));
+       }
+       *res = elements;
+       return 0;
+}
+
+int netlink_add_setelems(struct netlink_ctx *ctx, const struct handle *h,
+                        const struct expr *expr)
+{
+       struct nfnl_nft_set *nls;
+       struct nl_cache *elements;
+       int err;
+
+       nls = alloc_nft_set(h);
+#if TRACE
+       netlink_dump_object(OBJ_CAST(nls));
+#endif
+       err = alloc_setelem_cache(expr, &elements);
+       if (err < 0)
+               goto out;
+       err = nfnl_nft_setelem_add(nf_sock, nls, elements, 0);
+       if (err < 0)
+               goto out;
+       err = nl_recvmsgs_default(nf_sock);
+out:
+       nfnl_nft_set_put(nls);
+       if (err < 0)
+               netlink_io_error(ctx, NULL, "Could not add set elements: %s",
+                                nl_geterror(err));
+       return err;
+}
+
+int netlink_delete_setelems(struct netlink_ctx *ctx, const struct handle *h,
+                           const struct expr *expr)
+{
+       struct nfnl_nft_set *nls;
+       struct nl_cache *elements;
+       int err;
+
+       nls = alloc_nft_set(h);
+       err = alloc_setelem_cache(expr, &elements);
+       if (err < 0)
+               goto out;
+       err = nfnl_nft_setelem_delete(nf_sock, nls, elements, 0);
+       if (err < 0)
+               goto out;
+       err = nl_recvmsgs_default(nf_sock);
+out:
+       nfnl_nft_set_put(nls);
+       if (err < 0)
+               netlink_io_error(ctx, NULL, "Could not delete set elements: %s",
+                                nl_geterror(err));
+       return err;
+}
+
+static void list_setelem_cb(struct nl_object *obj, void *arg)
+{
+       struct nfnl_nft_setelem *nlse = nl_object_priv(obj);
+       struct nfnl_nft_data *nld;
+       struct netlink_ctx *ctx = arg;
+       struct set *set = ctx->set;
+       struct expr *expr, *data;
+       uint32_t flags;
+#if TRACE
+       netlink_dump_object(obj);
+#endif
+       if (!nfnl_nft_setelem_test_key(nlse)) {
+               netlink_io_error(ctx, NULL, "Incomplete set element received");
+               return;
+       }
+
+       nld   = nfnl_nft_setelem_get_key(nlse);
+       flags = nfnl_nft_setelem_get_flags(nlse);
+
+       expr = netlink_alloc_value(&internal_location, nld);
+       expr->dtype     = set->keytype;
+       expr->byteorder = set->keytype->byteorder;
+       if (expr->byteorder == BYTEORDER_HOST_ENDIAN)
+               mpz_switch_byteorder(expr->value, expr->len / BITS_PER_BYTE);
+
+       if (flags & NFT_SET_ELEM_INTERVAL_END)
+               expr->flags |= EXPR_F_INTERVAL_END;
+       else if (nfnl_nft_setelem_test_data(nlse)) {
+               nld = nfnl_nft_setelem_get_data(nlse);
+
+               data = netlink_alloc_data(&internal_location, nld,
+                                         set->datatype->type == EXPR_VERDICT ?
+                                         NFT_REG_VERDICT : NFT_REG_1);
+               data->dtype = set->datatype;
+
+               expr = mapping_expr_alloc(&internal_location, expr, data);
+       }
+
+       compound_expr_add(set->init, expr);
+}
+
+extern void interval_map_decompose(struct expr *set);
+
+int netlink_get_setelems(struct netlink_ctx *ctx, const struct handle *h,
+                        struct set *set)
+{
+       struct nl_cache *elements;
+       struct nfnl_nft_set *nls;
+       int err;
+
+       nls = alloc_nft_set(h);
+#if TRACE
+       netlink_dump_object(OBJ_CAST(nls));
+#endif
+       err = nfnl_nft_setelem_alloc_cache(nf_sock, nls, &elements);
+       if (err < 0)
+               goto out;
+       err = nl_recvmsgs_default(nf_sock);
+       if (err < 0)
+               goto out;
+
+       ctx->set = set;
+       set->init = set_expr_alloc(&internal_location);
+       nl_cache_foreach(elements, list_setelem_cb, ctx);
+       nl_cache_free(elements);
+       ctx->set = NULL;
+
+       if (set->flags & NFT_SET_INTERVAL)
+               interval_map_decompose(set->init);
+out:
+       nfnl_nft_set_put(nls);
+       if (err < 0)
+               netlink_io_error(ctx, NULL, "Could not receive set elements: %s",
+                                nl_geterror(err));
+       return err;
+}
index 4b559399def7a94ac21bb443d377efdcc058d8f0..a511313ec8aa3314fa69c98b7948f791f720894b 100644 (file)
@@ -19,6 +19,7 @@
 
 struct netlink_parse_ctx {
        struct list_head        *msgs;
+       struct table            *table;
        struct rule             *rule;
        struct expr             *registers[NFT_REG_MAX + 1];
 };
@@ -132,91 +133,34 @@ static void netlink_parse_cmp(struct netlink_parse_ctx *ctx,
        list_add_tail(&stmt->list, &ctx->rule->stmts);
 }
 
-struct netlink_data_ctx {
-       const struct location   *location;
-       struct expr             *expr;
-       enum nft_registers      dreg;
-};
-
-static void netlink_data_ctx_init(struct netlink_data_ctx *dctx,
-                                 const struct location *loc,
-                                 struct expr *expr, enum nft_registers dreg)
-{
-       dctx->location  = loc;
-       dctx->expr      = expr;
-       dctx->dreg      = dreg;
-}
-
-static void netlink_set_parse_data(struct nfnl_nft_data *data,
-                                  enum nft_set_elem_flags flags,
-                                  void *arg)
-{
-       struct netlink_data_ctx *dctx = arg;
-       struct expr *expr;
-
-       assert(dctx->dreg != NFT_REG_VERDICT);
-       expr = netlink_alloc_value(dctx->location, data);
-       if (flags & NFT_SE_INTERVAL_END)
-               expr->flags |= EXPR_F_INTERVAL_END;
-       compound_expr_add(dctx->expr, expr);
-}
-
-static void netlink_set_parse_mapping(struct nfnl_nft_data *data,
-                                     struct nfnl_nft_data *mapping,
-                                     enum nft_set_elem_flags flags,
-                                     void *arg)
-{
-       struct netlink_data_ctx *dctx = arg;
-       struct expr *expr, *left, *right;
-
-       left  = netlink_alloc_value(dctx->location, data);
-       if (mapping != NULL) {
-               right = netlink_alloc_data(dctx->location, mapping, dctx->dreg);
-               expr  = mapping_expr_alloc(dctx->location, left, right);
-       } else
-               expr  = left;
-
-       if (flags & NFT_SE_INTERVAL_END)
-               expr->flags |= EXPR_F_INTERVAL_END;
-       compound_expr_add(dctx->expr, expr);
-}
-
-extern void interval_map_decompose(struct expr *set);
-
-static void netlink_parse_set(struct netlink_parse_ctx *ctx,
-                             const struct location *loc,
-                             const struct nfnl_nft_expr *nle)
+static void netlink_parse_lookup(struct netlink_parse_ctx *ctx,
+                                const struct location *loc,
+                                const struct nfnl_nft_expr *nle)
 {
        struct stmt *stmt;
        struct expr *expr, *left, *right;
-       struct netlink_data_ctx dctx;
+       struct set *set;
        enum nft_registers dreg;
-       enum nft_set_flags flags;
 
-       left = netlink_get_register(ctx, loc, nfnl_nft_set_get_sreg(nle));
+       left = netlink_get_register(ctx, loc, nfnl_nft_lookup_get_sreg(nle));
        if (left == NULL)
                return netlink_error(ctx, loc,
-                                    "Set expression has no left hand side");
+                                    "Lookup expression has no left hand side");
 
-       right = set_expr_alloc(loc);
+       set = set_lookup(ctx->table, nfnl_nft_lookup_get_set(nle));
+       if (set == NULL)
+               return netlink_error(ctx, loc,
+                                    "Unknown set '%s' in lookup expression",
+                                    nfnl_nft_lookup_get_set(nle));
 
-       flags = nfnl_nft_set_get_flags(nle);
-       if (flags & NFT_SET_MAP) {
-               dreg = nfnl_nft_set_get_dreg(nle);
-               netlink_data_ctx_init(&dctx, loc, right, dreg);
-               nfnl_nft_set_foreach_mapping(nle, netlink_set_parse_mapping,
-                                            &dctx);
+       right = set_ref_expr_alloc(loc, set);
 
+       if (nfnl_nft_lookup_test_dreg(nle)) {
+               dreg = nfnl_nft_lookup_get_dreg(nle);
                expr = map_expr_alloc(loc, left, right);
                if (dreg != NFT_REG_VERDICT)
                        return netlink_set_register(ctx, dreg, expr);
        } else {
-               netlink_data_ctx_init(&dctx, loc, right, EXPR_VALUE);
-               nfnl_nft_set_foreach_elem(nle, netlink_set_parse_data, &dctx);
-               if (flags & NFT_SET_INTERVAL) {
-                       interval_map_decompose(right);
-                       right->flags |= NFT_SET_INTERVAL;
-               }
                expr = relational_expr_alloc(loc, OP_LOOKUP, left, right);
        }
 
@@ -487,7 +431,7 @@ static const struct {
 } netlink_parsers[] = {
        { .name = "immediate",  .parse = netlink_parse_immediate },
        { .name = "cmp",        .parse = netlink_parse_cmp },
-       { .name = "set",        .parse = netlink_parse_set },
+       { .name = "lookup",     .parse = netlink_parse_lookup },
        { .name = "bitwise",    .parse = netlink_parse_bitwise },
        { .name = "byteorder",  .parse = netlink_parse_byteorder },
        { .name = "payload",    .parse = netlink_parse_payload },
@@ -586,12 +530,6 @@ static void expr_postprocess(struct rule_pp_ctx *ctx,
        switch (expr->ops->type) {
        case EXPR_MAP:
                expr_postprocess(ctx, stmt, &expr->expr);
-               list_for_each_entry(i, &expr->mappings->expressions, list) {
-                       if (i->flags & EXPR_F_INTERVAL_END)
-                               continue;
-                       expr_set_type(i->left, expr->expr->dtype,
-                                     expr->expr->byteorder);
-               }
                expr_postprocess(ctx, stmt, &expr->mappings);
                break;
        case EXPR_MAPPING:
@@ -682,6 +620,7 @@ static void expr_postprocess(struct rule_pp_ctx *ctx,
                        expr->len = len;
                }
                break;
+       case EXPR_SET_REF:
        case EXPR_EXTHDR:
        case EXPR_META:
        case EXPR_CT:
@@ -734,6 +673,8 @@ struct rule *netlink_delinearize_rule(struct netlink_ctx *ctx,
        h.handle = nfnl_nft_rule_get_handle(nlr);
 
        pctx->rule = rule_alloc(&internal_location, &h);
+       pctx->table = table_lookup(&h);
+       assert(pctx->table != NULL);
        nfnl_nft_rule_foreach_expr(nlr, netlink_parse_expr, pctx);
 
        rule_parse_postprocess(pctx, pctx->rule);
index 65e4b69bba8648b04835132556ab1a2d4e0859aa..121dca15df444f9e4e3d8b7b1a3b6014791e47ab 100644 (file)
@@ -105,17 +105,10 @@ static void netlink_gen_map(struct netlink_linearize_ctx *ctx,
                            enum nft_registers dreg)
 {
        struct nfnl_nft_expr *nle;
-       struct nfnl_nft_data *data;
-       struct nfnl_nft_data *mapping;
-       const struct expr *i;
-       enum nft_set_elem_flags flags;
        enum nft_registers sreg;
-       unsigned int klen, dlen;
 
-       assert(expr->mappings->ops->type == EXPR_SET);
+       assert(expr->mappings->ops->type == EXPR_SET_REF);
 
-       klen = expr->expr->len / BITS_PER_BYTE;
-       dlen = expr->mappings->len / BITS_PER_BYTE;
        if (dreg == NFT_REG_VERDICT)
                sreg = get_register(ctx);
        else
@@ -123,38 +116,10 @@ static void netlink_gen_map(struct netlink_linearize_ctx *ctx,
 
        netlink_gen_expr(ctx, expr->expr, sreg);
 
-       nle = alloc_nft_expr(nfnl_nft_set_init);
-       nfnl_nft_set_set_flags(nle, NFT_SET_MAP);
-       nfnl_nft_set_set_sreg(nle, sreg);
-       nfnl_nft_set_set_klen(nle, klen);
-       nfnl_nft_set_set_dreg(nle, dreg);
-       nfnl_nft_set_set_dlen(nle, dlen);
-
-       if (expr->mappings->flags & SET_F_INTERVAL) {
-               set_to_intervals(expr->mappings);
-               nfnl_nft_set_set_flags(nle, NFT_SET_INTERVAL);
-       }
-
-       list_for_each_entry(i, &expr->mappings->expressions, list) {
-               flags = 0;
-
-               switch (i->ops->type) {
-               case EXPR_MAPPING:
-                       data    = netlink_gen_data(i->left);
-                       mapping = netlink_gen_data(i->right);
-                       break;
-               case EXPR_VALUE:
-                       assert(i->flags & EXPR_F_INTERVAL_END);
-                       data    = netlink_gen_data(i);
-                       mapping = NULL;
-                       flags   = NFT_SE_INTERVAL_END;
-                       break;
-               default:
-                       BUG();
-               }
-
-               nfnl_nft_set_add_mapping(nle, data, mapping, flags);
-       }
+       nle = alloc_nft_expr(nfnl_nft_lookup_init);
+       nfnl_nft_lookup_set_sreg(nle, sreg);
+       nfnl_nft_lookup_set_dreg(nle, dreg);
+       nfnl_nft_lookup_set_set(nle, expr->mappings->set->handle.set);
 
        if (dreg == NFT_REG_VERDICT)
                release_register(ctx);
@@ -167,34 +132,17 @@ static void netlink_gen_lookup(struct netlink_linearize_ctx *ctx,
                               enum nft_registers dreg)
 {
        struct nfnl_nft_expr *nle;
-       const struct expr *i;
-       enum nft_set_elem_flags flags;
        enum nft_registers sreg;
 
-       assert(expr->right->ops->type == EXPR_SET);
+       assert(expr->right->ops->type == EXPR_SET_REF);
        assert(dreg == NFT_REG_VERDICT);
 
        sreg = get_register(ctx);
        netlink_gen_expr(ctx, expr->left, sreg);
 
-       nle = alloc_nft_expr(nfnl_nft_set_init);
-       nfnl_nft_set_set_sreg(nle, sreg);
-       nfnl_nft_set_set_klen(nle, expr->left->len / BITS_PER_BYTE);
-
-       if (expr->right->flags & SET_F_INTERVAL) {
-               set_to_intervals(expr->right);
-               nfnl_nft_set_set_flags(nle, NFT_SET_INTERVAL);
-       }
-
-       list_for_each_entry(i, &expr->right->expressions, list) {
-               assert(i->ops->type == EXPR_VALUE);
-
-               flags = 0;
-               if (i->flags & EXPR_F_INTERVAL_END)
-                       flags = NFT_SE_INTERVAL_END;
-
-               nfnl_nft_set_add_elem(nle, netlink_gen_data(i), flags);
-       }
+       nle = alloc_nft_expr(nfnl_nft_lookup_init);
+       nfnl_nft_lookup_set_sreg(nle, sreg);
+       nfnl_nft_lookup_set_set(nle, expr->right->set->handle.set);
 
        release_register(ctx);
        nfnl_nft_rule_add_expr(ctx->nlr, nle);
index c63a14e05f56c00f589b4ec434e593342f98462a..419dcd7291763afa0999ae63a3faac99a5cb5a81 100644 (file)
@@ -119,6 +119,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
        struct rule             *rule;
        struct stmt             *stmt;
        struct expr             *expr;
+       struct set              *set;
 }
 
 %token TOKEN_EOF 0             "end of file"
@@ -146,9 +147,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
 %token DASH                    "-"
 %token AT                      "@"
 %token ARROW                   "=>"
-%token MAP                     "map"
 %token VMAP                    "vmap"
-%token SET                     "set"
 
 %token INCLUDE                 "include"
 %token DEFINE                  "define"
@@ -158,6 +157,10 @@ static void location_update(struct location *loc, struct location *rhs, int n)
 %token TABLE                   "table"
 %token CHAIN                   "chain"
 %token RULE                    "rule"
+%token SETS                    "sets"
+%token SET                     "set"
+%token ELEMENT                 "element"
+%token MAP                     "map"
 %token HANDLE                  "handle"
 
 %token ADD                     "add"
@@ -327,15 +330,23 @@ static void location_update(struct location *loc, struct location *rhs, int n)
 
 %type <handle>                 table_spec chain_spec chain_identifier ruleid_spec
 %destructor { handle_free(&$$); } table_spec chain_spec chain_identifier ruleid_spec
+%type <handle>                 set_spec set_identifier
+%destructor { handle_free(&$$); } set_spec set_identifier
 %type <val>                    handle_spec family_spec
 
 %type <table>                  table_block_alloc table_block
 %destructor { table_free($$); }        table_block_alloc
-%type <chain>                  table_line chain_block_alloc chain_block
-%destructor { chain_free($$); }        table_line chain_block_alloc
+%type <chain>                  chain_block_alloc chain_block
+%destructor { chain_free($$); }        chain_block_alloc
 %type <rule>                   rule
 %destructor { rule_free($$); } rule
 
+%type <set>                    set_block_alloc set_block
+%destructor { set_free($$); }  set_block_alloc
+
+%type <set>                    map_block_alloc map_block
+%destructor { set_free($$); }  map_block_alloc
+
 %type <list>                   stmt_list
 %destructor { stmt_list_free($$); xfree($$); } stmt_list
 %type <stmt>                   stmt match_stmt verdict_stmt
@@ -372,11 +383,11 @@ static void location_update(struct location *loc, struct location *rhs, int n)
 %type <expr>                   concat_expr map_lhs_expr
 %destructor { expr_free($$); } concat_expr map_lhs_expr
 
-%type <expr>                   map_expr map_list map_list_expr
-%destructor { expr_free($$); } map_expr map_list map_list_expr
+%type <expr>                   map_expr
+%destructor { expr_free($$); } map_expr
 
-%type <expr>                   verdict_map_expr verdict_map_list verdict_map_list_expr
-%destructor { expr_free($$); } verdict_map_expr verdict_map_list verdict_map_list_expr
+%type <expr>                   verdict_map_expr
+%destructor { expr_free($$); } verdict_map_expr
 
 %type <expr>                   set_expr set_list_expr set_list_member_expr
 %destructor { expr_free($$); } set_expr set_list_expr set_list_member_expr
@@ -384,10 +395,8 @@ static void location_update(struct location *loc, struct location *rhs, int n)
 %type <expr>                   expr initializer_expr
 %destructor { expr_free($$); } expr initializer_expr
 
-%type <expr>                   match_expr
-%destructor { expr_free($$); } match_expr
-%type <expr>                   relational_expr membership_expr
-%destructor { expr_free($$); } relational_expr membership_expr
+%type <expr>                   relational_expr
+%destructor { expr_free($$); } relational_expr
 %type <val>                    relational_op
 
 %type <expr>                   payload_expr payload_raw_expr
@@ -520,6 +529,24 @@ add_cmd                    :       TABLE           table_spec
                        {
                                $$ = cmd_alloc(CMD_ADD, CMD_OBJ_RULE, &$1, $2);
                        }
+                       |       SET             set_spec        set_block_alloc
+                                               '{'     set_block       '}'
+                       {
+                               $5->location = @5;
+                               handle_merge(&$3->handle, &$2);
+                               $$ = cmd_alloc(CMD_ADD, CMD_OBJ_SET, &$2, $5);
+                       }
+                       |       MAP             set_spec        map_block_alloc
+                                               '{'     map_block       '}'
+                       {
+                               $5->location = @5;
+                               handle_merge(&$3->handle, &$2);
+                               $$ = cmd_alloc(CMD_ADD, CMD_OBJ_SET, &$2, $5);
+                       }
+                       |       ELEMENT         set_spec        set_expr
+                       {
+                               $$ = cmd_alloc(CMD_ADD, CMD_OBJ_SETELEM, &$2, $3);
+                       }
                        ;
 
 delete_cmd             :       TABLE           table_spec
@@ -534,6 +561,14 @@ delete_cmd         :       TABLE           table_spec
                        {
                                $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_RULE, &$2, NULL);
                        }
+                       |       SET             set_spec
+                       {
+                               $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_SET, &$2, NULL);
+                       }
+                       |       ELEMENT         set_spec        set_expr
+                       {
+                               $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_SETELEM, &$2, $3);
+                       }
                        ;
 
 list_cmd               :       TABLE           table_spec
@@ -544,6 +579,14 @@ list_cmd           :       TABLE           table_spec
                        {
                                $$ = cmd_alloc(CMD_LIST, CMD_OBJ_CHAIN, &$2, NULL);
                        }
+                       |       SETS            table_spec
+                       {
+                               $$ = cmd_alloc(CMD_LIST, CMD_OBJ_SETS, &$2, NULL);
+                       }
+                       |       SET             set_spec
+                       {
+                               $$ = cmd_alloc(CMD_LIST, CMD_OBJ_SET, &$2, NULL);
+                       }
                        ;
 
 flush_cmd              :       TABLE           table_spec
@@ -554,6 +597,10 @@ flush_cmd          :       TABLE           table_spec
                        {
                                $$ = cmd_alloc(CMD_FLUSH, CMD_OBJ_CHAIN, &$2, NULL);
                        }
+                       |       SET             set_spec
+                       {
+                               $$ = cmd_alloc(CMD_FLUSH, CMD_OBJ_SET, &$2, NULL);
+                       }
                        ;
 
 table_block_alloc      :       /* empty */
@@ -566,20 +613,35 @@ table_block_alloc :       /* empty */
 table_block            :       /* empty */     { $$ = $<table>-1; }
                        |       table_block     common_block
                        |       table_block     stmt_seperator
-                       |       table_block     table_line      stmt_seperator
+                       |       table_block     CHAIN           chain_identifier
+                                       chain_block_alloc       '{'     chain_block     '}'
+                                       stmt_seperator
                        {
-                               list_add_tail(&$2->list, &$1->chains);
+                               handle_merge(&$4->handle, &$3);
+                               handle_free(&$3);
+                               close_scope(state);
+                               list_add_tail(&$4->list, &$1->chains);
                                $$ = $1;
                        }
-                       ;
-
-table_line             :       CHAIN           chain_identifier        chain_block_alloc
-                                               '{'     chain_block     '}'
-                       {
-                               handle_merge(&$3->handle, &$2);
-                               handle_free(&$2);
-                               close_scope(state);
-                               $$ = $3;
+                       |       table_block     SET             set_identifier
+                                       set_block_alloc         '{'     set_block       '}'
+                                       stmt_seperator
+                       {
+                               $4->location = @3;
+                               handle_merge(&$4->handle, &$3);
+                               handle_free(&$3);
+                               list_add_tail(&$4->list, &$1->sets);
+                               $$ = $1;
+                       }
+                       |       table_block     MAP             set_identifier
+                                       map_block_alloc         '{'     map_block       '}'
+                                       stmt_seperator
+                       {
+                               $4->location = @3;
+                               handle_merge(&$4->handle, &$3);
+                               handle_free(&$3);
+                               list_add_tail(&$4->list, &$1->sets);
+                               $$ = $1;
                        }
                        ;
 
@@ -601,6 +663,59 @@ chain_block                :       /* empty */     { $$ = $<chain>-1; }
                        }
                        ;
 
+set_block_alloc                :       /* empty */
+                       {
+                               $$ = set_alloc(NULL);
+                       }
+                       ;
+
+set_block              :       /* empty */     { $$ = $<set>-1; }
+                       |       set_block       common_block
+                       |       set_block       stmt_seperator
+                       |       set_block       TYPE            identifier      stmt_seperator
+                       {
+                               $1->keytype = datatype_lookup_byname($3);
+                               if ($1->keytype == NULL) {
+                                       erec_queue(error(&@3, "unknown datatype %s", $3),
+                                                  state->msgs);
+                                       YYERROR;
+                               }
+                               $$ = $1;
+                       }
+                       ;
+
+map_block_alloc                :       /* empty */
+                       {
+                               $$ = set_alloc(NULL);
+                               $$->flags |= NFT_SET_MAP;
+                       }
+                       ;
+
+map_block              :       /* empty */     { $$ = $<set>-1; }
+                       |       map_block       common_block
+                       |       map_block       stmt_seperator
+                       |       map_block       TYPE
+                                               identifier      ARROW   identifier
+                                               stmt_seperator
+                       {
+                               $1->keytype = datatype_lookup_byname($3);
+                               if ($1->keytype == NULL) {
+                                       erec_queue(error(&@3, "unknown datatype %s", $3),
+                                                  state->msgs);
+                                       YYERROR;
+                               }
+
+                               $1->datatype = datatype_lookup_byname($5);
+                               if ($1->datatype == NULL) {
+                                       erec_queue(error(&@5, "unknown datatype %s", $5),
+                                                  state->msgs);
+                                       YYERROR;
+                               }
+
+                               $$ = $1;
+                       }
+                       ;
+
 hook_spec              :       HOOK            HOOKNUM         NUM
                        {
                                $<chain>0->hooknum      = $2;
@@ -649,6 +764,20 @@ chain_identifier   :       identifier
                        }
                        ;
 
+set_spec               :       table_spec      identifier
+                       {
+                               $$              = $1;
+                               $$.set          = $2;
+                       }
+                       ;
+
+set_identifier         :       identifier
+                       {
+                               memset(&$$, 0, sizeof($$));
+                               $$.set          = $1;
+                       }
+                       ;
+
 handle_spec            :       /* empty */
                        {
                                $$ = 0;
@@ -806,7 +935,7 @@ nat_stmt_args               :       expr
                        }
                        ;
 
-match_stmt             :       match_expr
+match_stmt             :       relational_expr
                        {
                                $$ = expr_stmt_alloc(&@$, $1);
                        }
@@ -814,13 +943,23 @@ match_stmt                :       match_expr
 
 symbol_expr            :       string
                        {
-                               $$ = symbol_expr_alloc(&@$, $1);
+                               $$ = symbol_expr_alloc(&@$, SYMBOL_VALUE,
+                                                      current_scope(state),
+                                                      $1);
                                xfree($1);
                        }
                        |       '$'     identifier
                        {
-                               $$ = symbol_expr_alloc(&@$, $2);
-                               $$->scope = current_scope(state);
+                               $$ = symbol_expr_alloc(&@$, SYMBOL_DEFINE,
+                                                      current_scope(state),
+                                                      $2);
+                               xfree($2);
+                       }
+                       |       AT      identifier
+                       {
+                               $$ = symbol_expr_alloc(&@$, SYMBOL_SET,
+                                                      current_scope(state),
+                                                      $2);
                                xfree($2);
                        }
                        ;
@@ -830,7 +969,9 @@ integer_expr                :       NUM
                                char str[64];
 
                                snprintf(str, sizeof(str), "%" PRIu64, $1);
-                               $$ = symbol_expr_alloc(&@$, str);
+                               $$ = symbol_expr_alloc(&@$, SYMBOL_VALUE,
+                                                      current_scope(state),
+                                                      str);
                        }
                        ;
 
@@ -938,76 +1079,62 @@ map_lhs_expr             :       multiton_expr
                        |       concat_expr
                        ;
 
-map_expr               :       concat_expr     MAP     '{'     map_list '}'
+map_expr               :       concat_expr     MAP     expr
                        {
-                               $$ = map_expr_alloc(&@$, $1, $4);
+                               $$ = map_expr_alloc(&@$, $1, $3);
                        }
                        ;
 
-map_list               :       map_list_expr
+verdict_map_expr       :       concat_expr     VMAP    expr
                        {
-                               $$ = set_expr_alloc(&@$);
-                               compound_expr_add($$, $1);
+                               $$ = map_expr_alloc(&@$, $1, $3);
                        }
-                       |       map_list        COMMA   map_list_expr
-                       {
-                               compound_expr_add($1, $3);
-                               $1->location = @$;
-                               $$ = $1;
-                       }
-                       |       map_list        COMMA   opt_newline
                        ;
 
-map_list_expr          :       opt_newline     map_lhs_expr    opt_newline
-                                               ARROW           opt_newline
-                                               concat_expr     opt_newline
-                       {
-                               $$ = mapping_expr_alloc(&@$, $2, $6);
-                       }
+expr                   :       concat_expr
+                       |       set_expr
+                       |       map_expr
+                       |       multiton_expr
                        ;
 
-verdict_map_expr       :       concat_expr     VMAP    '{'     verdict_map_list '}'
+set_expr               :       '{'     set_list_expr           '}'
                        {
-                               $$ = map_expr_alloc(&@$, $1, $4);
+                               $2->location = @$;
+                               $$ = $2;
                        }
                        ;
 
-verdict_map_list       :       verdict_map_list_expr
+set_list_expr          :       set_list_member_expr
                        {
                                $$ = set_expr_alloc(&@$);
                                compound_expr_add($$, $1);
                        }
-                       |       verdict_map_list        COMMA   verdict_map_list_expr
+                       |       set_list_expr           COMMA   set_list_member_expr
                        {
                                compound_expr_add($1, $3);
-                               $1->location = @$;
                                $$ = $1;
                        }
-                       |       verdict_map_list        COMMA   opt_newline
+                       |       set_list_expr           COMMA   opt_newline
                        ;
 
-verdict_map_list_expr  :       opt_newline     map_lhs_expr    opt_newline
-                                               ARROW           opt_newline
-                                               verdict_expr    opt_newline
+set_list_member_expr   :       opt_newline     expr    opt_newline
                        {
-                               $$ = mapping_expr_alloc(&@$, $2, $6);
+                               $$ = $2;
+                       }
+                       |       opt_newline     map_lhs_expr    ARROW   concat_expr     opt_newline
+                       {
+                               $$ = mapping_expr_alloc(&@$, $2, $4);
+                       }
+                       |       opt_newline     map_lhs_expr    ARROW   verdict_expr    opt_newline
+                       {
+                               $$ = mapping_expr_alloc(&@$, $2, $4);
                        }
-                       ;
-
-expr                   :       concat_expr
-                       |       map_expr
-                       |       multiton_expr
                        ;
 
 initializer_expr       :       expr
-                       |       set_expr
                        |       list_expr
                        ;
 
-match_expr             :       relational_expr
-                       |       membership_expr
-                       ;
-
 relational_expr                :       expr    /* implicit */  expr
                        {
                                $$ = relational_expr_alloc(&@$, OP_IMPLICIT, $1, $2);
@@ -1030,38 +1157,6 @@ relational_op            :       EQ              { $$ = OP_EQ; }
                        |       LTE             { $$ = OP_LTE; }
                        ;
 
-membership_expr                :       expr    set_expr
-                       {
-                               $$ = relational_expr_alloc(&@$, OP_LOOKUP, $1, $2);
-                       }
-                       ;
-
-set_expr               :       '{'     set_list_expr           '}'
-                       {
-                               $2->location = @$;
-                               $$ = $2;
-                       }
-                       ;
-
-set_list_expr          :       set_list_member_expr
-                       {
-                               $$ = set_expr_alloc(&@$);
-                               compound_expr_add($$, $1);
-                       }
-                       |       set_list_expr           COMMA   set_list_member_expr
-                       {
-                               compound_expr_add($1, $3);
-                               $$ = $1;
-                       }
-                       |       set_list_expr           COMMA   opt_newline
-                       ;
-
-set_list_member_expr   :       opt_newline     expr    opt_newline
-                       {
-                               $$ = $2;
-                       }
-                       ;
-
 verdict_expr           :       ACCEPT
                        {
                                $$ = verdict_expr_alloc(&@$, NF_ACCEPT, NULL);
index 6f322b8b09b33e7366a961b6d74170b5b8910afc..a5032cf7b9f3d1cc9984398fe60fc37e94826ec4 100644 (file)
@@ -23,6 +23,7 @@ void handle_free(struct handle *h)
 {
        xfree(h->table);
        xfree(h->chain);
+       xfree(h->set);
 }
 
 void handle_merge(struct handle *dst, const struct handle *src)
@@ -33,10 +34,80 @@ void handle_merge(struct handle *dst, const struct handle *src)
                dst->table = xstrdup(src->table);
        if (dst->chain == NULL && src->chain != NULL)
                dst->chain = xstrdup(src->chain);
+       if (dst->set == NULL && src->set != NULL)
+               dst->set = xstrdup(src->set);
        if (dst->handle == 0)
                dst->handle = src->handle;
 }
 
+struct set *set_alloc(const struct location *loc)
+{
+       struct set *set;
+
+       set = xzalloc(sizeof(*set));
+       set->refcnt = 1;
+       if (loc != NULL)
+               set->location = *loc;
+       return set;
+}
+
+struct set *set_get(struct set *set)
+{
+       set->refcnt++;
+       return set;
+}
+
+void set_free(struct set *set)
+{
+       if (--set->refcnt > 0)
+               return;
+       handle_free(&set->handle);
+       xfree(set);
+}
+
+void set_add_hash(struct set *set, struct table *table)
+{
+       list_add_tail(&set->list, &table->sets);
+}
+
+struct set *set_lookup(const struct table *table, const char *name)
+{
+       struct set *set;
+
+       list_for_each_entry(set, &table->sets, list) {
+               if (!strcmp(set->handle.set, name))
+                       return set;
+       }
+       return NULL;
+}
+
+void set_print(const struct set *set)
+{
+       const char *type;
+
+       type = set->flags & SET_F_MAP ? "map" : "set";
+       printf("\t%s %s {\n", type, set->handle.set);
+
+       printf("\t\ttype %s", set->keytype->name);
+       if (set->flags & SET_F_MAP)
+               printf(" => %s", set->datatype->name);
+       printf("\n");
+
+       if (set->flags & SET_F_ANONYMOUS)
+               printf("\t\tanonymous\n");
+       if (set->flags & SET_F_CONSTANT)
+               printf("\t\tconstant\n");
+       if (set->flags & SET_F_INTERVAL)
+               printf("\t\tinterval\n");
+
+       if (set->init != NULL && set->init->size > 0) {
+               printf("\t\telements = ");
+               expr_print(set->init);
+               printf("\n");
+       }
+       printf("\t}\n");
+}
+
 struct rule *rule_alloc(const struct location *loc, const struct handle *h)
 {
        struct rule *rule;
@@ -168,6 +239,7 @@ struct table *table_alloc(void)
 
        table = xzalloc(sizeof(*table));
        init_list_head(&table->chains);
+       init_list_head(&table->sets);
        return table;
 }
 
@@ -204,9 +276,17 @@ struct table *table_lookup(const struct handle *h)
 static void table_print(const struct table *table)
 {
        struct chain *chain;
+       struct set *set;
        const char *delim = "";
 
        printf("table %s {\n", table->handle.table);
+       list_for_each_entry(set, &table->sets, list) {
+               if (set->flags & SET_F_ANONYMOUS)
+                       continue;
+               printf("%s", delim);
+               set_print(set);
+               delim = "\n";
+       }
        list_for_each_entry(chain, &table->chains, list) {
                printf("%s", delim);
                chain_print(chain);
@@ -233,6 +313,12 @@ void cmd_free(struct cmd *cmd)
        handle_free(&cmd->handle);
        if (cmd->data != NULL) {
                switch (cmd->obj) {
+               case CMD_OBJ_SETELEM:
+                       expr_free(cmd->expr);
+                       break;
+               case CMD_OBJ_SET:
+                       set_free(cmd->set);
+                       break;
                case CMD_OBJ_RULE:
                        rule_free(cmd->rule);
                        break;
@@ -267,14 +353,42 @@ static int do_add_chain(struct netlink_ctx *ctx, const struct handle *h,
        return 0;
 }
 
+static int do_add_setelems(struct netlink_ctx *ctx, const struct handle *h,
+                          const struct expr *expr)
+{
+       if (netlink_add_setelems(ctx, h, expr) < 0)
+               return -1;
+       return 0;
+}
+
+static int do_add_set(struct netlink_ctx *ctx, const struct handle *h,
+                     struct set *set)
+{
+       if (netlink_add_set(ctx, h, set) < 0)
+               return -1;
+       if (set->init != NULL) {
+               if (set->flags & SET_F_INTERVAL)
+                       set_to_intervals(set->init);
+               if (do_add_setelems(ctx, &set->handle, set->init) < 0)
+                       return -1;
+       }
+       return 0;
+}
+
 static int do_add_table(struct netlink_ctx *ctx, const struct handle *h,
                        struct table *table)
 {
        struct chain *chain;
+       struct set *set;
 
        if (netlink_add_table(ctx, h, table) < 0)
                return -1;
        if (table != NULL) {
+               list_for_each_entry(set, &table->sets, list) {
+                       handle_merge(&set->handle, &table->handle);
+                       if (do_add_set(ctx, &set->handle, set) < 0)
+                               return -1;
+               }
                list_for_each_entry(chain, &table->chains, list) {
                        if (do_add_chain(ctx, &chain->handle, chain) < 0)
                                return -1;
@@ -292,6 +406,10 @@ static int do_command_add(struct netlink_ctx *ctx, struct cmd *cmd)
                return do_add_chain(ctx, &cmd->handle, cmd->chain);
        case CMD_OBJ_RULE:
                return netlink_add_rule(ctx, &cmd->handle, cmd->rule);
+       case CMD_OBJ_SET:
+               return do_add_set(ctx, &cmd->handle, cmd->set);
+       case CMD_OBJ_SETELEM:
+               return do_add_setelems(ctx, &cmd->handle, cmd->expr);
        default:
                BUG();
        }
@@ -307,39 +425,76 @@ static int do_command_delete(struct netlink_ctx *ctx, struct cmd *cmd)
                return netlink_delete_chain(ctx, &cmd->handle);
        case CMD_OBJ_RULE:
                return netlink_delete_rule(ctx, &cmd->handle);
+       case CMD_OBJ_SET:
+               return netlink_delete_set(ctx, &cmd->handle);
+       case CMD_OBJ_SETELEM:
+               return netlink_delete_setelems(ctx, &cmd->handle, cmd->expr);
        default:
                BUG();
        }
 }
 
+static int do_list_sets(struct netlink_ctx *ctx, struct table *table)
+{
+       struct set *set, *nset;
+
+       if (netlink_list_sets(ctx, &table->handle) < 0)
+               return -1;
+
+       list_for_each_entry_safe(set, nset, &ctx->list, list) {
+               if (set->flags & SET_F_ANONYMOUS &&
+                   netlink_get_setelems(ctx, &set->handle, set) < 0)
+                       return -1;
+               list_move_tail(&set->list, &table->sets);
+       }
+       return 0;
+}
+
 static int do_command_list(struct netlink_ctx *ctx, struct cmd *cmd)
 {
        struct table *table;
        struct chain *chain;
-       struct rule *rule, *next;
+       struct rule *rule, *nrule;
+       struct set *set, *nset;
+
+       table = table_alloc();
+       handle_merge(&table->handle, &cmd->handle);
+       table_add_hash(table);
 
        switch (cmd->obj) {
        case CMD_OBJ_TABLE:
+               if (do_list_sets(ctx, table) < 0)
+                       return -1;
                if (netlink_list_table(ctx, &cmd->handle) < 0)
                        return -1;
                break;
        case CMD_OBJ_CHAIN:
+               if (do_list_sets(ctx, table) < 0)
+                       return -1;
                if (netlink_list_chain(ctx, &cmd->handle) < 0)
                        return -1;
                break;
+       case CMD_OBJ_SETS:
+               if (netlink_list_sets(ctx, &cmd->handle) < 0)
+                       return -1;
+               list_for_each_entry_safe(set, nset, &ctx->list, list)
+                       list_move_tail(&set->list, &table->sets);
+               break;
+       case CMD_OBJ_SET:
+               if (netlink_get_set(ctx, &cmd->handle) < 0)
+                       return -1;
+               list_for_each_entry(set, &ctx->list, list) {
+                       if (netlink_get_setelems(ctx, &cmd->handle, set) < 0)
+                               return -1;
+                       set_print(set);
+               }
+               return 0;
        default:
                BUG();
        }
 
-       table = NULL;
-       list_for_each_entry_safe(rule, next, &ctx->list, list) {
+       list_for_each_entry_safe(rule, nrule, &ctx->list, list) {
                table = table_lookup(&rule->handle);
-               if (table == NULL) {
-                       table = table_alloc();
-                       handle_merge(&table->handle, &rule->handle);
-                       table_add_hash(table);
-               }
-
                chain = chain_lookup(table, &rule->handle);
                if (chain == NULL) {
                        chain = chain_alloc(rule->handle.chain);
@@ -349,10 +504,7 @@ static int do_command_list(struct netlink_ctx *ctx, struct cmd *cmd)
                list_move_tail(&rule->list, &chain->rules);
        }
 
-       if (table != NULL)
-               table_print(table);
-       else
-               printf("table %s does not exist\n", cmd->handle.table);
+       table_print(table);
        return 0;
 }
 
index f8d018bbc9d2180cb280e89f37e12b23f92c5765..de2373da45dd11b1f1a2574836afc49501a46585 100644 (file)
@@ -210,9 +210,7 @@ addrstring  ({macaddr}|{ip4addr}|{ip6addr})
 "$"                    { return '$'; }
 "="                    { return '='; }
 "=>"                   { return ARROW; }
-"map"                  { return MAP; }
 "vmap"                 { return VMAP; }
-"set"                  { return SET; }
 
 "NF_INET_PRE_ROUTING"  { yylval->val = NF_INET_PRE_ROUTING;    return HOOKNUM; }
 "NF_INET_LOCAL_IN"     { yylval->val = NF_INET_LOCAL_IN;       return HOOKNUM; }
@@ -229,6 +227,10 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
 "table"                        { return TABLE; }
 "chain"                        { return CHAIN; }
 "rule"                 { return RULE; }
+"sets"                 { return SETS; }
+"set"                  { return SET; }
+"element"              { return ELEMENT; }
+"map"                  { return MAP; }
 "handle"               { return HANDLE; }
 
 "accept"               { return ACCEPT; }