Commit b8f6a0ee authored by David S. Miller's avatar David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 6938843d aa4095a1
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#ifndef _NET_NF_TABLES_H #ifndef _NET_NF_TABLES_H
#define _NET_NF_TABLES_H #define _NET_NF_TABLES_H
#include <asm/unaligned.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/netfilter.h> #include <linux/netfilter.h>
#include <linux/netfilter/nfnetlink.h> #include <linux/netfilter/nfnetlink.h>
...@@ -102,23 +103,28 @@ struct nft_regs { ...@@ -102,23 +103,28 @@ 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 * Note, when using concatenations, register allocation happens at 32-bit
* level. So for store instruction, pad the rest part with zero to avoid * level. So for store instruction, pad the rest part with zero to avoid
* garbage values. * garbage values.
*/ */
static inline void nft_reg_store16(u32 *dreg, u16 val) static inline void nft_reg_store8(u32 *dreg, u8 val)
{ {
*dreg = 0; *dreg = 0;
*(u16 *)dreg = val; *(u8 *)dreg = val;
} }
static inline void nft_reg_store8(u32 *dreg, u8 val) static inline u8 nft_reg_load8(u32 *sreg)
{
return *(u8 *)sreg;
}
static inline void nft_reg_store16(u32 *dreg, u16 val)
{ {
*dreg = 0; *dreg = 0;
*(u8 *)dreg = val; *(u16 *)dreg = val;
} }
static inline u16 nft_reg_load16(u32 *sreg) static inline u16 nft_reg_load16(u32 *sreg)
...@@ -126,9 +132,14 @@ static inline u16 nft_reg_load16(u32 *sreg) ...@@ -126,9 +132,14 @@ static inline u16 nft_reg_load16(u32 *sreg)
return *(u16 *)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, static inline void nft_data_copy(u32 *dst, const struct nft_data *src,
...@@ -291,17 +302,23 @@ struct nft_expr; ...@@ -291,17 +302,23 @@ struct nft_expr;
* struct nft_set_ops - nf_tables set operations * struct nft_set_ops - nf_tables set operations
* *
* @lookup: look up an element within the set * @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 * @insert: insert new element into set
* @activate: activate new element in the next generation * @activate: activate new element in the next generation
* @deactivate: lookup for element and deactivate it in the next generation * @deactivate: lookup for element and deactivate it in the next generation
* @flush: deactivate element in the next generation * @flush: deactivate element in the next generation
* @remove: remove element from set * @remove: remove element from set
* @walk: iterate over all set elemeennts * @walk: iterate over all set elements
* @get: get set elements * @get: get set elements
* @privsize: function to return size of set private data * @privsize: function to return size of set private data
* @init: initialize private data of new set instance * @init: initialize private data of new set instance
* @destroy: destroy private data of set instance * @destroy: destroy private data of set instance
* @elemsize: element private size * @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 { struct nft_set_ops {
bool (*lookup)(const struct net *net, bool (*lookup)(const struct net *net,
...@@ -316,6 +333,8 @@ struct nft_set_ops { ...@@ -316,6 +333,8 @@ struct nft_set_ops {
const struct nft_expr *expr, const struct nft_expr *expr,
struct nft_regs *regs, struct nft_regs *regs,
const struct nft_set_ext **ext); const struct nft_set_ext **ext);
bool (*delete)(const struct nft_set *set,
const u32 *key);
int (*insert)(const struct net *net, int (*insert)(const struct net *net,
const struct nft_set *set, const struct nft_set *set,
...@@ -1108,6 +1127,7 @@ struct nft_object_type { ...@@ -1108,6 +1127,7 @@ struct nft_object_type {
* @init: initialize object from netlink attributes * @init: initialize object from netlink attributes
* @destroy: release existing stateful object * @destroy: release existing stateful object
* @dump: netlink dump stateful object * @dump: netlink dump stateful object
* @update: update stateful object
*/ */
struct nft_object_ops { struct nft_object_ops {
void (*eval)(struct nft_object *obj, void (*eval)(struct nft_object *obj,
...@@ -1122,6 +1142,8 @@ struct nft_object_ops { ...@@ -1122,6 +1142,8 @@ struct nft_object_ops {
int (*dump)(struct sk_buff *skb, int (*dump)(struct sk_buff *skb,
struct nft_object *obj, struct nft_object *obj,
bool reset); bool reset);
void (*update)(struct nft_object *obj,
struct nft_object *newobj);
const struct nft_object_type *type; const struct nft_object_type *type;
}; };
...@@ -1410,10 +1432,16 @@ struct nft_trans_elem { ...@@ -1410,10 +1432,16 @@ struct nft_trans_elem {
struct nft_trans_obj { struct nft_trans_obj {
struct nft_object *obj; struct nft_object *obj;
struct nft_object *newobj;
bool update;
}; };
#define nft_trans_obj(trans) \ #define nft_trans_obj(trans) \
(((struct nft_trans_obj *)trans->data)->obj) (((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_trans_flowtable {
struct nft_flowtable *flowtable; struct nft_flowtable *flowtable;
......
...@@ -636,6 +636,7 @@ enum nft_lookup_attributes { ...@@ -636,6 +636,7 @@ enum nft_lookup_attributes {
enum nft_dynset_ops { enum nft_dynset_ops {
NFT_DYNSET_OP_ADD, NFT_DYNSET_OP_ADD,
NFT_DYNSET_OP_UPDATE, NFT_DYNSET_OP_UPDATE,
NFT_DYNSET_OP_DELETE,
}; };
enum nft_dynset_flags { enum nft_dynset_flags {
...@@ -799,6 +800,9 @@ enum nft_exthdr_attributes { ...@@ -799,6 +800,9 @@ enum nft_exthdr_attributes {
* @NFT_META_OIFKIND: packet output interface kind name (dev->rtnl_link_ops->kind) * @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_IIFPVID: packet input bridge port pvid
* @NFT_META_BRI_IIFVPROTO: packet input bridge vlan proto * @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 { enum nft_meta_keys {
NFT_META_LEN, NFT_META_LEN,
...@@ -831,6 +835,9 @@ enum nft_meta_keys { ...@@ -831,6 +835,9 @@ enum nft_meta_keys {
NFT_META_OIFKIND, NFT_META_OIFKIND,
NFT_META_BRI_IIFPVID, NFT_META_BRI_IIFPVID,
NFT_META_BRI_IIFVPROTO, 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 { ...@@ -33,6 +33,15 @@ struct nfulnl_msg_packet_timestamp {
__aligned_be64 usec; __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 { enum nfulnl_attr_type {
NFULA_UNSPEC, NFULA_UNSPEC,
NFULA_PACKET_HDR, NFULA_PACKET_HDR,
...@@ -54,6 +63,8 @@ enum nfulnl_attr_type { ...@@ -54,6 +63,8 @@ enum nfulnl_attr_type {
NFULA_HWLEN, /* hardware header length */ NFULA_HWLEN, /* hardware header length */
NFULA_CT, /* nf_conntrack_netlink.h */ NFULA_CT, /* nf_conntrack_netlink.h */
NFULA_CT_INFO, /* enum ip_conntrack_info */ NFULA_CT_INFO, /* enum ip_conntrack_info */
NFULA_VLAN, /* nested attribute: packet vlan info */
NFULA_L2HDR, /* full L2 header */
__NFULA_MAX __NFULA_MAX
}; };
......
...@@ -73,8 +73,7 @@ struct conntrack_gc_work { ...@@ -73,8 +73,7 @@ struct conntrack_gc_work {
}; };
static __read_mostly struct kmem_cache *nf_conntrack_cachep; static __read_mostly struct kmem_cache *nf_conntrack_cachep;
static __read_mostly spinlock_t nf_conntrack_locks_all_lock; static DEFINE_SPINLOCK(nf_conntrack_locks_all_lock);
static __read_mostly DEFINE_SPINLOCK(nf_conntrack_locks_all_lock);
static __read_mostly bool nf_conntrack_locks_all; static __read_mostly bool nf_conntrack_locks_all;
/* every gc cycle scans at most 1/GC_MAX_BUCKETS_DIV part of table */ /* every gc cycle scans at most 1/GC_MAX_BUCKETS_DIV part of table */
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
#include <net/netfilter/nf_conntrack_ecache.h> #include <net/netfilter/nf_conntrack_ecache.h>
#include <net/netfilter/nf_conntrack_labels.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) static int replace_u32(u32 *address, u32 mask, u32 new)
{ {
......
...@@ -5131,6 +5131,41 @@ nft_obj_type_get(struct net *net, u32 objtype) ...@@ -5131,6 +5131,41 @@ nft_obj_type_get(struct net *net, u32 objtype)
return ERR_PTR(-ENOENT); 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, static int nf_tables_newobj(struct net *net, struct sock *nlsk,
struct sk_buff *skb, const struct nlmsghdr *nlh, struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const nla[], const struct nlattr * const nla[],
...@@ -5170,7 +5205,13 @@ static int nf_tables_newobj(struct net *net, struct sock *nlsk, ...@@ -5170,7 +5205,13 @@ static int nf_tables_newobj(struct net *net, struct sock *nlsk,
NL_SET_BAD_ATTR(extack, nla[NFTA_OBJ_NAME]); NL_SET_BAD_ATTR(extack, nla[NFTA_OBJ_NAME]);
return -EEXIST; 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); 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) ...@@ -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) static void nft_commit_release(struct nft_trans *trans)
{ {
switch (trans->msg_type) { switch (trans->msg_type) {
...@@ -6795,10 +6849,18 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb) ...@@ -6795,10 +6849,18 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
te->set->ndeact--; te->set->ndeact--;
break; break;
case NFT_MSG_NEWOBJ: case NFT_MSG_NEWOBJ:
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)); nft_clear(net, nft_trans_obj(trans));
nf_tables_obj_notify(&trans->ctx, nft_trans_obj(trans), nf_tables_obj_notify(&trans->ctx,
nft_trans_obj(trans),
NFT_MSG_NEWOBJ); NFT_MSG_NEWOBJ);
nft_trans_destroy(trans); nft_trans_destroy(trans);
}
break; break;
case NFT_MSG_DELOBJ: case NFT_MSG_DELOBJ:
nft_obj_del(nft_trans_obj(trans)); nft_obj_del(nft_trans_obj(trans));
...@@ -6945,8 +7007,13 @@ static int __nf_tables_abort(struct net *net) ...@@ -6945,8 +7007,13 @@ static int __nf_tables_abort(struct net *net)
nft_trans_destroy(trans); nft_trans_destroy(trans);
break; break;
case NFT_MSG_NEWOBJ: case NFT_MSG_NEWOBJ:
if (nft_trans_obj_update(trans)) {
kfree(nft_trans_obj_newobj(trans));
nft_trans_destroy(trans);
} else {
trans->ctx.table->use--; trans->ctx.table->use--;
nft_obj_del(nft_trans_obj(trans)); nft_obj_del(nft_trans_obj(trans));
}
break; break;
case NFT_MSG_DELOBJ: case NFT_MSG_DELOBJ:
trans->ctx.table->use++; trans->ctx.table->use++;
......
...@@ -385,6 +385,57 @@ nfulnl_timer(struct timer_list *t) ...@@ -385,6 +385,57 @@ nfulnl_timer(struct timer_list *t)
instance_put(inst); 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 /* This is an inline function, we don't really care about a long
* list of arguments */ * list of arguments */
static inline int static inline int
...@@ -580,6 +631,10 @@ __build_packet_message(struct nfnl_log_net *log, ...@@ -580,6 +631,10 @@ __build_packet_message(struct nfnl_log_net *log,
NFULA_CT, NFULA_CT_INFO) < 0) NFULA_CT, NFULA_CT_INFO) < 0)
goto nla_put_failure; goto nla_put_failure;
if ((pf == NFPROTO_NETDEV || pf == NFPROTO_BRIDGE) &&
nfulnl_put_bridge(inst, skb) < 0)
goto nla_put_failure;
if (data_len) { if (data_len) {
struct nlattr *nla; struct nlattr *nla;
int size = nla_attr_size(data_len); int size = nla_attr_size(data_len);
...@@ -687,6 +742,8 @@ nfulnl_log_packet(struct net *net, ...@@ -687,6 +742,8 @@ nfulnl_log_packet(struct net *net,
size += nfnl_ct->build_size(ct); size += nfnl_ct->build_size(ct);
} }
} }
if (pf == NFPROTO_NETDEV || pf == NFPROTO_BRIDGE)
size += nfulnl_get_bridge_size(skb);
qthreshold = inst->qthreshold; qthreshold = inst->qthreshold;
/* per-rule qthreshold overrides per-instance */ /* per-rule qthreshold overrides per-instance */
......
...@@ -43,14 +43,15 @@ void nft_byteorder_eval(const struct nft_expr *expr, ...@@ -43,14 +43,15 @@ void nft_byteorder_eval(const struct nft_expr *expr,
switch (priv->op) { switch (priv->op) {
case NFT_BYTEORDER_NTOH: case NFT_BYTEORDER_NTOH:
for (i = 0; i < priv->len / 8; i++) { for (i = 0; i < priv->len / 8; i++) {
src64 = get_unaligned((u64 *)&src[i]); src64 = nft_reg_load64(&src[i]);
put_unaligned_be64(src64, &dst[i]); nft_reg_store64(&dst[i], be64_to_cpu(src64));
} }
break; break;
case NFT_BYTEORDER_HTON: case NFT_BYTEORDER_HTON:
for (i = 0; i < priv->len / 8; i++) { for (i = 0; i < priv->len / 8; i++) {
src64 = get_unaligned_be64(&src[i]); src64 = (__force __u64)
put_unaligned(src64, (u64 *)&dst[i]); cpu_to_be64(nft_reg_load64(&src[i]));
nft_reg_store64(&dst[i], src64);
} }
break; break;
} }
......
...@@ -84,6 +84,11 @@ void nft_dynset_eval(const struct nft_expr *expr, ...@@ -84,6 +84,11 @@ void nft_dynset_eval(const struct nft_expr *expr,
const struct nft_expr *sexpr; const struct nft_expr *sexpr;
u64 timeout; u64 timeout;
if (priv->op == NFT_DYNSET_OP_DELETE) {
set->ops->delete(set, &regs->data[priv->sreg_key]);
return;
}
if (set->ops->update(set, &regs->data[priv->sreg_key], nft_dynset_new, if (set->ops->update(set, &regs->data[priv->sreg_key], nft_dynset_new,
expr, regs, &ext)) { expr, regs, &ext)) {
sexpr = NULL; sexpr = NULL;
...@@ -161,6 +166,7 @@ static int nft_dynset_init(const struct nft_ctx *ctx, ...@@ -161,6 +166,7 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
priv->op = ntohl(nla_get_be32(tb[NFTA_DYNSET_OP])); priv->op = ntohl(nla_get_be32(tb[NFTA_DYNSET_OP]));
switch (priv->op) { switch (priv->op) {
case NFT_DYNSET_OP_ADD: case NFT_DYNSET_OP_ADD:
case NFT_DYNSET_OP_DELETE:
break; break;
case NFT_DYNSET_OP_UPDATE: case NFT_DYNSET_OP_UPDATE:
if (!(set->flags & NFT_SET_TIMEOUT)) if (!(set->flags & NFT_SET_TIMEOUT))
......
...@@ -26,8 +26,36 @@ ...@@ -26,8 +26,36 @@
#include <uapi/linux/netfilter_bridge.h> /* NF_BR_PRE_ROUTING */ #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 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, void nft_meta_get_eval(const struct nft_expr *expr,
struct nft_regs *regs, struct nft_regs *regs,
const struct nft_pktinfo *pkt) const struct nft_pktinfo *pkt)
...@@ -218,6 +246,15 @@ void nft_meta_get_eval(const struct nft_expr *expr, ...@@ -218,6 +246,15 @@ void nft_meta_get_eval(const struct nft_expr *expr,
goto err; goto err;
strncpy((char *)dest, out->rtnl_link_ops->kind, IFNAMSIZ); strncpy((char *)dest, out->rtnl_link_ops->kind, IFNAMSIZ);
break; 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: default:
WARN_ON(1); WARN_ON(1);
goto err; goto err;
...@@ -330,6 +367,15 @@ int nft_meta_get_init(const struct nft_ctx *ctx, ...@@ -330,6 +367,15 @@ int nft_meta_get_init(const struct nft_ctx *ctx,
len = sizeof(u8); len = sizeof(u8);
break; break;
#endif #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: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
#include <net/netfilter/nf_tables.h> #include <net/netfilter/nf_tables.h>
struct nft_quota { struct nft_quota {
u64 quota; atomic64_t quota;
unsigned long flags; unsigned long flags;
atomic64_t consumed; atomic64_t consumed;
}; };
...@@ -21,7 +21,8 @@ struct nft_quota { ...@@ -21,7 +21,8 @@ struct nft_quota {
static inline bool nft_overquota(struct nft_quota *priv, static inline bool nft_overquota(struct nft_quota *priv,
const struct sk_buff *skb) 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) 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[], ...@@ -89,7 +90,7 @@ static int nft_quota_do_init(const struct nlattr * const tb[],
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
priv->quota = quota; atomic64_set(&priv->quota, quota);
priv->flags = flags; priv->flags = flags;
atomic64_set(&priv->consumed, consumed); atomic64_set(&priv->consumed, consumed);
...@@ -105,10 +106,22 @@ static int nft_quota_obj_init(const struct nft_ctx *ctx, ...@@ -105,10 +106,22 @@ static int nft_quota_obj_init(const struct nft_ctx *ctx,
return nft_quota_do_init(tb, priv); 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, static int nft_quota_do_dump(struct sk_buff *skb, struct nft_quota *priv,
bool reset) bool reset)
{ {
u64 consumed, consumed_cap; u64 consumed, consumed_cap, quota;
u32 flags = priv->flags; u32 flags = priv->flags;
/* Since we inconditionally increment consumed quota for each packet /* 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, ...@@ -116,14 +129,15 @@ static int nft_quota_do_dump(struct sk_buff *skb, struct nft_quota *priv,
* userspace. * userspace.
*/ */
consumed = atomic64_read(&priv->consumed); consumed = atomic64_read(&priv->consumed);
if (consumed >= priv->quota) { quota = atomic64_read(&priv->quota);
consumed_cap = priv->quota; if (consumed >= quota) {
consumed_cap = quota;
flags |= NFT_QUOTA_F_DEPLETED; flags |= NFT_QUOTA_F_DEPLETED;
} else { } else {
consumed_cap = consumed; 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) || NFTA_QUOTA_PAD) ||
nla_put_be64(skb, NFTA_QUOTA_CONSUMED, cpu_to_be64(consumed_cap), nla_put_be64(skb, NFTA_QUOTA_CONSUMED, cpu_to_be64(consumed_cap),
NFTA_QUOTA_PAD) || NFTA_QUOTA_PAD) ||
...@@ -155,6 +169,7 @@ static const struct nft_object_ops nft_quota_obj_ops = { ...@@ -155,6 +169,7 @@ static const struct nft_object_ops nft_quota_obj_ops = {
.init = nft_quota_obj_init, .init = nft_quota_obj_init,
.eval = nft_quota_obj_eval, .eval = nft_quota_obj_eval,
.dump = nft_quota_obj_dump, .dump = nft_quota_obj_dump,
.update = nft_quota_obj_update,
}; };
static struct nft_object_type nft_quota_obj_type __read_mostly = { static struct nft_object_type nft_quota_obj_type __read_mostly = {
......
...@@ -234,6 +234,24 @@ static void nft_rhash_remove(const struct net *net, ...@@ -234,6 +234,24 @@ static void nft_rhash_remove(const struct net *net,
rhashtable_remove_fast(&priv->ht, &he->node, nft_rhash_params); 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, static void nft_rhash_walk(const struct nft_ctx *ctx, struct nft_set *set,
struct nft_set_iter *iter) struct nft_set_iter *iter)
{ {
...@@ -662,6 +680,7 @@ struct nft_set_type nft_set_rhash_type __read_mostly = { ...@@ -662,6 +680,7 @@ struct nft_set_type nft_set_rhash_type __read_mostly = {
.remove = nft_rhash_remove, .remove = nft_rhash_remove,
.lookup = nft_rhash_lookup, .lookup = nft_rhash_lookup,
.update = nft_rhash_update, .update = nft_rhash_update,
.delete = nft_rhash_delete,
.walk = nft_rhash_walk, .walk = nft_rhash_walk,
.get = nft_rhash_get, .get = nft_rhash_get,
}, },
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment