Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next
Pablo Neira Ayuso says: ==================== Netfilter updates for net-next The following patchset contains Netfilter updates for net-next: 1) Add nft_reg_store64() and nft_reg_load64() helpers, from Ander Juaristi. 2) Time matching support, also from Ander Juaristi. 3) VLAN support for nfnetlink_log, from Michael Braun. 4) Support for set element deletions from the packet path, also from Ander. 5) Remove __read_mostly from conntrack spinlock, from Li RongQing. 6) Support for updating stateful objects, this also includes the initial client for this infrastructure: the quota extension. A follow up fix for the control plane also comes in this batch. Patches from Fernando Fernandez Mancera. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
b8f6a0eeb9
|
@ -2,6 +2,7 @@
|
|||
#ifndef _NET_NF_TABLES_H
|
||||
#define _NET_NF_TABLES_H
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter/nfnetlink.h>
|
||||
|
@ -102,33 +103,43 @@ struct nft_regs {
|
|||
};
|
||||
};
|
||||
|
||||
/* Store/load an u16 or u8 integer to/from the u32 data register.
|
||||
/* Store/load an u8, u16 or u64 integer to/from the u32 data register.
|
||||
*
|
||||
* Note, when using concatenations, register allocation happens at 32-bit
|
||||
* level. So for store instruction, pad the rest part with zero to avoid
|
||||
* garbage values.
|
||||
*/
|
||||
|
||||
static inline void nft_reg_store16(u32 *dreg, u16 val)
|
||||
{
|
||||
*dreg = 0;
|
||||
*(u16 *)dreg = val;
|
||||
}
|
||||
|
||||
static inline void nft_reg_store8(u32 *dreg, u8 val)
|
||||
{
|
||||
*dreg = 0;
|
||||
*(u8 *)dreg = val;
|
||||
}
|
||||
|
||||
static inline u8 nft_reg_load8(u32 *sreg)
|
||||
{
|
||||
return *(u8 *)sreg;
|
||||
}
|
||||
|
||||
static inline void nft_reg_store16(u32 *dreg, u16 val)
|
||||
{
|
||||
*dreg = 0;
|
||||
*(u16 *)dreg = val;
|
||||
}
|
||||
|
||||
static inline u16 nft_reg_load16(u32 *sreg)
|
||||
{
|
||||
return *(u16 *)sreg;
|
||||
}
|
||||
|
||||
static inline u8 nft_reg_load8(u32 *sreg)
|
||||
static inline void nft_reg_store64(u32 *dreg, u64 val)
|
||||
{
|
||||
return *(u8 *)sreg;
|
||||
put_unaligned(val, (u64 *)dreg);
|
||||
}
|
||||
|
||||
static inline u64 nft_reg_load64(u32 *sreg)
|
||||
{
|
||||
return get_unaligned((u64 *)sreg);
|
||||
}
|
||||
|
||||
static inline void nft_data_copy(u32 *dst, const struct nft_data *src,
|
||||
|
@ -291,17 +302,23 @@ struct nft_expr;
|
|||
* struct nft_set_ops - nf_tables set operations
|
||||
*
|
||||
* @lookup: look up an element within the set
|
||||
* @update: update an element if exists, add it if doesn't exist
|
||||
* @delete: delete an element
|
||||
* @insert: insert new element into set
|
||||
* @activate: activate new element in the next generation
|
||||
* @deactivate: lookup for element and deactivate it in the next generation
|
||||
* @flush: deactivate element in the next generation
|
||||
* @remove: remove element from set
|
||||
* @walk: iterate over all set elemeennts
|
||||
* @walk: iterate over all set elements
|
||||
* @get: get set elements
|
||||
* @privsize: function to return size of set private data
|
||||
* @init: initialize private data of new set instance
|
||||
* @destroy: destroy private data of set instance
|
||||
* @elemsize: element private size
|
||||
*
|
||||
* Operations lookup, update and delete have simpler interfaces, are faster
|
||||
* and currently only used in the packet path. All the rest are slower,
|
||||
* control plane functions.
|
||||
*/
|
||||
struct nft_set_ops {
|
||||
bool (*lookup)(const struct net *net,
|
||||
|
@ -316,6 +333,8 @@ struct nft_set_ops {
|
|||
const struct nft_expr *expr,
|
||||
struct nft_regs *regs,
|
||||
const struct nft_set_ext **ext);
|
||||
bool (*delete)(const struct nft_set *set,
|
||||
const u32 *key);
|
||||
|
||||
int (*insert)(const struct net *net,
|
||||
const struct nft_set *set,
|
||||
|
@ -1108,6 +1127,7 @@ struct nft_object_type {
|
|||
* @init: initialize object from netlink attributes
|
||||
* @destroy: release existing stateful object
|
||||
* @dump: netlink dump stateful object
|
||||
* @update: update stateful object
|
||||
*/
|
||||
struct nft_object_ops {
|
||||
void (*eval)(struct nft_object *obj,
|
||||
|
@ -1122,6 +1142,8 @@ struct nft_object_ops {
|
|||
int (*dump)(struct sk_buff *skb,
|
||||
struct nft_object *obj,
|
||||
bool reset);
|
||||
void (*update)(struct nft_object *obj,
|
||||
struct nft_object *newobj);
|
||||
const struct nft_object_type *type;
|
||||
};
|
||||
|
||||
|
@ -1410,10 +1432,16 @@ struct nft_trans_elem {
|
|||
|
||||
struct nft_trans_obj {
|
||||
struct nft_object *obj;
|
||||
struct nft_object *newobj;
|
||||
bool update;
|
||||
};
|
||||
|
||||
#define nft_trans_obj(trans) \
|
||||
(((struct nft_trans_obj *)trans->data)->obj)
|
||||
#define nft_trans_obj_newobj(trans) \
|
||||
(((struct nft_trans_obj *)trans->data)->newobj)
|
||||
#define nft_trans_obj_update(trans) \
|
||||
(((struct nft_trans_obj *)trans->data)->update)
|
||||
|
||||
struct nft_trans_flowtable {
|
||||
struct nft_flowtable *flowtable;
|
||||
|
|
|
@ -636,6 +636,7 @@ enum nft_lookup_attributes {
|
|||
enum nft_dynset_ops {
|
||||
NFT_DYNSET_OP_ADD,
|
||||
NFT_DYNSET_OP_UPDATE,
|
||||
NFT_DYNSET_OP_DELETE,
|
||||
};
|
||||
|
||||
enum nft_dynset_flags {
|
||||
|
@ -799,6 +800,9 @@ enum nft_exthdr_attributes {
|
|||
* @NFT_META_OIFKIND: packet output interface kind name (dev->rtnl_link_ops->kind)
|
||||
* @NFT_META_BRI_IIFPVID: packet input bridge port pvid
|
||||
* @NFT_META_BRI_IIFVPROTO: packet input bridge vlan proto
|
||||
* @NFT_META_TIME_NS: time since epoch (in nanoseconds)
|
||||
* @NFT_META_TIME_DAY: day of week (from 0 = Sunday to 6 = Saturday)
|
||||
* @NFT_META_TIME_HOUR: hour of day (in seconds)
|
||||
*/
|
||||
enum nft_meta_keys {
|
||||
NFT_META_LEN,
|
||||
|
@ -831,6 +835,9 @@ enum nft_meta_keys {
|
|||
NFT_META_OIFKIND,
|
||||
NFT_META_BRI_IIFPVID,
|
||||
NFT_META_BRI_IIFVPROTO,
|
||||
NFT_META_TIME_NS,
|
||||
NFT_META_TIME_DAY,
|
||||
NFT_META_TIME_HOUR,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -33,6 +33,15 @@ struct nfulnl_msg_packet_timestamp {
|
|||
__aligned_be64 usec;
|
||||
};
|
||||
|
||||
enum nfulnl_vlan_attr {
|
||||
NFULA_VLAN_UNSPEC,
|
||||
NFULA_VLAN_PROTO, /* __be16 skb vlan_proto */
|
||||
NFULA_VLAN_TCI, /* __be16 skb htons(vlan_tci) */
|
||||
__NFULA_VLAN_MAX,
|
||||
};
|
||||
|
||||
#define NFULA_VLAN_MAX (__NFULA_VLAN_MAX + 1)
|
||||
|
||||
enum nfulnl_attr_type {
|
||||
NFULA_UNSPEC,
|
||||
NFULA_PACKET_HDR,
|
||||
|
@ -54,6 +63,8 @@ enum nfulnl_attr_type {
|
|||
NFULA_HWLEN, /* hardware header length */
|
||||
NFULA_CT, /* nf_conntrack_netlink.h */
|
||||
NFULA_CT_INFO, /* enum ip_conntrack_info */
|
||||
NFULA_VLAN, /* nested attribute: packet vlan info */
|
||||
NFULA_L2HDR, /* full L2 header */
|
||||
|
||||
__NFULA_MAX
|
||||
};
|
||||
|
|
|
@ -73,8 +73,7 @@ struct conntrack_gc_work {
|
|||
};
|
||||
|
||||
static __read_mostly struct kmem_cache *nf_conntrack_cachep;
|
||||
static __read_mostly spinlock_t nf_conntrack_locks_all_lock;
|
||||
static __read_mostly DEFINE_SPINLOCK(nf_conntrack_locks_all_lock);
|
||||
static DEFINE_SPINLOCK(nf_conntrack_locks_all_lock);
|
||||
static __read_mostly bool nf_conntrack_locks_all;
|
||||
|
||||
/* every gc cycle scans at most 1/GC_MAX_BUCKETS_DIV part of table */
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#include <net/netfilter/nf_conntrack_ecache.h>
|
||||
#include <net/netfilter/nf_conntrack_labels.h>
|
||||
|
||||
static __read_mostly DEFINE_SPINLOCK(nf_connlabels_lock);
|
||||
static DEFINE_SPINLOCK(nf_connlabels_lock);
|
||||
|
||||
static int replace_u32(u32 *address, u32 mask, u32 new)
|
||||
{
|
||||
|
|
|
@ -5131,6 +5131,41 @@ nft_obj_type_get(struct net *net, u32 objtype)
|
|||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
|
||||
static int nf_tables_updobj(const struct nft_ctx *ctx,
|
||||
const struct nft_object_type *type,
|
||||
const struct nlattr *attr,
|
||||
struct nft_object *obj)
|
||||
{
|
||||
struct nft_object *newobj;
|
||||
struct nft_trans *trans;
|
||||
int err;
|
||||
|
||||
if (!obj->ops->update)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
trans = nft_trans_alloc(ctx, NFT_MSG_NEWOBJ,
|
||||
sizeof(struct nft_trans_obj));
|
||||
if (!trans)
|
||||
return -ENOMEM;
|
||||
|
||||
newobj = nft_obj_init(ctx, type, attr);
|
||||
if (IS_ERR(newobj)) {
|
||||
err = PTR_ERR(newobj);
|
||||
goto err1;
|
||||
}
|
||||
|
||||
nft_trans_obj(trans) = obj;
|
||||
nft_trans_obj_update(trans) = true;
|
||||
nft_trans_obj_newobj(trans) = newobj;
|
||||
list_add_tail(&trans->list, &ctx->net->nft.commit_list);
|
||||
|
||||
return 0;
|
||||
err1:
|
||||
kfree(trans);
|
||||
kfree(newobj);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int nf_tables_newobj(struct net *net, struct sock *nlsk,
|
||||
struct sk_buff *skb, const struct nlmsghdr *nlh,
|
||||
const struct nlattr * const nla[],
|
||||
|
@ -5170,7 +5205,13 @@ static int nf_tables_newobj(struct net *net, struct sock *nlsk,
|
|||
NL_SET_BAD_ATTR(extack, nla[NFTA_OBJ_NAME]);
|
||||
return -EEXIST;
|
||||
}
|
||||
return 0;
|
||||
if (nlh->nlmsg_flags & NLM_F_REPLACE)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
type = nft_obj_type_get(net, objtype);
|
||||
nft_ctx_init(&ctx, net, skb, nlh, family, table, NULL, nla);
|
||||
|
||||
return nf_tables_updobj(&ctx, type, nla[NFTA_OBJ_DATA], obj);
|
||||
}
|
||||
|
||||
nft_ctx_init(&ctx, net, skb, nlh, family, table, NULL, nla);
|
||||
|
@ -6431,6 +6472,19 @@ static void nft_chain_commit_update(struct nft_trans *trans)
|
|||
}
|
||||
}
|
||||
|
||||
static void nft_obj_commit_update(struct nft_trans *trans)
|
||||
{
|
||||
struct nft_object *newobj;
|
||||
struct nft_object *obj;
|
||||
|
||||
obj = nft_trans_obj(trans);
|
||||
newobj = nft_trans_obj_newobj(trans);
|
||||
|
||||
obj->ops->update(obj, newobj);
|
||||
|
||||
kfree(newobj);
|
||||
}
|
||||
|
||||
static void nft_commit_release(struct nft_trans *trans)
|
||||
{
|
||||
switch (trans->msg_type) {
|
||||
|
@ -6795,10 +6849,18 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
|
|||
te->set->ndeact--;
|
||||
break;
|
||||
case NFT_MSG_NEWOBJ:
|
||||
nft_clear(net, nft_trans_obj(trans));
|
||||
nf_tables_obj_notify(&trans->ctx, nft_trans_obj(trans),
|
||||
NFT_MSG_NEWOBJ);
|
||||
nft_trans_destroy(trans);
|
||||
if (nft_trans_obj_update(trans)) {
|
||||
nft_obj_commit_update(trans);
|
||||
nf_tables_obj_notify(&trans->ctx,
|
||||
nft_trans_obj(trans),
|
||||
NFT_MSG_NEWOBJ);
|
||||
} else {
|
||||
nft_clear(net, nft_trans_obj(trans));
|
||||
nf_tables_obj_notify(&trans->ctx,
|
||||
nft_trans_obj(trans),
|
||||
NFT_MSG_NEWOBJ);
|
||||
nft_trans_destroy(trans);
|
||||
}
|
||||
break;
|
||||
case NFT_MSG_DELOBJ:
|
||||
nft_obj_del(nft_trans_obj(trans));
|
||||
|
@ -6945,8 +7007,13 @@ static int __nf_tables_abort(struct net *net)
|
|||
nft_trans_destroy(trans);
|
||||
break;
|
||||
case NFT_MSG_NEWOBJ:
|
||||
trans->ctx.table->use--;
|
||||
nft_obj_del(nft_trans_obj(trans));
|
||||
if (nft_trans_obj_update(trans)) {
|
||||
kfree(nft_trans_obj_newobj(trans));
|
||||
nft_trans_destroy(trans);
|
||||
} else {
|
||||
trans->ctx.table->use--;
|
||||
nft_obj_del(nft_trans_obj(trans));
|
||||
}
|
||||
break;
|
||||
case NFT_MSG_DELOBJ:
|
||||
trans->ctx.table->use++;
|
||||
|
|
|
@ -385,6 +385,57 @@ nfulnl_timer(struct timer_list *t)
|
|||
instance_put(inst);
|
||||
}
|
||||
|
||||
static u32 nfulnl_get_bridge_size(const struct sk_buff *skb)
|
||||
{
|
||||
u32 size = 0;
|
||||
|
||||
if (!skb_mac_header_was_set(skb))
|
||||
return 0;
|
||||
|
||||
if (skb_vlan_tag_present(skb)) {
|
||||
size += nla_total_size(0); /* nested */
|
||||
size += nla_total_size(sizeof(u16)); /* id */
|
||||
size += nla_total_size(sizeof(u16)); /* tag */
|
||||
}
|
||||
|
||||
if (skb->network_header > skb->mac_header)
|
||||
size += nla_total_size(skb->network_header - skb->mac_header);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static int nfulnl_put_bridge(struct nfulnl_instance *inst, const struct sk_buff *skb)
|
||||
{
|
||||
if (!skb_mac_header_was_set(skb))
|
||||
return 0;
|
||||
|
||||
if (skb_vlan_tag_present(skb)) {
|
||||
struct nlattr *nest;
|
||||
|
||||
nest = nla_nest_start(inst->skb, NFULA_VLAN);
|
||||
if (!nest)
|
||||
goto nla_put_failure;
|
||||
|
||||
if (nla_put_be16(inst->skb, NFULA_VLAN_TCI, htons(skb->vlan_tci)) ||
|
||||
nla_put_be16(inst->skb, NFULA_VLAN_PROTO, skb->vlan_proto))
|
||||
goto nla_put_failure;
|
||||
|
||||
nla_nest_end(inst->skb, nest);
|
||||
}
|
||||
|
||||
if (skb->mac_header < skb->network_header) {
|
||||
int len = (int)(skb->network_header - skb->mac_header);
|
||||
|
||||
if (nla_put(inst->skb, NFULA_L2HDR, len, skb_mac_header(skb)))
|
||||
goto nla_put_failure;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* This is an inline function, we don't really care about a long
|
||||
* list of arguments */
|
||||
static inline int
|
||||
|
@ -580,6 +631,10 @@ __build_packet_message(struct nfnl_log_net *log,
|
|||
NFULA_CT, NFULA_CT_INFO) < 0)
|
||||
goto nla_put_failure;
|
||||
|
||||
if ((pf == NFPROTO_NETDEV || pf == NFPROTO_BRIDGE) &&
|
||||
nfulnl_put_bridge(inst, skb) < 0)
|
||||
goto nla_put_failure;
|
||||
|
||||
if (data_len) {
|
||||
struct nlattr *nla;
|
||||
int size = nla_attr_size(data_len);
|
||||
|
@ -687,6 +742,8 @@ nfulnl_log_packet(struct net *net,
|
|||
size += nfnl_ct->build_size(ct);
|
||||
}
|
||||
}
|
||||
if (pf == NFPROTO_NETDEV || pf == NFPROTO_BRIDGE)
|
||||
size += nfulnl_get_bridge_size(skb);
|
||||
|
||||
qthreshold = inst->qthreshold;
|
||||
/* per-rule qthreshold overrides per-instance */
|
||||
|
|
|
@ -43,14 +43,15 @@ void nft_byteorder_eval(const struct nft_expr *expr,
|
|||
switch (priv->op) {
|
||||
case NFT_BYTEORDER_NTOH:
|
||||
for (i = 0; i < priv->len / 8; i++) {
|
||||
src64 = get_unaligned((u64 *)&src[i]);
|
||||
put_unaligned_be64(src64, &dst[i]);
|
||||
src64 = nft_reg_load64(&src[i]);
|
||||
nft_reg_store64(&dst[i], be64_to_cpu(src64));
|
||||
}
|
||||
break;
|
||||
case NFT_BYTEORDER_HTON:
|
||||
for (i = 0; i < priv->len / 8; i++) {
|
||||
src64 = get_unaligned_be64(&src[i]);
|
||||
put_unaligned(src64, (u64 *)&dst[i]);
|
||||
src64 = (__force __u64)
|
||||
cpu_to_be64(nft_reg_load64(&src[i]));
|
||||
nft_reg_store64(&dst[i], src64);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -84,6 +84,11 @@ void nft_dynset_eval(const struct nft_expr *expr,
|
|||
const struct nft_expr *sexpr;
|
||||
u64 timeout;
|
||||
|
||||
if (priv->op == NFT_DYNSET_OP_DELETE) {
|
||||
set->ops->delete(set, ®s->data[priv->sreg_key]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (set->ops->update(set, ®s->data[priv->sreg_key], nft_dynset_new,
|
||||
expr, regs, &ext)) {
|
||||
sexpr = NULL;
|
||||
|
@ -161,6 +166,7 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
|
|||
priv->op = ntohl(nla_get_be32(tb[NFTA_DYNSET_OP]));
|
||||
switch (priv->op) {
|
||||
case NFT_DYNSET_OP_ADD:
|
||||
case NFT_DYNSET_OP_DELETE:
|
||||
break;
|
||||
case NFT_DYNSET_OP_UPDATE:
|
||||
if (!(set->flags & NFT_SET_TIMEOUT))
|
||||
|
|
|
@ -26,8 +26,36 @@
|
|||
|
||||
#include <uapi/linux/netfilter_bridge.h> /* NF_BR_PRE_ROUTING */
|
||||
|
||||
#define NFT_META_SECS_PER_MINUTE 60
|
||||
#define NFT_META_SECS_PER_HOUR 3600
|
||||
#define NFT_META_SECS_PER_DAY 86400
|
||||
#define NFT_META_DAYS_PER_WEEK 7
|
||||
|
||||
static DEFINE_PER_CPU(struct rnd_state, nft_prandom_state);
|
||||
|
||||
static u8 nft_meta_weekday(unsigned long secs)
|
||||
{
|
||||
unsigned int dse;
|
||||
u8 wday;
|
||||
|
||||
secs -= NFT_META_SECS_PER_MINUTE * sys_tz.tz_minuteswest;
|
||||
dse = secs / NFT_META_SECS_PER_DAY;
|
||||
wday = (4 + dse) % NFT_META_DAYS_PER_WEEK;
|
||||
|
||||
return wday;
|
||||
}
|
||||
|
||||
static u32 nft_meta_hour(unsigned long secs)
|
||||
{
|
||||
struct tm tm;
|
||||
|
||||
time64_to_tm(secs, 0, &tm);
|
||||
|
||||
return tm.tm_hour * NFT_META_SECS_PER_HOUR
|
||||
+ tm.tm_min * NFT_META_SECS_PER_MINUTE
|
||||
+ tm.tm_sec;
|
||||
}
|
||||
|
||||
void nft_meta_get_eval(const struct nft_expr *expr,
|
||||
struct nft_regs *regs,
|
||||
const struct nft_pktinfo *pkt)
|
||||
|
@ -218,6 +246,15 @@ void nft_meta_get_eval(const struct nft_expr *expr,
|
|||
goto err;
|
||||
strncpy((char *)dest, out->rtnl_link_ops->kind, IFNAMSIZ);
|
||||
break;
|
||||
case NFT_META_TIME_NS:
|
||||
nft_reg_store64(dest, ktime_get_real_ns());
|
||||
break;
|
||||
case NFT_META_TIME_DAY:
|
||||
nft_reg_store8(dest, nft_meta_weekday(get_seconds()));
|
||||
break;
|
||||
case NFT_META_TIME_HOUR:
|
||||
*dest = nft_meta_hour(get_seconds());
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
goto err;
|
||||
|
@ -330,6 +367,15 @@ int nft_meta_get_init(const struct nft_ctx *ctx,
|
|||
len = sizeof(u8);
|
||||
break;
|
||||
#endif
|
||||
case NFT_META_TIME_NS:
|
||||
len = sizeof(u64);
|
||||
break;
|
||||
case NFT_META_TIME_DAY:
|
||||
len = sizeof(u8);
|
||||
break;
|
||||
case NFT_META_TIME_HOUR:
|
||||
len = sizeof(u32);
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include <net/netfilter/nf_tables.h>
|
||||
|
||||
struct nft_quota {
|
||||
u64 quota;
|
||||
atomic64_t quota;
|
||||
unsigned long flags;
|
||||
atomic64_t consumed;
|
||||
};
|
||||
|
@ -21,7 +21,8 @@ struct nft_quota {
|
|||
static inline bool nft_overquota(struct nft_quota *priv,
|
||||
const struct sk_buff *skb)
|
||||
{
|
||||
return atomic64_add_return(skb->len, &priv->consumed) >= priv->quota;
|
||||
return atomic64_add_return(skb->len, &priv->consumed) >=
|
||||
atomic64_read(&priv->quota);
|
||||
}
|
||||
|
||||
static inline bool nft_quota_invert(struct nft_quota *priv)
|
||||
|
@ -89,7 +90,7 @@ static int nft_quota_do_init(const struct nlattr * const tb[],
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
priv->quota = quota;
|
||||
atomic64_set(&priv->quota, quota);
|
||||
priv->flags = flags;
|
||||
atomic64_set(&priv->consumed, consumed);
|
||||
|
||||
|
@ -105,10 +106,22 @@ static int nft_quota_obj_init(const struct nft_ctx *ctx,
|
|||
return nft_quota_do_init(tb, priv);
|
||||
}
|
||||
|
||||
static void nft_quota_obj_update(struct nft_object *obj,
|
||||
struct nft_object *newobj)
|
||||
{
|
||||
struct nft_quota *newpriv = nft_obj_data(newobj);
|
||||
struct nft_quota *priv = nft_obj_data(obj);
|
||||
u64 newquota;
|
||||
|
||||
newquota = atomic64_read(&newpriv->quota);
|
||||
atomic64_set(&priv->quota, newquota);
|
||||
priv->flags = newpriv->flags;
|
||||
}
|
||||
|
||||
static int nft_quota_do_dump(struct sk_buff *skb, struct nft_quota *priv,
|
||||
bool reset)
|
||||
{
|
||||
u64 consumed, consumed_cap;
|
||||
u64 consumed, consumed_cap, quota;
|
||||
u32 flags = priv->flags;
|
||||
|
||||
/* Since we inconditionally increment consumed quota for each packet
|
||||
|
@ -116,14 +129,15 @@ static int nft_quota_do_dump(struct sk_buff *skb, struct nft_quota *priv,
|
|||
* userspace.
|
||||
*/
|
||||
consumed = atomic64_read(&priv->consumed);
|
||||
if (consumed >= priv->quota) {
|
||||
consumed_cap = priv->quota;
|
||||
quota = atomic64_read(&priv->quota);
|
||||
if (consumed >= quota) {
|
||||
consumed_cap = quota;
|
||||
flags |= NFT_QUOTA_F_DEPLETED;
|
||||
} else {
|
||||
consumed_cap = consumed;
|
||||
}
|
||||
|
||||
if (nla_put_be64(skb, NFTA_QUOTA_BYTES, cpu_to_be64(priv->quota),
|
||||
if (nla_put_be64(skb, NFTA_QUOTA_BYTES, cpu_to_be64(quota),
|
||||
NFTA_QUOTA_PAD) ||
|
||||
nla_put_be64(skb, NFTA_QUOTA_CONSUMED, cpu_to_be64(consumed_cap),
|
||||
NFTA_QUOTA_PAD) ||
|
||||
|
@ -155,6 +169,7 @@ static const struct nft_object_ops nft_quota_obj_ops = {
|
|||
.init = nft_quota_obj_init,
|
||||
.eval = nft_quota_obj_eval,
|
||||
.dump = nft_quota_obj_dump,
|
||||
.update = nft_quota_obj_update,
|
||||
};
|
||||
|
||||
static struct nft_object_type nft_quota_obj_type __read_mostly = {
|
||||
|
|
|
@ -234,6 +234,24 @@ static void nft_rhash_remove(const struct net *net,
|
|||
rhashtable_remove_fast(&priv->ht, &he->node, nft_rhash_params);
|
||||
}
|
||||
|
||||
static bool nft_rhash_delete(const struct nft_set *set,
|
||||
const u32 *key)
|
||||
{
|
||||
struct nft_rhash *priv = nft_set_priv(set);
|
||||
struct nft_rhash_cmp_arg arg = {
|
||||
.genmask = NFT_GENMASK_ANY,
|
||||
.set = set,
|
||||
.key = key,
|
||||
};
|
||||
struct nft_rhash_elem *he;
|
||||
|
||||
he = rhashtable_lookup(&priv->ht, &arg, nft_rhash_params);
|
||||
if (he == NULL)
|
||||
return false;
|
||||
|
||||
return rhashtable_remove_fast(&priv->ht, &he->node, nft_rhash_params) == 0;
|
||||
}
|
||||
|
||||
static void nft_rhash_walk(const struct nft_ctx *ctx, struct nft_set *set,
|
||||
struct nft_set_iter *iter)
|
||||
{
|
||||
|
@ -662,6 +680,7 @@ struct nft_set_type nft_set_rhash_type __read_mostly = {
|
|||
.remove = nft_rhash_remove,
|
||||
.lookup = nft_rhash_lookup,
|
||||
.update = nft_rhash_update,
|
||||
.delete = nft_rhash_delete,
|
||||
.walk = nft_rhash_walk,
|
||||
.get = nft_rhash_get,
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue