Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions include/net/netfilter/nf_tables.h
Original file line number Diff line number Diff line change
Expand Up @@ -761,10 +761,16 @@ static inline struct nft_set_elem_expr *nft_set_ext_expr(const struct nft_set_ex
return nft_set_ext(ext, NFT_SET_EXT_EXPRESSIONS);
}

static inline bool nft_set_elem_expired(const struct nft_set_ext *ext)
static inline bool __nft_set_elem_expired(const struct nft_set_ext *ext,
u64 tstamp)
{
return nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION) &&
time_is_before_eq_jiffies64(*nft_set_ext_expiration(ext));
time_after_eq64(tstamp, *nft_set_ext_expiration(ext));
}

static inline bool nft_set_elem_expired(const struct nft_set_ext *ext)
{
return __nft_set_elem_expired(ext, get_jiffies_64());
}

static inline struct nft_set_ext *nft_set_elem_ext(const struct nft_set *set,
Expand Down Expand Up @@ -1673,6 +1679,7 @@ struct nftables_pernet {
struct list_head notify_list;
struct mutex commit_mutex;
u64 table_handle;
u64 tstamp;
unsigned int base_seq;
unsigned int gc_seq;
u8 validate_state;
Expand All @@ -1685,4 +1692,9 @@ static inline struct nftables_pernet *nft_pernet(const struct net *net)
return net_generic(net, nf_tables_net_id);
}

static inline u64 nft_net_tstamp(const struct net *net)
{
return nft_pernet(net)->tstamp;
}

#endif /* _NET_NF_TABLES_H */
4 changes: 3 additions & 1 deletion net/netfilter/nf_tables_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -9195,6 +9195,7 @@ struct nft_trans_gc *nft_trans_gc_catchall_async(struct nft_trans_gc *gc,
struct nft_trans_gc *nft_trans_gc_catchall_sync(struct nft_trans_gc *gc)
{
struct nft_set_elem_catchall *catchall, *next;
u64 tstamp = nft_net_tstamp(gc->net);
const struct nft_set *set = gc->set;
struct nft_elem_priv *elem_priv;
struct nft_set_elem elem;
Expand All @@ -9205,7 +9206,7 @@ struct nft_trans_gc *nft_trans_gc_catchall_sync(struct nft_trans_gc *gc)
list_for_each_entry_safe(catchall, next, &set->catchall_list, list) {
ext = nft_set_elem_ext(set, catchall->elem);

if (!nft_set_elem_expired(ext))
if (!__nft_set_elem_expired(ext, tstamp))
continue;

gc = nft_trans_gc_queue_sync(gc, GFP_KERNEL);
Expand Down Expand Up @@ -9958,6 +9959,7 @@ static bool nf_tables_valid_genid(struct net *net, u32 genid)
bool genid_ok;

mutex_lock(&nft_net->commit_mutex);
nft_net->tstamp = get_jiffies_64();

genid_ok = genid == 0 || nft_net->base_seq == genid;
if (!genid_ok)
Expand Down
8 changes: 7 additions & 1 deletion net/netfilter/nft_set_hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ struct nft_rhash_cmp_arg {
const struct nft_set *set;
const u32 *key;
u8 genmask;
u64 tstamp;
};

static inline u32 nft_rhash_key(const void *data, u32 len, u32 seed)
Expand All @@ -62,7 +63,7 @@ static inline int nft_rhash_cmp(struct rhashtable_compare_arg *arg,
return 1;
if (nft_set_elem_is_dead(&he->ext))
return 1;
if (nft_set_elem_expired(&he->ext))
if (__nft_set_elem_expired(&he->ext, x->tstamp))
return 1;
if (!nft_set_elem_active(&he->ext, x->genmask))
return 1;
Expand All @@ -87,6 +88,7 @@ bool nft_rhash_lookup(const struct net *net, const struct nft_set *set,
.genmask = nft_genmask_cur(net),
.set = set,
.key = key,
.tstamp = get_jiffies_64(),
};

he = rhashtable_lookup(&priv->ht, &arg, nft_rhash_params);
Expand All @@ -106,6 +108,7 @@ nft_rhash_get(const struct net *net, const struct nft_set *set,
.genmask = nft_genmask_cur(net),
.set = set,
.key = elem->key.val.data,
.tstamp = get_jiffies_64(),
};

he = rhashtable_lookup(&priv->ht, &arg, nft_rhash_params);
Expand All @@ -131,6 +134,7 @@ static bool nft_rhash_update(struct nft_set *set, const u32 *key,
.genmask = NFT_GENMASK_ANY,
.set = set,
.key = key,
.tstamp = get_jiffies_64(),
};

he = rhashtable_lookup(&priv->ht, &arg, nft_rhash_params);
Expand Down Expand Up @@ -175,6 +179,7 @@ static int nft_rhash_insert(const struct net *net, const struct nft_set *set,
.genmask = nft_genmask_next(net),
.set = set,
.key = elem->key.val.data,
.tstamp = nft_net_tstamp(net),
};
struct nft_rhash_elem *prev;

Expand Down Expand Up @@ -216,6 +221,7 @@ nft_rhash_deactivate(const struct net *net, const struct nft_set *set,
.genmask = nft_genmask_next(net),
.set = set,
.key = elem->key.val.data,
.tstamp = nft_net_tstamp(net),
};

rcu_read_lock();
Expand Down
40 changes: 23 additions & 17 deletions net/netfilter/nft_set_pipapo.c
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ static DEFINE_PER_CPU(bool, nft_pipapo_scratch_index);
* Return: -1 on no match, bit position on 'match_only', 0 otherwise.
*/
int pipapo_refill(unsigned long *map, int len, int rules, unsigned long *dst,
union nft_pipapo_map_bucket *mt, bool match_only)
const union nft_pipapo_map_bucket *mt, bool match_only)
{
unsigned long bitset;
int k, ret = -1;
Expand Down Expand Up @@ -414,9 +414,9 @@ bool nft_pipapo_lookup(const struct net *net, const struct nft_set *set,
struct nft_pipapo *priv = nft_set_priv(set);
unsigned long *res_map, *fill_map;
u8 genmask = nft_genmask_cur(net);
const struct nft_pipapo_match *m;
const struct nft_pipapo_field *f;
const u8 *rp = (const u8 *)key;
struct nft_pipapo_match *m;
struct nft_pipapo_field *f;
bool map_index;
int i;

Expand All @@ -432,7 +432,7 @@ bool nft_pipapo_lookup(const struct net *net, const struct nft_set *set,
res_map = *raw_cpu_ptr(m->scratch) + (map_index ? m->bsize_max : 0);
fill_map = *raw_cpu_ptr(m->scratch) + (map_index ? 0 : m->bsize_max);

memset(res_map, 0xff, m->bsize_max * sizeof(*res_map));
pipapo_resmap_init(m, res_map);

nft_pipapo_for_each_field(f, i, m) {
bool last = i == m->field_count - 1;
Expand Down Expand Up @@ -504,6 +504,7 @@ bool nft_pipapo_lookup(const struct net *net, const struct nft_set *set,
* @set: nftables API set representation
* @data: Key data to be matched against existing elements
* @genmask: If set, check that element is active in given genmask
* @tstamp: timestamp to check for expired elements
*
* This is essentially the same as the lookup function, except that it matches
* key data against the uncommitted copy and doesn't use preallocated maps for
Expand All @@ -513,15 +514,18 @@ bool nft_pipapo_lookup(const struct net *net, const struct nft_set *set,
*/
static struct nft_pipapo_elem *pipapo_get(const struct net *net,
const struct nft_set *set,
const u8 *data, u8 genmask)
const u8 *data, u8 genmask,
u64 tstamp)
{
struct nft_pipapo_elem *ret = ERR_PTR(-ENOENT);
struct nft_pipapo *priv = nft_set_priv(set);
struct nft_pipapo_match *m = priv->clone;
unsigned long *res_map, *fill_map = NULL;
struct nft_pipapo_field *f;
const struct nft_pipapo_match *m;
const struct nft_pipapo_field *f;
int i;

m = priv->clone;

res_map = kmalloc_array(m->bsize_max, sizeof(*res_map), GFP_ATOMIC);
if (!res_map) {
ret = ERR_PTR(-ENOMEM);
Expand All @@ -534,7 +538,7 @@ static struct nft_pipapo_elem *pipapo_get(const struct net *net,
goto out;
}

memset(res_map, 0xff, m->bsize_max * sizeof(*res_map));
pipapo_resmap_init(m, res_map);

nft_pipapo_for_each_field(f, i, m) {
bool last = i == m->field_count - 1;
Expand Down Expand Up @@ -566,7 +570,7 @@ static struct nft_pipapo_elem *pipapo_get(const struct net *net,
goto out;

if (last) {
if (nft_set_elem_expired(&f->mt[b].e->ext))
if (__nft_set_elem_expired(&f->mt[b].e->ext, tstamp))
goto next_match;
if ((genmask &&
!nft_set_elem_active(&f->mt[b].e->ext, genmask)))
Expand Down Expand Up @@ -606,7 +610,7 @@ nft_pipapo_get(const struct net *net, const struct nft_set *set,
static struct nft_pipapo_elem *e;

e = pipapo_get(net, set, (const u8 *)elem->key.val.data,
nft_genmask_cur(net));
nft_genmask_cur(net), get_jiffies_64());
if (IS_ERR(e))
return ERR_CAST(e);

Expand Down Expand Up @@ -1173,6 +1177,7 @@ static int nft_pipapo_insert(const struct net *net, const struct nft_set *set,
struct nft_pipapo_match *m = priv->clone;
u8 genmask = nft_genmask_next(net);
struct nft_pipapo_elem *e, *dup;
u64 tstamp = nft_net_tstamp(net);
struct nft_pipapo_field *f;
const u8 *start_p, *end_p;
int i, bsize_max, err = 0;
Expand All @@ -1182,7 +1187,7 @@ static int nft_pipapo_insert(const struct net *net, const struct nft_set *set,
else
end = start;

dup = pipapo_get(net, set, start, genmask);
dup = pipapo_get(net, set, start, genmask, tstamp);
if (!IS_ERR(dup)) {
/* Check if we already have the same exact entry */
const struct nft_data *dup_key, *dup_end;
Expand All @@ -1204,7 +1209,7 @@ static int nft_pipapo_insert(const struct net *net, const struct nft_set *set,

if (PTR_ERR(dup) == -ENOENT) {
/* Look for partially overlapping entries */
dup = pipapo_get(net, set, end, nft_genmask_next(net));
dup = pipapo_get(net, set, end, nft_genmask_next(net), tstamp);
}

if (PTR_ERR(dup) != -ENOENT) {
Expand Down Expand Up @@ -1566,6 +1571,7 @@ static void pipapo_gc(const struct nft_set *_set, struct nft_pipapo_match *m)
struct nft_set *set = (struct nft_set *) _set;
struct nft_pipapo *priv = nft_set_priv(set);
struct net *net = read_pnet(&set->net);
u64 tstamp = nft_net_tstamp(net);
int rules_f0, first_rule = 0;
struct nft_pipapo_elem *e;
struct nft_trans_gc *gc;
Expand All @@ -1576,7 +1582,7 @@ static void pipapo_gc(const struct nft_set *_set, struct nft_pipapo_match *m)

while ((rules_f0 = pipapo_rules_same_key(m->f, first_rule))) {
union nft_pipapo_map_bucket rulemap[NFT_PIPAPO_MAX_FIELDS];
struct nft_pipapo_field *f;
const struct nft_pipapo_field *f;
int i, start, rules_fx;

start = first_rule;
Expand All @@ -1600,7 +1606,7 @@ static void pipapo_gc(const struct nft_set *_set, struct nft_pipapo_match *m)
/* synchronous gc never fails, there is no need to set on
* NFT_SET_ELEM_DEAD_BIT.
*/
if (nft_set_elem_expired(&e->ext)) {
if (__nft_set_elem_expired(&e->ext, tstamp)) {
priv->dirty = true;

gc = nft_trans_gc_queue_sync(gc, GFP_ATOMIC);
Expand Down Expand Up @@ -1775,7 +1781,7 @@ static void *pipapo_deactivate(const struct net *net, const struct nft_set *set,
{
struct nft_pipapo_elem *e;

e = pipapo_get(net, set, data, nft_genmask_next(net));
e = pipapo_get(net, set, data, nft_genmask_next(net), nft_net_tstamp(net));
if (IS_ERR(e))
return NULL;

Expand Down Expand Up @@ -2022,8 +2028,8 @@ static void nft_pipapo_walk(const struct nft_ctx *ctx, struct nft_set *set,
{
struct nft_pipapo *priv = nft_set_priv(set);
struct net *net = read_pnet(&set->net);
struct nft_pipapo_match *m;
struct nft_pipapo_field *f;
const struct nft_pipapo_match *m;
const struct nft_pipapo_field *f;
int i, r;

rcu_read_lock();
Expand Down
27 changes: 24 additions & 3 deletions net/netfilter/nft_set_pipapo.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,15 +179,15 @@ struct nft_pipapo_elem {
};

int pipapo_refill(unsigned long *map, int len, int rules, unsigned long *dst,
union nft_pipapo_map_bucket *mt, bool match_only);
const union nft_pipapo_map_bucket *mt, bool match_only);

/**
* pipapo_and_field_buckets_4bit() - Intersect 4-bit buckets
* @f: Field including lookup table
* @dst: Area to store result
* @data: Input data selecting table buckets
*/
static inline void pipapo_and_field_buckets_4bit(struct nft_pipapo_field *f,
static inline void pipapo_and_field_buckets_4bit(const struct nft_pipapo_field *f,
unsigned long *dst,
const u8 *data)
{
Expand Down Expand Up @@ -215,7 +215,7 @@ static inline void pipapo_and_field_buckets_4bit(struct nft_pipapo_field *f,
* @dst: Area to store result
* @data: Input data selecting table buckets
*/
static inline void pipapo_and_field_buckets_8bit(struct nft_pipapo_field *f,
static inline void pipapo_and_field_buckets_8bit(const struct nft_pipapo_field *f,
unsigned long *dst,
const u8 *data)
{
Expand Down Expand Up @@ -279,4 +279,25 @@ static u64 pipapo_estimate_size(const struct nft_set_desc *desc)
return size;
}

/**
* pipapo_resmap_init() - Initialise result map before first use
* @m: Matching data, including mapping table
* @res_map: Result map
*
* Initialize all bits covered by the first field to one, so that after
* the first step, only the matching bits of the first bit group remain.
*
* If other fields have a large bitmap, set remainder of res_map to 0.
*/
static inline void pipapo_resmap_init(const struct nft_pipapo_match *m, unsigned long *res_map)
{
const struct nft_pipapo_field *f = m->f;
int i;

for (i = 0; i < f->bsize; i++)
res_map[i] = ULONG_MAX;

for (i = f->bsize; i < m->bsize_max; i++)
res_map[i] = 0ul;
}
#endif /* _NFT_SET_PIPAPO_H */
Loading
Loading