mirror of
https://github.com/rd-stuffs/msm-4.14.git
synced 2025-02-20 11:45:48 +08:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next
Pablo Neira Ayuso says: ==================== Netfilter/IPVS updates for net-next The following patchset contains Netfilter/IPVS updates for your net-next tree. A couple of new features for nf_tables, and unsorted cleanups and incremental updates for the Netfilter tree. More specifically, they are: 1) Allow to check for TCP option presence via nft_exthdr, patch from Phil Sutter. 2) Add symmetric hash support to nft_hash, from Laura Garcia Liebana. 3) Use pr_cont() in ebt_log, from Joe Perches. 4) Remove some dead code in arp_tables reported via static analysis tool, from Colin Ian King. 5) Consolidate nf_tables expression validation, from Liping Zhang. 6) Consolidate set lookup via nft_set_lookup(). 7) Remove unnecessary rcu read lock side in bridge netfilter, from Florian Westphal. 8) Remove unused variable in nf_reject_ipv4, from Tahee Yoo. 9) Pass nft_ctx struct to object initialization indirections, from Florian Westphal. 10) Add code to integrate conntrack helper into nf_tables, also from Florian. 11) Allow to check if interface index or name exists via NFTA_FIB_F_PRESENT, from Phil Sutter. 12) Simplify resolve_normal_ct(), from Florian. 13) Use per-limit spinlock in nft_limit and xt_limit, from Liping Zhang. 14) Use rwlock in nft_set_rbtree set, also from Liping Zhang. 15) One patch to remove a useless printk at netns init path in ipvs, and several patches to document IPVS knobs. 16) Use refcount_t for reference counter in the Netfilter/IPVS code, from Elena Reshetova. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
41e95736b3
@ -175,6 +175,14 @@ nat_icmp_send - BOOLEAN
|
|||||||
for VS/NAT when the load balancer receives packets from real
|
for VS/NAT when the load balancer receives packets from real
|
||||||
servers but the connection entries don't exist.
|
servers but the connection entries don't exist.
|
||||||
|
|
||||||
|
pmtu_disc - BOOLEAN
|
||||||
|
0 - disabled
|
||||||
|
not 0 - enabled (default)
|
||||||
|
|
||||||
|
By default, reject with FRAG_NEEDED all DF packets that exceed
|
||||||
|
the PMTU, irrespective of the forwarding method. For TUN method
|
||||||
|
the flag can be disabled to fragment such packets.
|
||||||
|
|
||||||
secure_tcp - INTEGER
|
secure_tcp - INTEGER
|
||||||
0 - disabled (default)
|
0 - disabled (default)
|
||||||
|
|
||||||
@ -185,15 +193,59 @@ secure_tcp - INTEGER
|
|||||||
The value definition is the same as that of drop_entry and
|
The value definition is the same as that of drop_entry and
|
||||||
drop_packet.
|
drop_packet.
|
||||||
|
|
||||||
sync_threshold - INTEGER
|
sync_threshold - vector of 2 INTEGERs: sync_threshold, sync_period
|
||||||
default 3
|
default 3 50
|
||||||
|
|
||||||
It sets synchronization threshold, which is the minimum number
|
It sets synchronization threshold, which is the minimum number
|
||||||
of incoming packets that a connection needs to receive before
|
of incoming packets that a connection needs to receive before
|
||||||
the connection will be synchronized. A connection will be
|
the connection will be synchronized. A connection will be
|
||||||
synchronized, every time the number of its incoming packets
|
synchronized, every time the number of its incoming packets
|
||||||
modulus 50 equals the threshold. The range of the threshold is
|
modulus sync_period equals the threshold. The range of the
|
||||||
from 0 to 49.
|
threshold is from 0 to sync_period.
|
||||||
|
|
||||||
|
When sync_period and sync_refresh_period are 0, send sync only
|
||||||
|
for state changes or only once when pkts matches sync_threshold
|
||||||
|
|
||||||
|
sync_refresh_period - UNSIGNED INTEGER
|
||||||
|
default 0
|
||||||
|
|
||||||
|
In seconds, difference in reported connection timer that triggers
|
||||||
|
new sync message. It can be used to avoid sync messages for the
|
||||||
|
specified period (or half of the connection timeout if it is lower)
|
||||||
|
if connection state is not changed since last sync.
|
||||||
|
|
||||||
|
This is useful for normal connections with high traffic to reduce
|
||||||
|
sync rate. Additionally, retry sync_retries times with period of
|
||||||
|
sync_refresh_period/8.
|
||||||
|
|
||||||
|
sync_retries - INTEGER
|
||||||
|
default 0
|
||||||
|
|
||||||
|
Defines sync retries with period of sync_refresh_period/8. Useful
|
||||||
|
to protect against loss of sync messages. The range of the
|
||||||
|
sync_retries is from 0 to 3.
|
||||||
|
|
||||||
|
sync_qlen_max - UNSIGNED LONG
|
||||||
|
|
||||||
|
Hard limit for queued sync messages that are not sent yet. It
|
||||||
|
defaults to 1/32 of the memory pages but actually represents
|
||||||
|
number of messages. It will protect us from allocating large
|
||||||
|
parts of memory when the sending rate is lower than the queuing
|
||||||
|
rate.
|
||||||
|
|
||||||
|
sync_sock_size - INTEGER
|
||||||
|
default 0
|
||||||
|
|
||||||
|
Configuration of SNDBUF (master) or RCVBUF (slave) socket limit.
|
||||||
|
Default value is 0 (preserve system defaults).
|
||||||
|
|
||||||
|
sync_ports - INTEGER
|
||||||
|
default 1
|
||||||
|
|
||||||
|
The number of threads that master and backup servers can use for
|
||||||
|
sync traffic. Every thread will use single UDP port, thread 0 will
|
||||||
|
use the default port 8848 while last thread will use port
|
||||||
|
8848+sync_ports-1.
|
||||||
|
|
||||||
snat_reroute - BOOLEAN
|
snat_reroute - BOOLEAN
|
||||||
0 - disabled
|
0 - disabled
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
#include <linux/list.h> /* for struct list_head */
|
#include <linux/list.h> /* for struct list_head */
|
||||||
#include <linux/spinlock.h> /* for struct rwlock_t */
|
#include <linux/spinlock.h> /* for struct rwlock_t */
|
||||||
#include <linux/atomic.h> /* for struct atomic_t */
|
#include <linux/atomic.h> /* for struct atomic_t */
|
||||||
|
#include <linux/refcount.h> /* for struct refcount_t */
|
||||||
|
|
||||||
#include <linux/compiler.h>
|
#include <linux/compiler.h>
|
||||||
#include <linux/timer.h>
|
#include <linux/timer.h>
|
||||||
#include <linux/bug.h>
|
#include <linux/bug.h>
|
||||||
@ -525,7 +527,7 @@ struct ip_vs_conn {
|
|||||||
struct netns_ipvs *ipvs;
|
struct netns_ipvs *ipvs;
|
||||||
|
|
||||||
/* counter and timer */
|
/* counter and timer */
|
||||||
atomic_t refcnt; /* reference count */
|
refcount_t refcnt; /* reference count */
|
||||||
struct timer_list timer; /* Expiration timer */
|
struct timer_list timer; /* Expiration timer */
|
||||||
volatile unsigned long timeout; /* timeout */
|
volatile unsigned long timeout; /* timeout */
|
||||||
|
|
||||||
@ -667,7 +669,7 @@ struct ip_vs_dest {
|
|||||||
atomic_t conn_flags; /* flags to copy to conn */
|
atomic_t conn_flags; /* flags to copy to conn */
|
||||||
atomic_t weight; /* server weight */
|
atomic_t weight; /* server weight */
|
||||||
|
|
||||||
atomic_t refcnt; /* reference counter */
|
refcount_t refcnt; /* reference counter */
|
||||||
struct ip_vs_stats stats; /* statistics */
|
struct ip_vs_stats stats; /* statistics */
|
||||||
unsigned long idle_start; /* start time, jiffies */
|
unsigned long idle_start; /* start time, jiffies */
|
||||||
|
|
||||||
@ -1211,14 +1213,14 @@ struct ip_vs_conn * ip_vs_conn_out_get_proto(struct netns_ipvs *ipvs, int af,
|
|||||||
*/
|
*/
|
||||||
static inline bool __ip_vs_conn_get(struct ip_vs_conn *cp)
|
static inline bool __ip_vs_conn_get(struct ip_vs_conn *cp)
|
||||||
{
|
{
|
||||||
return atomic_inc_not_zero(&cp->refcnt);
|
return refcount_inc_not_zero(&cp->refcnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* put back the conn without restarting its timer */
|
/* put back the conn without restarting its timer */
|
||||||
static inline void __ip_vs_conn_put(struct ip_vs_conn *cp)
|
static inline void __ip_vs_conn_put(struct ip_vs_conn *cp)
|
||||||
{
|
{
|
||||||
smp_mb__before_atomic();
|
smp_mb__before_atomic();
|
||||||
atomic_dec(&cp->refcnt);
|
refcount_dec(&cp->refcnt);
|
||||||
}
|
}
|
||||||
void ip_vs_conn_put(struct ip_vs_conn *cp);
|
void ip_vs_conn_put(struct ip_vs_conn *cp);
|
||||||
void ip_vs_conn_fill_cport(struct ip_vs_conn *cp, __be16 cport);
|
void ip_vs_conn_fill_cport(struct ip_vs_conn *cp, __be16 cport);
|
||||||
@ -1410,18 +1412,18 @@ void ip_vs_try_bind_dest(struct ip_vs_conn *cp);
|
|||||||
|
|
||||||
static inline void ip_vs_dest_hold(struct ip_vs_dest *dest)
|
static inline void ip_vs_dest_hold(struct ip_vs_dest *dest)
|
||||||
{
|
{
|
||||||
atomic_inc(&dest->refcnt);
|
refcount_inc(&dest->refcnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void ip_vs_dest_put(struct ip_vs_dest *dest)
|
static inline void ip_vs_dest_put(struct ip_vs_dest *dest)
|
||||||
{
|
{
|
||||||
smp_mb__before_atomic();
|
smp_mb__before_atomic();
|
||||||
atomic_dec(&dest->refcnt);
|
refcount_dec(&dest->refcnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void ip_vs_dest_put_and_free(struct ip_vs_dest *dest)
|
static inline void ip_vs_dest_put_and_free(struct ip_vs_dest *dest)
|
||||||
{
|
{
|
||||||
if (atomic_dec_and_test(&dest->refcnt))
|
if (refcount_dec_and_test(&dest->refcnt))
|
||||||
kfree(dest);
|
kfree(dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
#ifndef _NF_CONNTRACK_EXPECT_H
|
#ifndef _NF_CONNTRACK_EXPECT_H
|
||||||
#define _NF_CONNTRACK_EXPECT_H
|
#define _NF_CONNTRACK_EXPECT_H
|
||||||
|
|
||||||
|
#include <linux/refcount.h>
|
||||||
|
|
||||||
#include <net/netfilter/nf_conntrack.h>
|
#include <net/netfilter/nf_conntrack.h>
|
||||||
#include <net/netfilter/nf_conntrack_zones.h>
|
#include <net/netfilter/nf_conntrack_zones.h>
|
||||||
|
|
||||||
@ -37,7 +39,7 @@ struct nf_conntrack_expect {
|
|||||||
struct timer_list timeout;
|
struct timer_list timeout;
|
||||||
|
|
||||||
/* Usage count. */
|
/* Usage count. */
|
||||||
atomic_t use;
|
refcount_t use;
|
||||||
|
|
||||||
/* Flags */
|
/* Flags */
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <net/net_namespace.h>
|
#include <net/net_namespace.h>
|
||||||
#include <linux/netfilter/nf_conntrack_common.h>
|
#include <linux/netfilter/nf_conntrack_common.h>
|
||||||
#include <linux/netfilter/nf_conntrack_tuple_common.h>
|
#include <linux/netfilter/nf_conntrack_tuple_common.h>
|
||||||
|
#include <linux/refcount.h>
|
||||||
#include <net/netfilter/nf_conntrack.h>
|
#include <net/netfilter/nf_conntrack.h>
|
||||||
#include <net/netfilter/nf_conntrack_extend.h>
|
#include <net/netfilter/nf_conntrack_extend.h>
|
||||||
|
|
||||||
@ -12,7 +13,7 @@
|
|||||||
struct ctnl_timeout {
|
struct ctnl_timeout {
|
||||||
struct list_head head;
|
struct list_head head;
|
||||||
struct rcu_head rcu_head;
|
struct rcu_head rcu_head;
|
||||||
atomic_t refcnt;
|
refcount_t refcnt;
|
||||||
char name[CTNL_TIMEOUT_NAME_MAX];
|
char name[CTNL_TIMEOUT_NAME_MAX];
|
||||||
__u16 l3num;
|
__u16 l3num;
|
||||||
struct nf_conntrack_l4proto *l4proto;
|
struct nf_conntrack_l4proto *l4proto;
|
||||||
|
@ -385,10 +385,11 @@ static inline struct nft_set *nft_set_container_of(const void *priv)
|
|||||||
return (void *)priv - offsetof(struct nft_set, data);
|
return (void *)priv - offsetof(struct nft_set, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct nft_set *nf_tables_set_lookup(const struct nft_table *table,
|
struct nft_set *nft_set_lookup(const struct net *net,
|
||||||
const struct nlattr *nla, u8 genmask);
|
const struct nft_table *table,
|
||||||
struct nft_set *nf_tables_set_lookup_byid(const struct net *net,
|
const struct nlattr *nla_set_name,
|
||||||
const struct nlattr *nla, u8 genmask);
|
const struct nlattr *nla_set_id,
|
||||||
|
u8 genmask);
|
||||||
|
|
||||||
static inline unsigned long nft_set_gc_interval(const struct nft_set *set)
|
static inline unsigned long nft_set_gc_interval(const struct nft_set *set)
|
||||||
{
|
{
|
||||||
@ -1016,7 +1017,8 @@ struct nft_object_type {
|
|||||||
unsigned int maxattr;
|
unsigned int maxattr;
|
||||||
struct module *owner;
|
struct module *owner;
|
||||||
const struct nla_policy *policy;
|
const struct nla_policy *policy;
|
||||||
int (*init)(const struct nlattr * const tb[],
|
int (*init)(const struct nft_ctx *ctx,
|
||||||
|
const struct nlattr *const tb[],
|
||||||
struct nft_object *obj);
|
struct nft_object *obj);
|
||||||
void (*destroy)(struct nft_object *obj);
|
void (*destroy)(struct nft_object *obj);
|
||||||
int (*dump)(struct sk_buff *skb,
|
int (*dump)(struct sk_buff *skb,
|
||||||
|
@ -32,6 +32,6 @@ void nft_fib6_eval_type(const struct nft_expr *expr, struct nft_regs *regs,
|
|||||||
void nft_fib6_eval(const struct nft_expr *expr, struct nft_regs *regs,
|
void nft_fib6_eval(const struct nft_expr *expr, struct nft_regs *regs,
|
||||||
const struct nft_pktinfo *pkt);
|
const struct nft_pktinfo *pkt);
|
||||||
|
|
||||||
void nft_fib_store_result(void *reg, enum nft_fib_result r,
|
void nft_fib_store_result(void *reg, const struct nft_fib *priv,
|
||||||
const struct nft_pktinfo *pkt, int index);
|
const struct nft_pktinfo *pkt, int index);
|
||||||
#endif
|
#endif
|
||||||
|
@ -815,6 +815,17 @@ enum nft_rt_keys {
|
|||||||
NFT_RT_NEXTHOP6,
|
NFT_RT_NEXTHOP6,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* enum nft_hash_types - nf_tables hash expression types
|
||||||
|
*
|
||||||
|
* @NFT_HASH_JENKINS: Jenkins Hash
|
||||||
|
* @NFT_HASH_SYM: Symmetric Hash
|
||||||
|
*/
|
||||||
|
enum nft_hash_types {
|
||||||
|
NFT_HASH_JENKINS,
|
||||||
|
NFT_HASH_SYM,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* enum nft_hash_attributes - nf_tables hash expression netlink attributes
|
* enum nft_hash_attributes - nf_tables hash expression netlink attributes
|
||||||
*
|
*
|
||||||
@ -824,6 +835,7 @@ enum nft_rt_keys {
|
|||||||
* @NFTA_HASH_MODULUS: modulus value (NLA_U32)
|
* @NFTA_HASH_MODULUS: modulus value (NLA_U32)
|
||||||
* @NFTA_HASH_SEED: seed value (NLA_U32)
|
* @NFTA_HASH_SEED: seed value (NLA_U32)
|
||||||
* @NFTA_HASH_OFFSET: add this offset value to hash result (NLA_U32)
|
* @NFTA_HASH_OFFSET: add this offset value to hash result (NLA_U32)
|
||||||
|
* @NFTA_HASH_TYPE: hash operation (NLA_U32: nft_hash_types)
|
||||||
*/
|
*/
|
||||||
enum nft_hash_attributes {
|
enum nft_hash_attributes {
|
||||||
NFTA_HASH_UNSPEC,
|
NFTA_HASH_UNSPEC,
|
||||||
@ -833,6 +845,7 @@ enum nft_hash_attributes {
|
|||||||
NFTA_HASH_MODULUS,
|
NFTA_HASH_MODULUS,
|
||||||
NFTA_HASH_SEED,
|
NFTA_HASH_SEED,
|
||||||
NFTA_HASH_OFFSET,
|
NFTA_HASH_OFFSET,
|
||||||
|
NFTA_HASH_TYPE,
|
||||||
__NFTA_HASH_MAX,
|
__NFTA_HASH_MAX,
|
||||||
};
|
};
|
||||||
#define NFTA_HASH_MAX (__NFTA_HASH_MAX - 1)
|
#define NFTA_HASH_MAX (__NFTA_HASH_MAX - 1)
|
||||||
@ -1244,12 +1257,23 @@ enum nft_fib_flags {
|
|||||||
NFTA_FIB_F_MARK = 1 << 2, /* use skb->mark */
|
NFTA_FIB_F_MARK = 1 << 2, /* use skb->mark */
|
||||||
NFTA_FIB_F_IIF = 1 << 3, /* restrict to iif */
|
NFTA_FIB_F_IIF = 1 << 3, /* restrict to iif */
|
||||||
NFTA_FIB_F_OIF = 1 << 4, /* restrict to oif */
|
NFTA_FIB_F_OIF = 1 << 4, /* restrict to oif */
|
||||||
|
NFTA_FIB_F_PRESENT = 1 << 5, /* check existence only */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum nft_ct_helper_attributes {
|
||||||
|
NFTA_CT_HELPER_UNSPEC,
|
||||||
|
NFTA_CT_HELPER_NAME,
|
||||||
|
NFTA_CT_HELPER_L3PROTO,
|
||||||
|
NFTA_CT_HELPER_L4PROTO,
|
||||||
|
__NFTA_CT_HELPER_MAX,
|
||||||
|
};
|
||||||
|
#define NFTA_CT_HELPER_MAX (__NFTA_CT_HELPER_MAX - 1)
|
||||||
|
|
||||||
#define NFT_OBJECT_UNSPEC 0
|
#define NFT_OBJECT_UNSPEC 0
|
||||||
#define NFT_OBJECT_COUNTER 1
|
#define NFT_OBJECT_COUNTER 1
|
||||||
#define NFT_OBJECT_QUOTA 2
|
#define NFT_OBJECT_QUOTA 2
|
||||||
#define __NFT_OBJECT_MAX 3
|
#define NFT_OBJECT_CT_HELPER 3
|
||||||
|
#define __NFT_OBJECT_MAX 4
|
||||||
#define NFT_OBJECT_MAX (__NFT_OBJECT_MAX - 1)
|
#define NFT_OBJECT_MAX (__NFT_OBJECT_MAX - 1)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -995,13 +995,10 @@ int br_nf_hook_thresh(unsigned int hook, struct net *net,
|
|||||||
if (!elem)
|
if (!elem)
|
||||||
return okfn(net, sk, skb);
|
return okfn(net, sk, skb);
|
||||||
|
|
||||||
/* We may already have this, but read-locks nest anyway */
|
|
||||||
rcu_read_lock();
|
|
||||||
nf_hook_state_init(&state, hook, NFPROTO_BRIDGE, indev, outdev,
|
nf_hook_state_init(&state, hook, NFPROTO_BRIDGE, indev, outdev,
|
||||||
sk, net, okfn);
|
sk, net, okfn);
|
||||||
|
|
||||||
ret = nf_hook_slow(skb, &state, elem);
|
ret = nf_hook_slow(skb, &state, elem);
|
||||||
rcu_read_unlock();
|
|
||||||
if (ret == 1)
|
if (ret == 1)
|
||||||
ret = okfn(net, sk, skb);
|
ret = okfn(net, sk, skb);
|
||||||
|
|
||||||
|
@ -62,10 +62,10 @@ print_ports(const struct sk_buff *skb, uint8_t protocol, int offset)
|
|||||||
pptr = skb_header_pointer(skb, offset,
|
pptr = skb_header_pointer(skb, offset,
|
||||||
sizeof(_ports), &_ports);
|
sizeof(_ports), &_ports);
|
||||||
if (pptr == NULL) {
|
if (pptr == NULL) {
|
||||||
printk(" INCOMPLETE TCP/UDP header");
|
pr_cont(" INCOMPLETE TCP/UDP header");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
printk(" SPT=%u DPT=%u", ntohs(pptr->src), ntohs(pptr->dst));
|
pr_cont(" SPT=%u DPT=%u", ntohs(pptr->src), ntohs(pptr->dst));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,11 +100,11 @@ ebt_log_packet(struct net *net, u_int8_t pf, unsigned int hooknum,
|
|||||||
|
|
||||||
ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
|
ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
|
||||||
if (ih == NULL) {
|
if (ih == NULL) {
|
||||||
printk(" INCOMPLETE IP header");
|
pr_cont(" INCOMPLETE IP header");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
printk(" IP SRC=%pI4 IP DST=%pI4, IP tos=0x%02X, IP proto=%d",
|
pr_cont(" IP SRC=%pI4 IP DST=%pI4, IP tos=0x%02X, IP proto=%d",
|
||||||
&ih->saddr, &ih->daddr, ih->tos, ih->protocol);
|
&ih->saddr, &ih->daddr, ih->tos, ih->protocol);
|
||||||
print_ports(skb, ih->protocol, ih->ihl*4);
|
print_ports(skb, ih->protocol, ih->ihl*4);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -120,11 +120,11 @@ ebt_log_packet(struct net *net, u_int8_t pf, unsigned int hooknum,
|
|||||||
|
|
||||||
ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
|
ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
|
||||||
if (ih == NULL) {
|
if (ih == NULL) {
|
||||||
printk(" INCOMPLETE IPv6 header");
|
pr_cont(" INCOMPLETE IPv6 header");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
printk(" IPv6 SRC=%pI6 IPv6 DST=%pI6, IPv6 priority=0x%01X, Next Header=%d",
|
pr_cont(" IPv6 SRC=%pI6 IPv6 DST=%pI6, IPv6 priority=0x%01X, Next Header=%d",
|
||||||
&ih->saddr, &ih->daddr, ih->priority, ih->nexthdr);
|
&ih->saddr, &ih->daddr, ih->priority, ih->nexthdr);
|
||||||
nexthdr = ih->nexthdr;
|
nexthdr = ih->nexthdr;
|
||||||
offset_ph = ipv6_skip_exthdr(skb, sizeof(_iph), &nexthdr, &frag_off);
|
offset_ph = ipv6_skip_exthdr(skb, sizeof(_iph), &nexthdr, &frag_off);
|
||||||
if (offset_ph == -1)
|
if (offset_ph == -1)
|
||||||
@ -142,12 +142,12 @@ ebt_log_packet(struct net *net, u_int8_t pf, unsigned int hooknum,
|
|||||||
|
|
||||||
ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
|
ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
|
||||||
if (ah == NULL) {
|
if (ah == NULL) {
|
||||||
printk(" INCOMPLETE ARP header");
|
pr_cont(" INCOMPLETE ARP header");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
printk(" ARP HTYPE=%d, PTYPE=0x%04x, OPCODE=%d",
|
pr_cont(" ARP HTYPE=%d, PTYPE=0x%04x, OPCODE=%d",
|
||||||
ntohs(ah->ar_hrd), ntohs(ah->ar_pro),
|
ntohs(ah->ar_hrd), ntohs(ah->ar_pro),
|
||||||
ntohs(ah->ar_op));
|
ntohs(ah->ar_op));
|
||||||
|
|
||||||
/* If it's for Ethernet and the lengths are OK,
|
/* If it's for Ethernet and the lengths are OK,
|
||||||
* then log the ARP payload
|
* then log the ARP payload
|
||||||
@ -161,17 +161,17 @@ ebt_log_packet(struct net *net, u_int8_t pf, unsigned int hooknum,
|
|||||||
ap = skb_header_pointer(skb, sizeof(_arph),
|
ap = skb_header_pointer(skb, sizeof(_arph),
|
||||||
sizeof(_arpp), &_arpp);
|
sizeof(_arpp), &_arpp);
|
||||||
if (ap == NULL) {
|
if (ap == NULL) {
|
||||||
printk(" INCOMPLETE ARP payload");
|
pr_cont(" INCOMPLETE ARP payload");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
printk(" ARP MAC SRC=%pM ARP IP SRC=%pI4 ARP MAC DST=%pM ARP IP DST=%pI4",
|
pr_cont(" ARP MAC SRC=%pM ARP IP SRC=%pI4 ARP MAC DST=%pM ARP IP DST=%pI4",
|
||||||
ap->mac_src, ap->ip_src, ap->mac_dst, ap->ip_dst);
|
ap->mac_src, ap->ip_src,
|
||||||
|
ap->mac_dst, ap->ip_dst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
printk("\n");
|
pr_cont("\n");
|
||||||
spin_unlock_bh(&ebt_log_lock);
|
spin_unlock_bh(&ebt_log_lock);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int
|
static unsigned int
|
||||||
|
@ -375,11 +375,7 @@ static int nft_reject_bridge_init(const struct nft_ctx *ctx,
|
|||||||
const struct nlattr * const tb[])
|
const struct nlattr * const tb[])
|
||||||
{
|
{
|
||||||
struct nft_reject *priv = nft_expr_priv(expr);
|
struct nft_reject *priv = nft_expr_priv(expr);
|
||||||
int icmp_code, err;
|
int icmp_code;
|
||||||
|
|
||||||
err = nft_reject_bridge_validate(ctx, expr, NULL);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
if (tb[NFTA_REJECT_TYPE] == NULL)
|
if (tb[NFTA_REJECT_TYPE] == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -562,8 +562,6 @@ static int translate_table(struct xt_table_info *newinfo, void *entry0,
|
|||||||
XT_ERROR_TARGET) == 0)
|
XT_ERROR_TARGET) == 0)
|
||||||
++newinfo->stacksize;
|
++newinfo->stacksize;
|
||||||
}
|
}
|
||||||
if (ret != 0)
|
|
||||||
goto out_free;
|
|
||||||
|
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
if (i != repl->num_entries)
|
if (i != repl->num_entries)
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include <linux/icmp.h>
|
#include <linux/icmp.h>
|
||||||
#include <linux/if_arp.h>
|
#include <linux/if_arp.h>
|
||||||
#include <linux/seq_file.h>
|
#include <linux/seq_file.h>
|
||||||
|
#include <linux/refcount.h>
|
||||||
#include <linux/netfilter_arp.h>
|
#include <linux/netfilter_arp.h>
|
||||||
#include <linux/netfilter/x_tables.h>
|
#include <linux/netfilter/x_tables.h>
|
||||||
#include <linux/netfilter_ipv4/ip_tables.h>
|
#include <linux/netfilter_ipv4/ip_tables.h>
|
||||||
@ -40,8 +41,8 @@ MODULE_DESCRIPTION("Xtables: CLUSTERIP target");
|
|||||||
|
|
||||||
struct clusterip_config {
|
struct clusterip_config {
|
||||||
struct list_head list; /* list of all configs */
|
struct list_head list; /* list of all configs */
|
||||||
atomic_t refcount; /* reference count */
|
refcount_t refcount; /* reference count */
|
||||||
atomic_t entries; /* number of entries/rules
|
refcount_t entries; /* number of entries/rules
|
||||||
* referencing us */
|
* referencing us */
|
||||||
|
|
||||||
__be32 clusterip; /* the IP address */
|
__be32 clusterip; /* the IP address */
|
||||||
@ -77,7 +78,7 @@ struct clusterip_net {
|
|||||||
static inline void
|
static inline void
|
||||||
clusterip_config_get(struct clusterip_config *c)
|
clusterip_config_get(struct clusterip_config *c)
|
||||||
{
|
{
|
||||||
atomic_inc(&c->refcount);
|
refcount_inc(&c->refcount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -89,7 +90,7 @@ static void clusterip_config_rcu_free(struct rcu_head *head)
|
|||||||
static inline void
|
static inline void
|
||||||
clusterip_config_put(struct clusterip_config *c)
|
clusterip_config_put(struct clusterip_config *c)
|
||||||
{
|
{
|
||||||
if (atomic_dec_and_test(&c->refcount))
|
if (refcount_dec_and_test(&c->refcount))
|
||||||
call_rcu_bh(&c->rcu, clusterip_config_rcu_free);
|
call_rcu_bh(&c->rcu, clusterip_config_rcu_free);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,7 +104,7 @@ clusterip_config_entry_put(struct clusterip_config *c)
|
|||||||
struct clusterip_net *cn = net_generic(net, clusterip_net_id);
|
struct clusterip_net *cn = net_generic(net, clusterip_net_id);
|
||||||
|
|
||||||
local_bh_disable();
|
local_bh_disable();
|
||||||
if (atomic_dec_and_lock(&c->entries, &cn->lock)) {
|
if (refcount_dec_and_lock(&c->entries, &cn->lock)) {
|
||||||
list_del_rcu(&c->list);
|
list_del_rcu(&c->list);
|
||||||
spin_unlock(&cn->lock);
|
spin_unlock(&cn->lock);
|
||||||
local_bh_enable();
|
local_bh_enable();
|
||||||
@ -149,10 +150,10 @@ clusterip_config_find_get(struct net *net, __be32 clusterip, int entry)
|
|||||||
c = NULL;
|
c = NULL;
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
if (unlikely(!atomic_inc_not_zero(&c->refcount)))
|
if (unlikely(!refcount_inc_not_zero(&c->refcount)))
|
||||||
c = NULL;
|
c = NULL;
|
||||||
else if (entry)
|
else if (entry)
|
||||||
atomic_inc(&c->entries);
|
refcount_inc(&c->entries);
|
||||||
}
|
}
|
||||||
rcu_read_unlock_bh();
|
rcu_read_unlock_bh();
|
||||||
|
|
||||||
@ -188,8 +189,8 @@ clusterip_config_init(const struct ipt_clusterip_tgt_info *i, __be32 ip,
|
|||||||
clusterip_config_init_nodelist(c, i);
|
clusterip_config_init_nodelist(c, i);
|
||||||
c->hash_mode = i->hash_mode;
|
c->hash_mode = i->hash_mode;
|
||||||
c->hash_initval = i->hash_initval;
|
c->hash_initval = i->hash_initval;
|
||||||
atomic_set(&c->refcount, 1);
|
refcount_set(&c->refcount, 1);
|
||||||
atomic_set(&c->entries, 1);
|
refcount_set(&c->entries, 1);
|
||||||
|
|
||||||
spin_lock_bh(&cn->lock);
|
spin_lock_bh(&cn->lock);
|
||||||
if (__clusterip_config_find(net, ip)) {
|
if (__clusterip_config_find(net, ip)) {
|
||||||
|
@ -998,18 +998,6 @@ err_id_free:
|
|||||||
*
|
*
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
static void hex_dump(const unsigned char *buf, size_t len)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
for (i = 0; i < len; i++) {
|
|
||||||
if (i && !(i % 16))
|
|
||||||
printk("\n");
|
|
||||||
printk("%02x ", *(buf + i));
|
|
||||||
}
|
|
||||||
printk("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse and mangle SNMP message according to mapping.
|
* Parse and mangle SNMP message according to mapping.
|
||||||
* (And this is the fucking 'basic' method).
|
* (And this is the fucking 'basic' method).
|
||||||
@ -1026,7 +1014,8 @@ static int snmp_parse_mangle(unsigned char *msg,
|
|||||||
struct snmp_object *obj;
|
struct snmp_object *obj;
|
||||||
|
|
||||||
if (debug > 1)
|
if (debug > 1)
|
||||||
hex_dump(msg, len);
|
print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_NONE, 16, 1,
|
||||||
|
msg, len, 0);
|
||||||
|
|
||||||
asn1_open(&ctx, msg, len);
|
asn1_open(&ctx, msg, len);
|
||||||
|
|
||||||
|
@ -104,7 +104,6 @@ EXPORT_SYMBOL_GPL(nf_reject_ip_tcphdr_put);
|
|||||||
void nf_send_reset(struct net *net, struct sk_buff *oldskb, int hook)
|
void nf_send_reset(struct net *net, struct sk_buff *oldskb, int hook)
|
||||||
{
|
{
|
||||||
struct sk_buff *nskb;
|
struct sk_buff *nskb;
|
||||||
const struct iphdr *oiph;
|
|
||||||
struct iphdr *niph;
|
struct iphdr *niph;
|
||||||
const struct tcphdr *oth;
|
const struct tcphdr *oth;
|
||||||
struct tcphdr _oth;
|
struct tcphdr _oth;
|
||||||
@ -116,8 +115,6 @@ void nf_send_reset(struct net *net, struct sk_buff *oldskb, int hook)
|
|||||||
if (skb_rtable(oldskb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
|
if (skb_rtable(oldskb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
oiph = ip_hdr(oldskb);
|
|
||||||
|
|
||||||
nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) +
|
nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) +
|
||||||
LL_MAX_HEADER, GFP_ATOMIC);
|
LL_MAX_HEADER, GFP_ATOMIC);
|
||||||
if (!nskb)
|
if (!nskb)
|
||||||
|
@ -90,7 +90,7 @@ void nft_fib4_eval(const struct nft_expr *expr, struct nft_regs *regs,
|
|||||||
|
|
||||||
if (nft_hook(pkt) == NF_INET_PRE_ROUTING &&
|
if (nft_hook(pkt) == NF_INET_PRE_ROUTING &&
|
||||||
nft_fib_is_loopback(pkt->skb, nft_in(pkt))) {
|
nft_fib_is_loopback(pkt->skb, nft_in(pkt))) {
|
||||||
nft_fib_store_result(dest, priv->result, pkt,
|
nft_fib_store_result(dest, priv, pkt,
|
||||||
nft_in(pkt)->ifindex);
|
nft_in(pkt)->ifindex);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -99,7 +99,7 @@ void nft_fib4_eval(const struct nft_expr *expr, struct nft_regs *regs,
|
|||||||
if (ipv4_is_zeronet(iph->saddr)) {
|
if (ipv4_is_zeronet(iph->saddr)) {
|
||||||
if (ipv4_is_lbcast(iph->daddr) ||
|
if (ipv4_is_lbcast(iph->daddr) ||
|
||||||
ipv4_is_local_multicast(iph->daddr)) {
|
ipv4_is_local_multicast(iph->daddr)) {
|
||||||
nft_fib_store_result(dest, priv->result, pkt,
|
nft_fib_store_result(dest, priv, pkt,
|
||||||
get_ifindex(pkt->skb->dev));
|
get_ifindex(pkt->skb->dev));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -159,7 +159,7 @@ void nft_fib6_eval(const struct nft_expr *expr, struct nft_regs *regs,
|
|||||||
|
|
||||||
if (nft_hook(pkt) == NF_INET_PRE_ROUTING &&
|
if (nft_hook(pkt) == NF_INET_PRE_ROUTING &&
|
||||||
nft_fib_is_loopback(pkt->skb, nft_in(pkt))) {
|
nft_fib_is_loopback(pkt->skb, nft_in(pkt))) {
|
||||||
nft_fib_store_result(dest, priv->result, pkt,
|
nft_fib_store_result(dest, priv, pkt,
|
||||||
nft_in(pkt)->ifindex);
|
nft_in(pkt)->ifindex);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -181,7 +181,7 @@ static inline int ip_vs_conn_hash(struct ip_vs_conn *cp)
|
|||||||
|
|
||||||
if (!(cp->flags & IP_VS_CONN_F_HASHED)) {
|
if (!(cp->flags & IP_VS_CONN_F_HASHED)) {
|
||||||
cp->flags |= IP_VS_CONN_F_HASHED;
|
cp->flags |= IP_VS_CONN_F_HASHED;
|
||||||
atomic_inc(&cp->refcnt);
|
refcount_inc(&cp->refcnt);
|
||||||
hlist_add_head_rcu(&cp->c_list, &ip_vs_conn_tab[hash]);
|
hlist_add_head_rcu(&cp->c_list, &ip_vs_conn_tab[hash]);
|
||||||
ret = 1;
|
ret = 1;
|
||||||
} else {
|
} else {
|
||||||
@ -215,7 +215,7 @@ static inline int ip_vs_conn_unhash(struct ip_vs_conn *cp)
|
|||||||
if (cp->flags & IP_VS_CONN_F_HASHED) {
|
if (cp->flags & IP_VS_CONN_F_HASHED) {
|
||||||
hlist_del_rcu(&cp->c_list);
|
hlist_del_rcu(&cp->c_list);
|
||||||
cp->flags &= ~IP_VS_CONN_F_HASHED;
|
cp->flags &= ~IP_VS_CONN_F_HASHED;
|
||||||
atomic_dec(&cp->refcnt);
|
refcount_dec(&cp->refcnt);
|
||||||
ret = 1;
|
ret = 1;
|
||||||
} else
|
} else
|
||||||
ret = 0;
|
ret = 0;
|
||||||
@ -242,13 +242,13 @@ static inline bool ip_vs_conn_unlink(struct ip_vs_conn *cp)
|
|||||||
if (cp->flags & IP_VS_CONN_F_HASHED) {
|
if (cp->flags & IP_VS_CONN_F_HASHED) {
|
||||||
ret = false;
|
ret = false;
|
||||||
/* Decrease refcnt and unlink conn only if we are last user */
|
/* Decrease refcnt and unlink conn only if we are last user */
|
||||||
if (atomic_cmpxchg(&cp->refcnt, 1, 0) == 1) {
|
if (refcount_dec_if_one(&cp->refcnt)) {
|
||||||
hlist_del_rcu(&cp->c_list);
|
hlist_del_rcu(&cp->c_list);
|
||||||
cp->flags &= ~IP_VS_CONN_F_HASHED;
|
cp->flags &= ~IP_VS_CONN_F_HASHED;
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
ret = atomic_read(&cp->refcnt) ? false : true;
|
ret = refcount_read(&cp->refcnt) ? false : true;
|
||||||
|
|
||||||
spin_unlock(&cp->lock);
|
spin_unlock(&cp->lock);
|
||||||
ct_write_unlock_bh(hash);
|
ct_write_unlock_bh(hash);
|
||||||
@ -475,7 +475,7 @@ static void __ip_vs_conn_put_timer(struct ip_vs_conn *cp)
|
|||||||
void ip_vs_conn_put(struct ip_vs_conn *cp)
|
void ip_vs_conn_put(struct ip_vs_conn *cp)
|
||||||
{
|
{
|
||||||
if ((cp->flags & IP_VS_CONN_F_ONE_PACKET) &&
|
if ((cp->flags & IP_VS_CONN_F_ONE_PACKET) &&
|
||||||
(atomic_read(&cp->refcnt) == 1) &&
|
(refcount_read(&cp->refcnt) == 1) &&
|
||||||
!timer_pending(&cp->timer))
|
!timer_pending(&cp->timer))
|
||||||
/* expire connection immediately */
|
/* expire connection immediately */
|
||||||
__ip_vs_conn_put_notimer(cp);
|
__ip_vs_conn_put_notimer(cp);
|
||||||
@ -617,8 +617,8 @@ ip_vs_bind_dest(struct ip_vs_conn *cp, struct ip_vs_dest *dest)
|
|||||||
IP_VS_DBG_ADDR(cp->af, &cp->vaddr), ntohs(cp->vport),
|
IP_VS_DBG_ADDR(cp->af, &cp->vaddr), ntohs(cp->vport),
|
||||||
IP_VS_DBG_ADDR(cp->daf, &cp->daddr), ntohs(cp->dport),
|
IP_VS_DBG_ADDR(cp->daf, &cp->daddr), ntohs(cp->dport),
|
||||||
ip_vs_fwd_tag(cp), cp->state,
|
ip_vs_fwd_tag(cp), cp->state,
|
||||||
cp->flags, atomic_read(&cp->refcnt),
|
cp->flags, refcount_read(&cp->refcnt),
|
||||||
atomic_read(&dest->refcnt));
|
refcount_read(&dest->refcnt));
|
||||||
|
|
||||||
/* Update the connection counters */
|
/* Update the connection counters */
|
||||||
if (!(flags & IP_VS_CONN_F_TEMPLATE)) {
|
if (!(flags & IP_VS_CONN_F_TEMPLATE)) {
|
||||||
@ -714,8 +714,8 @@ static inline void ip_vs_unbind_dest(struct ip_vs_conn *cp)
|
|||||||
IP_VS_DBG_ADDR(cp->af, &cp->vaddr), ntohs(cp->vport),
|
IP_VS_DBG_ADDR(cp->af, &cp->vaddr), ntohs(cp->vport),
|
||||||
IP_VS_DBG_ADDR(cp->daf, &cp->daddr), ntohs(cp->dport),
|
IP_VS_DBG_ADDR(cp->daf, &cp->daddr), ntohs(cp->dport),
|
||||||
ip_vs_fwd_tag(cp), cp->state,
|
ip_vs_fwd_tag(cp), cp->state,
|
||||||
cp->flags, atomic_read(&cp->refcnt),
|
cp->flags, refcount_read(&cp->refcnt),
|
||||||
atomic_read(&dest->refcnt));
|
refcount_read(&dest->refcnt));
|
||||||
|
|
||||||
/* Update the connection counters */
|
/* Update the connection counters */
|
||||||
if (!(cp->flags & IP_VS_CONN_F_TEMPLATE)) {
|
if (!(cp->flags & IP_VS_CONN_F_TEMPLATE)) {
|
||||||
@ -863,10 +863,10 @@ static void ip_vs_conn_expire(unsigned long data)
|
|||||||
|
|
||||||
expire_later:
|
expire_later:
|
||||||
IP_VS_DBG(7, "delayed: conn->refcnt=%d conn->n_control=%d\n",
|
IP_VS_DBG(7, "delayed: conn->refcnt=%d conn->n_control=%d\n",
|
||||||
atomic_read(&cp->refcnt),
|
refcount_read(&cp->refcnt),
|
||||||
atomic_read(&cp->n_control));
|
atomic_read(&cp->n_control));
|
||||||
|
|
||||||
atomic_inc(&cp->refcnt);
|
refcount_inc(&cp->refcnt);
|
||||||
cp->timeout = 60*HZ;
|
cp->timeout = 60*HZ;
|
||||||
|
|
||||||
if (ipvs->sync_state & IP_VS_STATE_MASTER)
|
if (ipvs->sync_state & IP_VS_STATE_MASTER)
|
||||||
@ -941,7 +941,7 @@ ip_vs_conn_new(const struct ip_vs_conn_param *p, int dest_af,
|
|||||||
* it in the table, so that other thread run ip_vs_random_dropentry
|
* it in the table, so that other thread run ip_vs_random_dropentry
|
||||||
* but cannot drop this entry.
|
* but cannot drop this entry.
|
||||||
*/
|
*/
|
||||||
atomic_set(&cp->refcnt, 1);
|
refcount_set(&cp->refcnt, 1);
|
||||||
|
|
||||||
cp->control = NULL;
|
cp->control = NULL;
|
||||||
atomic_set(&cp->n_control, 0);
|
atomic_set(&cp->n_control, 0);
|
||||||
|
@ -542,7 +542,7 @@ ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb,
|
|||||||
IP_VS_DBG_ADDR(cp->af, &cp->caddr), ntohs(cp->cport),
|
IP_VS_DBG_ADDR(cp->af, &cp->caddr), ntohs(cp->cport),
|
||||||
IP_VS_DBG_ADDR(cp->af, &cp->vaddr), ntohs(cp->vport),
|
IP_VS_DBG_ADDR(cp->af, &cp->vaddr), ntohs(cp->vport),
|
||||||
IP_VS_DBG_ADDR(cp->daf, &cp->daddr), ntohs(cp->dport),
|
IP_VS_DBG_ADDR(cp->daf, &cp->daddr), ntohs(cp->dport),
|
||||||
cp->flags, atomic_read(&cp->refcnt));
|
cp->flags, refcount_read(&cp->refcnt));
|
||||||
|
|
||||||
ip_vs_conn_stats(cp, svc);
|
ip_vs_conn_stats(cp, svc);
|
||||||
return cp;
|
return cp;
|
||||||
@ -1193,7 +1193,7 @@ struct ip_vs_conn *ip_vs_new_conn_out(struct ip_vs_service *svc,
|
|||||||
IP_VS_DBG_ADDR(cp->af, &cp->caddr), ntohs(cp->cport),
|
IP_VS_DBG_ADDR(cp->af, &cp->caddr), ntohs(cp->cport),
|
||||||
IP_VS_DBG_ADDR(cp->af, &cp->vaddr), ntohs(cp->vport),
|
IP_VS_DBG_ADDR(cp->af, &cp->vaddr), ntohs(cp->vport),
|
||||||
IP_VS_DBG_ADDR(cp->af, &cp->daddr), ntohs(cp->dport),
|
IP_VS_DBG_ADDR(cp->af, &cp->daddr), ntohs(cp->dport),
|
||||||
cp->flags, atomic_read(&cp->refcnt));
|
cp->flags, refcount_read(&cp->refcnt));
|
||||||
LeaveFunction(12);
|
LeaveFunction(12);
|
||||||
return cp;
|
return cp;
|
||||||
}
|
}
|
||||||
@ -2231,8 +2231,6 @@ static int __net_init __ip_vs_init(struct net *net)
|
|||||||
if (ip_vs_sync_net_init(ipvs) < 0)
|
if (ip_vs_sync_net_init(ipvs) < 0)
|
||||||
goto sync_fail;
|
goto sync_fail;
|
||||||
|
|
||||||
printk(KERN_INFO "IPVS: Creating netns size=%zu id=%d\n",
|
|
||||||
sizeof(struct netns_ipvs), ipvs->gen);
|
|
||||||
return 0;
|
return 0;
|
||||||
/*
|
/*
|
||||||
* Error handling
|
* Error handling
|
||||||
|
@ -699,7 +699,7 @@ ip_vs_trash_get_dest(struct ip_vs_service *svc, int dest_af,
|
|||||||
dest->vfwmark,
|
dest->vfwmark,
|
||||||
IP_VS_DBG_ADDR(dest->af, &dest->addr),
|
IP_VS_DBG_ADDR(dest->af, &dest->addr),
|
||||||
ntohs(dest->port),
|
ntohs(dest->port),
|
||||||
atomic_read(&dest->refcnt));
|
refcount_read(&dest->refcnt));
|
||||||
if (dest->af == dest_af &&
|
if (dest->af == dest_af &&
|
||||||
ip_vs_addr_equal(dest_af, &dest->addr, daddr) &&
|
ip_vs_addr_equal(dest_af, &dest->addr, daddr) &&
|
||||||
dest->port == dport &&
|
dest->port == dport &&
|
||||||
@ -934,7 +934,7 @@ ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest,
|
|||||||
atomic_set(&dest->activeconns, 0);
|
atomic_set(&dest->activeconns, 0);
|
||||||
atomic_set(&dest->inactconns, 0);
|
atomic_set(&dest->inactconns, 0);
|
||||||
atomic_set(&dest->persistconns, 0);
|
atomic_set(&dest->persistconns, 0);
|
||||||
atomic_set(&dest->refcnt, 1);
|
refcount_set(&dest->refcnt, 1);
|
||||||
|
|
||||||
INIT_HLIST_NODE(&dest->d_list);
|
INIT_HLIST_NODE(&dest->d_list);
|
||||||
spin_lock_init(&dest->dst_lock);
|
spin_lock_init(&dest->dst_lock);
|
||||||
@ -998,7 +998,7 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
|
|||||||
IP_VS_DBG_BUF(3, "Get destination %s:%u from trash, "
|
IP_VS_DBG_BUF(3, "Get destination %s:%u from trash, "
|
||||||
"dest->refcnt=%d, service %u/%s:%u\n",
|
"dest->refcnt=%d, service %u/%s:%u\n",
|
||||||
IP_VS_DBG_ADDR(udest->af, &daddr), ntohs(dport),
|
IP_VS_DBG_ADDR(udest->af, &daddr), ntohs(dport),
|
||||||
atomic_read(&dest->refcnt),
|
refcount_read(&dest->refcnt),
|
||||||
dest->vfwmark,
|
dest->vfwmark,
|
||||||
IP_VS_DBG_ADDR(svc->af, &dest->vaddr),
|
IP_VS_DBG_ADDR(svc->af, &dest->vaddr),
|
||||||
ntohs(dest->vport));
|
ntohs(dest->vport));
|
||||||
@ -1074,7 +1074,7 @@ static void __ip_vs_del_dest(struct netns_ipvs *ipvs, struct ip_vs_dest *dest,
|
|||||||
spin_lock_bh(&ipvs->dest_trash_lock);
|
spin_lock_bh(&ipvs->dest_trash_lock);
|
||||||
IP_VS_DBG_BUF(3, "Moving dest %s:%u into trash, dest->refcnt=%d\n",
|
IP_VS_DBG_BUF(3, "Moving dest %s:%u into trash, dest->refcnt=%d\n",
|
||||||
IP_VS_DBG_ADDR(dest->af, &dest->addr), ntohs(dest->port),
|
IP_VS_DBG_ADDR(dest->af, &dest->addr), ntohs(dest->port),
|
||||||
atomic_read(&dest->refcnt));
|
refcount_read(&dest->refcnt));
|
||||||
if (list_empty(&ipvs->dest_trash) && !cleanup)
|
if (list_empty(&ipvs->dest_trash) && !cleanup)
|
||||||
mod_timer(&ipvs->dest_trash_timer,
|
mod_timer(&ipvs->dest_trash_timer,
|
||||||
jiffies + (IP_VS_DEST_TRASH_PERIOD >> 1));
|
jiffies + (IP_VS_DEST_TRASH_PERIOD >> 1));
|
||||||
@ -1157,7 +1157,7 @@ static void ip_vs_dest_trash_expire(unsigned long data)
|
|||||||
|
|
||||||
spin_lock(&ipvs->dest_trash_lock);
|
spin_lock(&ipvs->dest_trash_lock);
|
||||||
list_for_each_entry_safe(dest, next, &ipvs->dest_trash, t_list) {
|
list_for_each_entry_safe(dest, next, &ipvs->dest_trash, t_list) {
|
||||||
if (atomic_read(&dest->refcnt) > 1)
|
if (refcount_read(&dest->refcnt) > 1)
|
||||||
continue;
|
continue;
|
||||||
if (dest->idle_start) {
|
if (dest->idle_start) {
|
||||||
if (time_before(now, dest->idle_start +
|
if (time_before(now, dest->idle_start +
|
||||||
@ -1545,7 +1545,7 @@ ip_vs_forget_dev(struct ip_vs_dest *dest, struct net_device *dev)
|
|||||||
dev->name,
|
dev->name,
|
||||||
IP_VS_DBG_ADDR(dest->af, &dest->addr),
|
IP_VS_DBG_ADDR(dest->af, &dest->addr),
|
||||||
ntohs(dest->port),
|
ntohs(dest->port),
|
||||||
atomic_read(&dest->refcnt));
|
refcount_read(&dest->refcnt));
|
||||||
__ip_vs_dst_cache_reset(dest);
|
__ip_vs_dst_cache_reset(dest);
|
||||||
}
|
}
|
||||||
spin_unlock_bh(&dest->dst_lock);
|
spin_unlock_bh(&dest->dst_lock);
|
||||||
|
@ -448,7 +448,7 @@ __ip_vs_lblc_schedule(struct ip_vs_service *svc)
|
|||||||
IP_VS_DBG_ADDR(least->af, &least->addr),
|
IP_VS_DBG_ADDR(least->af, &least->addr),
|
||||||
ntohs(least->port),
|
ntohs(least->port),
|
||||||
atomic_read(&least->activeconns),
|
atomic_read(&least->activeconns),
|
||||||
atomic_read(&least->refcnt),
|
refcount_read(&least->refcnt),
|
||||||
atomic_read(&least->weight), loh);
|
atomic_read(&least->weight), loh);
|
||||||
|
|
||||||
return least;
|
return least;
|
||||||
|
@ -204,7 +204,7 @@ static inline struct ip_vs_dest *ip_vs_dest_set_min(struct ip_vs_dest_set *set)
|
|||||||
IP_VS_DBG_ADDR(least->af, &least->addr),
|
IP_VS_DBG_ADDR(least->af, &least->addr),
|
||||||
ntohs(least->port),
|
ntohs(least->port),
|
||||||
atomic_read(&least->activeconns),
|
atomic_read(&least->activeconns),
|
||||||
atomic_read(&least->refcnt),
|
refcount_read(&least->refcnt),
|
||||||
atomic_read(&least->weight), loh);
|
atomic_read(&least->weight), loh);
|
||||||
return least;
|
return least;
|
||||||
}
|
}
|
||||||
@ -249,7 +249,7 @@ static inline struct ip_vs_dest *ip_vs_dest_set_max(struct ip_vs_dest_set *set)
|
|||||||
__func__,
|
__func__,
|
||||||
IP_VS_DBG_ADDR(most->af, &most->addr), ntohs(most->port),
|
IP_VS_DBG_ADDR(most->af, &most->addr), ntohs(most->port),
|
||||||
atomic_read(&most->activeconns),
|
atomic_read(&most->activeconns),
|
||||||
atomic_read(&most->refcnt),
|
refcount_read(&most->refcnt),
|
||||||
atomic_read(&most->weight), moh);
|
atomic_read(&most->weight), moh);
|
||||||
return most;
|
return most;
|
||||||
}
|
}
|
||||||
@ -612,7 +612,7 @@ __ip_vs_lblcr_schedule(struct ip_vs_service *svc)
|
|||||||
IP_VS_DBG_ADDR(least->af, &least->addr),
|
IP_VS_DBG_ADDR(least->af, &least->addr),
|
||||||
ntohs(least->port),
|
ntohs(least->port),
|
||||||
atomic_read(&least->activeconns),
|
atomic_read(&least->activeconns),
|
||||||
atomic_read(&least->refcnt),
|
refcount_read(&least->refcnt),
|
||||||
atomic_read(&least->weight), loh);
|
atomic_read(&least->weight), loh);
|
||||||
|
|
||||||
return least;
|
return least;
|
||||||
|
@ -110,7 +110,7 @@ ip_vs_nq_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
|
|||||||
IP_VS_DBG_ADDR(least->af, &least->addr),
|
IP_VS_DBG_ADDR(least->af, &least->addr),
|
||||||
ntohs(least->port),
|
ntohs(least->port),
|
||||||
atomic_read(&least->activeconns),
|
atomic_read(&least->activeconns),
|
||||||
atomic_read(&least->refcnt),
|
refcount_read(&least->refcnt),
|
||||||
atomic_read(&least->weight), loh);
|
atomic_read(&least->weight), loh);
|
||||||
|
|
||||||
return least;
|
return least;
|
||||||
|
@ -447,7 +447,7 @@ set_sctp_state(struct ip_vs_proto_data *pd, struct ip_vs_conn *cp,
|
|||||||
ntohs(cp->cport),
|
ntohs(cp->cport),
|
||||||
sctp_state_name(cp->state),
|
sctp_state_name(cp->state),
|
||||||
sctp_state_name(next_state),
|
sctp_state_name(next_state),
|
||||||
atomic_read(&cp->refcnt));
|
refcount_read(&cp->refcnt));
|
||||||
if (dest) {
|
if (dest) {
|
||||||
if (!(cp->flags & IP_VS_CONN_F_INACTIVE) &&
|
if (!(cp->flags & IP_VS_CONN_F_INACTIVE) &&
|
||||||
(next_state != IP_VS_SCTP_S_ESTABLISHED)) {
|
(next_state != IP_VS_SCTP_S_ESTABLISHED)) {
|
||||||
|
@ -557,7 +557,7 @@ set_tcp_state(struct ip_vs_proto_data *pd, struct ip_vs_conn *cp,
|
|||||||
ntohs(cp->cport),
|
ntohs(cp->cport),
|
||||||
tcp_state_name(cp->state),
|
tcp_state_name(cp->state),
|
||||||
tcp_state_name(new_state),
|
tcp_state_name(new_state),
|
||||||
atomic_read(&cp->refcnt));
|
refcount_read(&cp->refcnt));
|
||||||
|
|
||||||
if (dest) {
|
if (dest) {
|
||||||
if (!(cp->flags & IP_VS_CONN_F_INACTIVE) &&
|
if (!(cp->flags & IP_VS_CONN_F_INACTIVE) &&
|
||||||
|
@ -97,7 +97,7 @@ stop:
|
|||||||
"activeconns %d refcnt %d weight %d\n",
|
"activeconns %d refcnt %d weight %d\n",
|
||||||
IP_VS_DBG_ADDR(dest->af, &dest->addr), ntohs(dest->port),
|
IP_VS_DBG_ADDR(dest->af, &dest->addr), ntohs(dest->port),
|
||||||
atomic_read(&dest->activeconns),
|
atomic_read(&dest->activeconns),
|
||||||
atomic_read(&dest->refcnt), atomic_read(&dest->weight));
|
refcount_read(&dest->refcnt), atomic_read(&dest->weight));
|
||||||
|
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,7 @@ ip_vs_sed_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
|
|||||||
IP_VS_DBG_ADDR(least->af, &least->addr),
|
IP_VS_DBG_ADDR(least->af, &least->addr),
|
||||||
ntohs(least->port),
|
ntohs(least->port),
|
||||||
atomic_read(&least->activeconns),
|
atomic_read(&least->activeconns),
|
||||||
atomic_read(&least->refcnt),
|
refcount_read(&least->refcnt),
|
||||||
atomic_read(&least->weight), loh);
|
atomic_read(&least->weight), loh);
|
||||||
|
|
||||||
return least;
|
return least;
|
||||||
|
@ -83,7 +83,7 @@ ip_vs_wlc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
|
|||||||
IP_VS_DBG_ADDR(least->af, &least->addr),
|
IP_VS_DBG_ADDR(least->af, &least->addr),
|
||||||
ntohs(least->port),
|
ntohs(least->port),
|
||||||
atomic_read(&least->activeconns),
|
atomic_read(&least->activeconns),
|
||||||
atomic_read(&least->refcnt),
|
refcount_read(&least->refcnt),
|
||||||
atomic_read(&least->weight), loh);
|
atomic_read(&least->weight), loh);
|
||||||
|
|
||||||
return least;
|
return least;
|
||||||
|
@ -218,7 +218,7 @@ found:
|
|||||||
"activeconns %d refcnt %d weight %d\n",
|
"activeconns %d refcnt %d weight %d\n",
|
||||||
IP_VS_DBG_ADDR(dest->af, &dest->addr), ntohs(dest->port),
|
IP_VS_DBG_ADDR(dest->af, &dest->addr), ntohs(dest->port),
|
||||||
atomic_read(&dest->activeconns),
|
atomic_read(&dest->activeconns),
|
||||||
atomic_read(&dest->refcnt),
|
refcount_read(&dest->refcnt),
|
||||||
atomic_read(&dest->weight));
|
atomic_read(&dest->weight));
|
||||||
mark->cl = dest;
|
mark->cl = dest;
|
||||||
|
|
||||||
|
@ -1129,7 +1129,7 @@ EXPORT_SYMBOL_GPL(nf_conntrack_free);
|
|||||||
|
|
||||||
/* Allocate a new conntrack: we return -ENOMEM if classification
|
/* Allocate a new conntrack: we return -ENOMEM if classification
|
||||||
failed due to stress. Otherwise it really is unclassifiable. */
|
failed due to stress. Otherwise it really is unclassifiable. */
|
||||||
static struct nf_conntrack_tuple_hash *
|
static noinline struct nf_conntrack_tuple_hash *
|
||||||
init_conntrack(struct net *net, struct nf_conn *tmpl,
|
init_conntrack(struct net *net, struct nf_conn *tmpl,
|
||||||
const struct nf_conntrack_tuple *tuple,
|
const struct nf_conntrack_tuple *tuple,
|
||||||
struct nf_conntrack_l3proto *l3proto,
|
struct nf_conntrack_l3proto *l3proto,
|
||||||
@ -1237,21 +1237,20 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
|
|||||||
return &ct->tuplehash[IP_CT_DIR_ORIGINAL];
|
return &ct->tuplehash[IP_CT_DIR_ORIGINAL];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* On success, returns conntrack ptr, sets skb->_nfct | ctinfo */
|
/* On success, returns 0, sets skb->_nfct | ctinfo */
|
||||||
static inline struct nf_conn *
|
static int
|
||||||
resolve_normal_ct(struct net *net, struct nf_conn *tmpl,
|
resolve_normal_ct(struct net *net, struct nf_conn *tmpl,
|
||||||
struct sk_buff *skb,
|
struct sk_buff *skb,
|
||||||
unsigned int dataoff,
|
unsigned int dataoff,
|
||||||
u_int16_t l3num,
|
u_int16_t l3num,
|
||||||
u_int8_t protonum,
|
u_int8_t protonum,
|
||||||
struct nf_conntrack_l3proto *l3proto,
|
struct nf_conntrack_l3proto *l3proto,
|
||||||
struct nf_conntrack_l4proto *l4proto,
|
struct nf_conntrack_l4proto *l4proto)
|
||||||
int *set_reply,
|
|
||||||
enum ip_conntrack_info *ctinfo)
|
|
||||||
{
|
{
|
||||||
const struct nf_conntrack_zone *zone;
|
const struct nf_conntrack_zone *zone;
|
||||||
struct nf_conntrack_tuple tuple;
|
struct nf_conntrack_tuple tuple;
|
||||||
struct nf_conntrack_tuple_hash *h;
|
struct nf_conntrack_tuple_hash *h;
|
||||||
|
enum ip_conntrack_info ctinfo;
|
||||||
struct nf_conntrack_zone tmp;
|
struct nf_conntrack_zone tmp;
|
||||||
struct nf_conn *ct;
|
struct nf_conn *ct;
|
||||||
u32 hash;
|
u32 hash;
|
||||||
@ -1260,7 +1259,7 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl,
|
|||||||
dataoff, l3num, protonum, net, &tuple, l3proto,
|
dataoff, l3num, protonum, net, &tuple, l3proto,
|
||||||
l4proto)) {
|
l4proto)) {
|
||||||
pr_debug("Can't get tuple\n");
|
pr_debug("Can't get tuple\n");
|
||||||
return NULL;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* look for tuple match */
|
/* look for tuple match */
|
||||||
@ -1271,33 +1270,30 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl,
|
|||||||
h = init_conntrack(net, tmpl, &tuple, l3proto, l4proto,
|
h = init_conntrack(net, tmpl, &tuple, l3proto, l4proto,
|
||||||
skb, dataoff, hash);
|
skb, dataoff, hash);
|
||||||
if (!h)
|
if (!h)
|
||||||
return NULL;
|
return 0;
|
||||||
if (IS_ERR(h))
|
if (IS_ERR(h))
|
||||||
return (void *)h;
|
return PTR_ERR(h);
|
||||||
}
|
}
|
||||||
ct = nf_ct_tuplehash_to_ctrack(h);
|
ct = nf_ct_tuplehash_to_ctrack(h);
|
||||||
|
|
||||||
/* It exists; we have (non-exclusive) reference. */
|
/* It exists; we have (non-exclusive) reference. */
|
||||||
if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY) {
|
if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY) {
|
||||||
*ctinfo = IP_CT_ESTABLISHED_REPLY;
|
ctinfo = IP_CT_ESTABLISHED_REPLY;
|
||||||
/* Please set reply bit if this packet OK */
|
|
||||||
*set_reply = 1;
|
|
||||||
} else {
|
} else {
|
||||||
/* Once we've had two way comms, always ESTABLISHED. */
|
/* Once we've had two way comms, always ESTABLISHED. */
|
||||||
if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
|
if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
|
||||||
pr_debug("normal packet for %p\n", ct);
|
pr_debug("normal packet for %p\n", ct);
|
||||||
*ctinfo = IP_CT_ESTABLISHED;
|
ctinfo = IP_CT_ESTABLISHED;
|
||||||
} else if (test_bit(IPS_EXPECTED_BIT, &ct->status)) {
|
} else if (test_bit(IPS_EXPECTED_BIT, &ct->status)) {
|
||||||
pr_debug("related packet for %p\n", ct);
|
pr_debug("related packet for %p\n", ct);
|
||||||
*ctinfo = IP_CT_RELATED;
|
ctinfo = IP_CT_RELATED;
|
||||||
} else {
|
} else {
|
||||||
pr_debug("new packet for %p\n", ct);
|
pr_debug("new packet for %p\n", ct);
|
||||||
*ctinfo = IP_CT_NEW;
|
ctinfo = IP_CT_NEW;
|
||||||
}
|
}
|
||||||
*set_reply = 0;
|
|
||||||
}
|
}
|
||||||
nf_ct_set(skb, ct, *ctinfo);
|
nf_ct_set(skb, ct, ctinfo);
|
||||||
return ct;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int
|
unsigned int
|
||||||
@ -1311,7 +1307,6 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
|
|||||||
unsigned int *timeouts;
|
unsigned int *timeouts;
|
||||||
unsigned int dataoff;
|
unsigned int dataoff;
|
||||||
u_int8_t protonum;
|
u_int8_t protonum;
|
||||||
int set_reply = 0;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
tmpl = nf_ct_get(skb, &ctinfo);
|
tmpl = nf_ct_get(skb, &ctinfo);
|
||||||
@ -1354,23 +1349,22 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
repeat:
|
repeat:
|
||||||
ct = resolve_normal_ct(net, tmpl, skb, dataoff, pf, protonum,
|
ret = resolve_normal_ct(net, tmpl, skb, dataoff, pf, protonum,
|
||||||
l3proto, l4proto, &set_reply, &ctinfo);
|
l3proto, l4proto);
|
||||||
if (!ct) {
|
if (ret < 0) {
|
||||||
/* Not valid part of a connection */
|
|
||||||
NF_CT_STAT_INC_ATOMIC(net, invalid);
|
|
||||||
ret = NF_ACCEPT;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IS_ERR(ct)) {
|
|
||||||
/* Too stressed to deal. */
|
/* Too stressed to deal. */
|
||||||
NF_CT_STAT_INC_ATOMIC(net, drop);
|
NF_CT_STAT_INC_ATOMIC(net, drop);
|
||||||
ret = NF_DROP;
|
ret = NF_DROP;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
NF_CT_ASSERT(skb_nfct(skb));
|
ct = nf_ct_get(skb, &ctinfo);
|
||||||
|
if (!ct) {
|
||||||
|
/* Not valid part of a connection */
|
||||||
|
NF_CT_STAT_INC_ATOMIC(net, invalid);
|
||||||
|
ret = NF_ACCEPT;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/* Decide what timeout policy we want to apply to this flow. */
|
/* Decide what timeout policy we want to apply to this flow. */
|
||||||
timeouts = nf_ct_timeout_lookup(net, ct, l4proto);
|
timeouts = nf_ct_timeout_lookup(net, ct, l4proto);
|
||||||
@ -1395,7 +1389,8 @@ repeat:
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (set_reply && !test_and_set_bit(IPS_SEEN_REPLY_BIT, &ct->status))
|
if (ctinfo == IP_CT_ESTABLISHED_REPLY &&
|
||||||
|
!test_and_set_bit(IPS_SEEN_REPLY_BIT, &ct->status))
|
||||||
nf_conntrack_event_cache(IPCT_REPLY, ct);
|
nf_conntrack_event_cache(IPCT_REPLY, ct);
|
||||||
out:
|
out:
|
||||||
if (tmpl)
|
if (tmpl)
|
||||||
|
@ -133,7 +133,7 @@ nf_ct_expect_find_get(struct net *net,
|
|||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
i = __nf_ct_expect_find(net, zone, tuple);
|
i = __nf_ct_expect_find(net, zone, tuple);
|
||||||
if (i && !atomic_inc_not_zero(&i->use))
|
if (i && !refcount_inc_not_zero(&i->use))
|
||||||
i = NULL;
|
i = NULL;
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
|
||||||
@ -186,7 +186,7 @@ nf_ct_find_expectation(struct net *net,
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (exp->flags & NF_CT_EXPECT_PERMANENT) {
|
if (exp->flags & NF_CT_EXPECT_PERMANENT) {
|
||||||
atomic_inc(&exp->use);
|
refcount_inc(&exp->use);
|
||||||
return exp;
|
return exp;
|
||||||
} else if (del_timer(&exp->timeout)) {
|
} else if (del_timer(&exp->timeout)) {
|
||||||
nf_ct_unlink_expect(exp);
|
nf_ct_unlink_expect(exp);
|
||||||
@ -275,7 +275,7 @@ struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
new->master = me;
|
new->master = me;
|
||||||
atomic_set(&new->use, 1);
|
refcount_set(&new->use, 1);
|
||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nf_ct_expect_alloc);
|
EXPORT_SYMBOL_GPL(nf_ct_expect_alloc);
|
||||||
@ -348,7 +348,7 @@ static void nf_ct_expect_free_rcu(struct rcu_head *head)
|
|||||||
|
|
||||||
void nf_ct_expect_put(struct nf_conntrack_expect *exp)
|
void nf_ct_expect_put(struct nf_conntrack_expect *exp)
|
||||||
{
|
{
|
||||||
if (atomic_dec_and_test(&exp->use))
|
if (refcount_dec_and_test(&exp->use))
|
||||||
call_rcu(&exp->rcu, nf_ct_expect_free_rcu);
|
call_rcu(&exp->rcu, nf_ct_expect_free_rcu);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nf_ct_expect_put);
|
EXPORT_SYMBOL_GPL(nf_ct_expect_put);
|
||||||
@ -361,7 +361,7 @@ static void nf_ct_expect_insert(struct nf_conntrack_expect *exp)
|
|||||||
unsigned int h = nf_ct_expect_dst_hash(net, &exp->tuple);
|
unsigned int h = nf_ct_expect_dst_hash(net, &exp->tuple);
|
||||||
|
|
||||||
/* two references : one for hash insert, one for the timer */
|
/* two references : one for hash insert, one for the timer */
|
||||||
atomic_add(2, &exp->use);
|
refcount_add(2, &exp->use);
|
||||||
|
|
||||||
hlist_add_head(&exp->lnode, &master_help->expectations);
|
hlist_add_head(&exp->lnode, &master_help->expectations);
|
||||||
master_help->expecting[exp->class]++;
|
master_help->expecting[exp->class]++;
|
||||||
|
@ -2693,7 +2693,7 @@ restart:
|
|||||||
cb->nlh->nlmsg_seq,
|
cb->nlh->nlmsg_seq,
|
||||||
IPCTNL_MSG_EXP_NEW,
|
IPCTNL_MSG_EXP_NEW,
|
||||||
exp) < 0) {
|
exp) < 0) {
|
||||||
if (!atomic_inc_not_zero(&exp->use))
|
if (!refcount_inc_not_zero(&exp->use))
|
||||||
continue;
|
continue;
|
||||||
cb->args[1] = (unsigned long)exp;
|
cb->args[1] = (unsigned long)exp;
|
||||||
goto out;
|
goto out;
|
||||||
@ -2739,7 +2739,7 @@ restart:
|
|||||||
cb->nlh->nlmsg_seq,
|
cb->nlh->nlmsg_seq,
|
||||||
IPCTNL_MSG_EXP_NEW,
|
IPCTNL_MSG_EXP_NEW,
|
||||||
exp) < 0) {
|
exp) < 0) {
|
||||||
if (!atomic_inc_not_zero(&exp->use))
|
if (!refcount_inc_not_zero(&exp->use))
|
||||||
continue;
|
continue;
|
||||||
cb->args[1] = (unsigned long)exp;
|
cb->args[1] = (unsigned long)exp;
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -1772,8 +1772,19 @@ static int nf_tables_newexpr(const struct nft_ctx *ctx,
|
|||||||
goto err1;
|
goto err1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ops->validate) {
|
||||||
|
const struct nft_data *data = NULL;
|
||||||
|
|
||||||
|
err = ops->validate(ctx, expr, &data);
|
||||||
|
if (err < 0)
|
||||||
|
goto err2;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
err2:
|
||||||
|
if (ops->destroy)
|
||||||
|
ops->destroy(ctx, expr);
|
||||||
err1:
|
err1:
|
||||||
expr->ops = NULL;
|
expr->ops = NULL;
|
||||||
return err;
|
return err;
|
||||||
@ -2523,8 +2534,8 @@ static int nft_ctx_init_from_setattr(struct nft_ctx *ctx, struct net *net,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct nft_set *nf_tables_set_lookup(const struct nft_table *table,
|
static struct nft_set *nf_tables_set_lookup(const struct nft_table *table,
|
||||||
const struct nlattr *nla, u8 genmask)
|
const struct nlattr *nla, u8 genmask)
|
||||||
{
|
{
|
||||||
struct nft_set *set;
|
struct nft_set *set;
|
||||||
|
|
||||||
@ -2538,11 +2549,10 @@ struct nft_set *nf_tables_set_lookup(const struct nft_table *table,
|
|||||||
}
|
}
|
||||||
return ERR_PTR(-ENOENT);
|
return ERR_PTR(-ENOENT);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nf_tables_set_lookup);
|
|
||||||
|
|
||||||
struct nft_set *nf_tables_set_lookup_byid(const struct net *net,
|
static struct nft_set *nf_tables_set_lookup_byid(const struct net *net,
|
||||||
const struct nlattr *nla,
|
const struct nlattr *nla,
|
||||||
u8 genmask)
|
u8 genmask)
|
||||||
{
|
{
|
||||||
struct nft_trans *trans;
|
struct nft_trans *trans;
|
||||||
u32 id = ntohl(nla_get_be32(nla));
|
u32 id = ntohl(nla_get_be32(nla));
|
||||||
@ -2557,7 +2567,25 @@ struct nft_set *nf_tables_set_lookup_byid(const struct net *net,
|
|||||||
}
|
}
|
||||||
return ERR_PTR(-ENOENT);
|
return ERR_PTR(-ENOENT);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nf_tables_set_lookup_byid);
|
|
||||||
|
struct nft_set *nft_set_lookup(const struct net *net,
|
||||||
|
const struct nft_table *table,
|
||||||
|
const struct nlattr *nla_set_name,
|
||||||
|
const struct nlattr *nla_set_id,
|
||||||
|
u8 genmask)
|
||||||
|
{
|
||||||
|
struct nft_set *set;
|
||||||
|
|
||||||
|
set = nf_tables_set_lookup(table, nla_set_name, genmask);
|
||||||
|
if (IS_ERR(set)) {
|
||||||
|
if (!nla_set_id)
|
||||||
|
return set;
|
||||||
|
|
||||||
|
set = nf_tables_set_lookup_byid(net, nla_set_id, genmask);
|
||||||
|
}
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(nft_set_lookup);
|
||||||
|
|
||||||
static int nf_tables_set_alloc_name(struct nft_ctx *ctx, struct nft_set *set,
|
static int nf_tables_set_alloc_name(struct nft_ctx *ctx, struct nft_set *set,
|
||||||
const char *name)
|
const char *name)
|
||||||
@ -4067,7 +4095,8 @@ static const struct nla_policy nft_obj_policy[NFTA_OBJ_MAX + 1] = {
|
|||||||
[NFTA_OBJ_DATA] = { .type = NLA_NESTED },
|
[NFTA_OBJ_DATA] = { .type = NLA_NESTED },
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct nft_object *nft_obj_init(const struct nft_object_type *type,
|
static struct nft_object *nft_obj_init(const struct nft_ctx *ctx,
|
||||||
|
const struct nft_object_type *type,
|
||||||
const struct nlattr *attr)
|
const struct nlattr *attr)
|
||||||
{
|
{
|
||||||
struct nlattr *tb[type->maxattr + 1];
|
struct nlattr *tb[type->maxattr + 1];
|
||||||
@ -4087,7 +4116,7 @@ static struct nft_object *nft_obj_init(const struct nft_object_type *type,
|
|||||||
if (obj == NULL)
|
if (obj == NULL)
|
||||||
goto err1;
|
goto err1;
|
||||||
|
|
||||||
err = type->init((const struct nlattr * const *)tb, obj);
|
err = type->init(ctx, (const struct nlattr * const *)tb, obj);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto err2;
|
goto err2;
|
||||||
|
|
||||||
@ -4195,7 +4224,7 @@ static int nf_tables_newobj(struct net *net, struct sock *nlsk,
|
|||||||
if (IS_ERR(type))
|
if (IS_ERR(type))
|
||||||
return PTR_ERR(type);
|
return PTR_ERR(type);
|
||||||
|
|
||||||
obj = nft_obj_init(type, nla[NFTA_OBJ_DATA]);
|
obj = nft_obj_init(&ctx, type, nla[NFTA_OBJ_DATA]);
|
||||||
if (IS_ERR(obj)) {
|
if (IS_ERR(obj)) {
|
||||||
err = PTR_ERR(obj);
|
err = PTR_ERR(obj);
|
||||||
goto err1;
|
goto err1;
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/skbuff.h>
|
#include <linux/skbuff.h>
|
||||||
#include <linux/atomic.h>
|
#include <linux/atomic.h>
|
||||||
|
#include <linux/refcount.h>
|
||||||
#include <linux/netlink.h>
|
#include <linux/netlink.h>
|
||||||
#include <linux/rculist.h>
|
#include <linux/rculist.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
@ -32,7 +33,7 @@ struct nf_acct {
|
|||||||
atomic64_t bytes;
|
atomic64_t bytes;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
struct list_head head;
|
struct list_head head;
|
||||||
atomic_t refcnt;
|
refcount_t refcnt;
|
||||||
char name[NFACCT_NAME_MAX];
|
char name[NFACCT_NAME_MAX];
|
||||||
struct rcu_head rcu_head;
|
struct rcu_head rcu_head;
|
||||||
char data[0];
|
char data[0];
|
||||||
@ -123,7 +124,7 @@ static int nfnl_acct_new(struct net *net, struct sock *nfnl,
|
|||||||
atomic64_set(&nfacct->pkts,
|
atomic64_set(&nfacct->pkts,
|
||||||
be64_to_cpu(nla_get_be64(tb[NFACCT_PKTS])));
|
be64_to_cpu(nla_get_be64(tb[NFACCT_PKTS])));
|
||||||
}
|
}
|
||||||
atomic_set(&nfacct->refcnt, 1);
|
refcount_set(&nfacct->refcnt, 1);
|
||||||
list_add_tail_rcu(&nfacct->head, &net->nfnl_acct_list);
|
list_add_tail_rcu(&nfacct->head, &net->nfnl_acct_list);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -166,7 +167,7 @@ nfnl_acct_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
|
|||||||
NFACCT_PAD) ||
|
NFACCT_PAD) ||
|
||||||
nla_put_be64(skb, NFACCT_BYTES, cpu_to_be64(bytes),
|
nla_put_be64(skb, NFACCT_BYTES, cpu_to_be64(bytes),
|
||||||
NFACCT_PAD) ||
|
NFACCT_PAD) ||
|
||||||
nla_put_be32(skb, NFACCT_USE, htonl(atomic_read(&acct->refcnt))))
|
nla_put_be32(skb, NFACCT_USE, htonl(refcount_read(&acct->refcnt))))
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
if (acct->flags & NFACCT_F_QUOTA) {
|
if (acct->flags & NFACCT_F_QUOTA) {
|
||||||
u64 *quota = (u64 *)acct->data;
|
u64 *quota = (u64 *)acct->data;
|
||||||
@ -329,7 +330,7 @@ static int nfnl_acct_try_del(struct nf_acct *cur)
|
|||||||
/* We want to avoid races with nfnl_acct_put. So only when the current
|
/* We want to avoid races with nfnl_acct_put. So only when the current
|
||||||
* refcnt is 1, we decrease it to 0.
|
* refcnt is 1, we decrease it to 0.
|
||||||
*/
|
*/
|
||||||
if (atomic_cmpxchg(&cur->refcnt, 1, 0) == 1) {
|
if (refcount_dec_if_one(&cur->refcnt)) {
|
||||||
/* We are protected by nfnl mutex. */
|
/* We are protected by nfnl mutex. */
|
||||||
list_del_rcu(&cur->head);
|
list_del_rcu(&cur->head);
|
||||||
kfree_rcu(cur, rcu_head);
|
kfree_rcu(cur, rcu_head);
|
||||||
@ -413,7 +414,7 @@ struct nf_acct *nfnl_acct_find_get(struct net *net, const char *acct_name)
|
|||||||
if (!try_module_get(THIS_MODULE))
|
if (!try_module_get(THIS_MODULE))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
if (!atomic_inc_not_zero(&cur->refcnt)) {
|
if (!refcount_inc_not_zero(&cur->refcnt)) {
|
||||||
module_put(THIS_MODULE);
|
module_put(THIS_MODULE);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
@ -429,7 +430,7 @@ EXPORT_SYMBOL_GPL(nfnl_acct_find_get);
|
|||||||
|
|
||||||
void nfnl_acct_put(struct nf_acct *acct)
|
void nfnl_acct_put(struct nf_acct *acct)
|
||||||
{
|
{
|
||||||
if (atomic_dec_and_test(&acct->refcnt))
|
if (refcount_dec_and_test(&acct->refcnt))
|
||||||
kfree_rcu(acct, rcu_head);
|
kfree_rcu(acct, rcu_head);
|
||||||
|
|
||||||
module_put(THIS_MODULE);
|
module_put(THIS_MODULE);
|
||||||
@ -502,7 +503,7 @@ static void __net_exit nfnl_acct_net_exit(struct net *net)
|
|||||||
list_for_each_entry_safe(cur, tmp, &net->nfnl_acct_list, head) {
|
list_for_each_entry_safe(cur, tmp, &net->nfnl_acct_list, head) {
|
||||||
list_del_rcu(&cur->head);
|
list_del_rcu(&cur->head);
|
||||||
|
|
||||||
if (atomic_dec_and_test(&cur->refcnt))
|
if (refcount_dec_and_test(&cur->refcnt))
|
||||||
kfree_rcu(cur, rcu_head);
|
kfree_rcu(cur, rcu_head);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -138,7 +138,7 @@ static int cttimeout_new_timeout(struct net *net, struct sock *ctnl,
|
|||||||
strcpy(timeout->name, nla_data(cda[CTA_TIMEOUT_NAME]));
|
strcpy(timeout->name, nla_data(cda[CTA_TIMEOUT_NAME]));
|
||||||
timeout->l3num = l3num;
|
timeout->l3num = l3num;
|
||||||
timeout->l4proto = l4proto;
|
timeout->l4proto = l4proto;
|
||||||
atomic_set(&timeout->refcnt, 1);
|
refcount_set(&timeout->refcnt, 1);
|
||||||
list_add_tail_rcu(&timeout->head, &net->nfct_timeout_list);
|
list_add_tail_rcu(&timeout->head, &net->nfct_timeout_list);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -172,7 +172,7 @@ ctnl_timeout_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
|
|||||||
nla_put_be16(skb, CTA_TIMEOUT_L3PROTO, htons(timeout->l3num)) ||
|
nla_put_be16(skb, CTA_TIMEOUT_L3PROTO, htons(timeout->l3num)) ||
|
||||||
nla_put_u8(skb, CTA_TIMEOUT_L4PROTO, timeout->l4proto->l4proto) ||
|
nla_put_u8(skb, CTA_TIMEOUT_L4PROTO, timeout->l4proto->l4proto) ||
|
||||||
nla_put_be32(skb, CTA_TIMEOUT_USE,
|
nla_put_be32(skb, CTA_TIMEOUT_USE,
|
||||||
htonl(atomic_read(&timeout->refcnt))))
|
htonl(refcount_read(&timeout->refcnt))))
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
|
|
||||||
if (likely(l4proto->ctnl_timeout.obj_to_nlattr)) {
|
if (likely(l4proto->ctnl_timeout.obj_to_nlattr)) {
|
||||||
@ -339,7 +339,7 @@ static int ctnl_timeout_try_del(struct net *net, struct ctnl_timeout *timeout)
|
|||||||
/* We want to avoid races with ctnl_timeout_put. So only when the
|
/* We want to avoid races with ctnl_timeout_put. So only when the
|
||||||
* current refcnt is 1, we decrease it to 0.
|
* current refcnt is 1, we decrease it to 0.
|
||||||
*/
|
*/
|
||||||
if (atomic_cmpxchg(&timeout->refcnt, 1, 0) == 1) {
|
if (refcount_dec_if_one(&timeout->refcnt)) {
|
||||||
/* We are protected by nfnl mutex. */
|
/* We are protected by nfnl mutex. */
|
||||||
list_del_rcu(&timeout->head);
|
list_del_rcu(&timeout->head);
|
||||||
nf_ct_l4proto_put(timeout->l4proto);
|
nf_ct_l4proto_put(timeout->l4proto);
|
||||||
@ -536,7 +536,7 @@ ctnl_timeout_find_get(struct net *net, const char *name)
|
|||||||
if (!try_module_get(THIS_MODULE))
|
if (!try_module_get(THIS_MODULE))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
if (!atomic_inc_not_zero(&timeout->refcnt)) {
|
if (!refcount_inc_not_zero(&timeout->refcnt)) {
|
||||||
module_put(THIS_MODULE);
|
module_put(THIS_MODULE);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
@ -550,7 +550,7 @@ err:
|
|||||||
|
|
||||||
static void ctnl_timeout_put(struct ctnl_timeout *timeout)
|
static void ctnl_timeout_put(struct ctnl_timeout *timeout)
|
||||||
{
|
{
|
||||||
if (atomic_dec_and_test(&timeout->refcnt))
|
if (refcount_dec_and_test(&timeout->refcnt))
|
||||||
kfree_rcu(timeout, rcu_head);
|
kfree_rcu(timeout, rcu_head);
|
||||||
|
|
||||||
module_put(THIS_MODULE);
|
module_put(THIS_MODULE);
|
||||||
@ -601,7 +601,7 @@ static void __net_exit cttimeout_net_exit(struct net *net)
|
|||||||
list_del_rcu(&cur->head);
|
list_del_rcu(&cur->head);
|
||||||
nf_ct_l4proto_put(cur->l4proto);
|
nf_ct_l4proto_put(cur->l4proto);
|
||||||
|
|
||||||
if (atomic_dec_and_test(&cur->refcnt))
|
if (refcount_dec_and_test(&cur->refcnt))
|
||||||
kfree_rcu(cur, rcu_head);
|
kfree_rcu(cur, rcu_head);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,8 @@
|
|||||||
#include <net/netfilter/nfnetlink_log.h>
|
#include <net/netfilter/nfnetlink_log.h>
|
||||||
|
|
||||||
#include <linux/atomic.h>
|
#include <linux/atomic.h>
|
||||||
|
#include <linux/refcount.h>
|
||||||
|
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
|
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
|
||||||
#include "../bridge/br_private.h"
|
#include "../bridge/br_private.h"
|
||||||
@ -57,7 +59,7 @@
|
|||||||
struct nfulnl_instance {
|
struct nfulnl_instance {
|
||||||
struct hlist_node hlist; /* global list of instances */
|
struct hlist_node hlist; /* global list of instances */
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
atomic_t use; /* use count */
|
refcount_t use; /* use count */
|
||||||
|
|
||||||
unsigned int qlen; /* number of nlmsgs in skb */
|
unsigned int qlen; /* number of nlmsgs in skb */
|
||||||
struct sk_buff *skb; /* pre-allocatd skb */
|
struct sk_buff *skb; /* pre-allocatd skb */
|
||||||
@ -115,7 +117,7 @@ __instance_lookup(struct nfnl_log_net *log, u_int16_t group_num)
|
|||||||
static inline void
|
static inline void
|
||||||
instance_get(struct nfulnl_instance *inst)
|
instance_get(struct nfulnl_instance *inst)
|
||||||
{
|
{
|
||||||
atomic_inc(&inst->use);
|
refcount_inc(&inst->use);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct nfulnl_instance *
|
static struct nfulnl_instance *
|
||||||
@ -125,7 +127,7 @@ instance_lookup_get(struct nfnl_log_net *log, u_int16_t group_num)
|
|||||||
|
|
||||||
rcu_read_lock_bh();
|
rcu_read_lock_bh();
|
||||||
inst = __instance_lookup(log, group_num);
|
inst = __instance_lookup(log, group_num);
|
||||||
if (inst && !atomic_inc_not_zero(&inst->use))
|
if (inst && !refcount_inc_not_zero(&inst->use))
|
||||||
inst = NULL;
|
inst = NULL;
|
||||||
rcu_read_unlock_bh();
|
rcu_read_unlock_bh();
|
||||||
|
|
||||||
@ -145,7 +147,7 @@ static void nfulnl_instance_free_rcu(struct rcu_head *head)
|
|||||||
static void
|
static void
|
||||||
instance_put(struct nfulnl_instance *inst)
|
instance_put(struct nfulnl_instance *inst)
|
||||||
{
|
{
|
||||||
if (inst && atomic_dec_and_test(&inst->use))
|
if (inst && refcount_dec_and_test(&inst->use))
|
||||||
call_rcu_bh(&inst->rcu, nfulnl_instance_free_rcu);
|
call_rcu_bh(&inst->rcu, nfulnl_instance_free_rcu);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,7 +182,7 @@ instance_create(struct net *net, u_int16_t group_num,
|
|||||||
INIT_HLIST_NODE(&inst->hlist);
|
INIT_HLIST_NODE(&inst->hlist);
|
||||||
spin_lock_init(&inst->lock);
|
spin_lock_init(&inst->lock);
|
||||||
/* needs to be two, since we _put() after creation */
|
/* needs to be two, since we _put() after creation */
|
||||||
atomic_set(&inst->use, 2);
|
refcount_set(&inst->use, 2);
|
||||||
|
|
||||||
setup_timer(&inst->timer, nfulnl_timer, (unsigned long)inst);
|
setup_timer(&inst->timer, nfulnl_timer, (unsigned long)inst);
|
||||||
|
|
||||||
@ -1031,7 +1033,7 @@ static int seq_show(struct seq_file *s, void *v)
|
|||||||
inst->group_num,
|
inst->group_num,
|
||||||
inst->peer_portid, inst->qlen,
|
inst->peer_portid, inst->qlen,
|
||||||
inst->copy_mode, inst->copy_range,
|
inst->copy_mode, inst->copy_range,
|
||||||
inst->flushtimeout, atomic_read(&inst->use));
|
inst->flushtimeout, refcount_read(&inst->use));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -230,10 +230,6 @@ nft_target_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
|
|||||||
union nft_entry e = {};
|
union nft_entry e = {};
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = nft_compat_chain_validate_dependency(target->table, ctx->chain);
|
|
||||||
if (ret < 0)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
target_compat_from_user(target, nla_data(tb[NFTA_TARGET_INFO]), info);
|
target_compat_from_user(target, nla_data(tb[NFTA_TARGET_INFO]), info);
|
||||||
|
|
||||||
if (ctx->nla[NFTA_RULE_COMPAT]) {
|
if (ctx->nla[NFTA_RULE_COMPAT]) {
|
||||||
@ -419,10 +415,6 @@ nft_match_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
|
|||||||
union nft_entry e = {};
|
union nft_entry e = {};
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = nft_compat_chain_validate_dependency(match->table, ctx->chain);
|
|
||||||
if (ret < 0)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
match_compat_from_user(match, nla_data(tb[NFTA_MATCH_INFO]), info);
|
match_compat_from_user(match, nla_data(tb[NFTA_MATCH_INFO]), info);
|
||||||
|
|
||||||
if (ctx->nla[NFTA_RULE_COMPAT]) {
|
if (ctx->nla[NFTA_RULE_COMPAT]) {
|
||||||
|
@ -82,7 +82,8 @@ static int nft_counter_do_init(const struct nlattr * const tb[],
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nft_counter_obj_init(const struct nlattr * const tb[],
|
static int nft_counter_obj_init(const struct nft_ctx *ctx,
|
||||||
|
const struct nlattr * const tb[],
|
||||||
struct nft_object *obj)
|
struct nft_object *obj)
|
||||||
{
|
{
|
||||||
struct nft_counter_percpu_priv *priv = nft_obj_data(obj);
|
struct nft_counter_percpu_priv *priv = nft_obj_data(obj);
|
||||||
|
@ -32,6 +32,12 @@ struct nft_ct {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct nft_ct_helper_obj {
|
||||||
|
struct nf_conntrack_helper *helper4;
|
||||||
|
struct nf_conntrack_helper *helper6;
|
||||||
|
u8 l4proto;
|
||||||
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_NF_CONNTRACK_ZONES
|
#ifdef CONFIG_NF_CONNTRACK_ZONES
|
||||||
static DEFINE_PER_CPU(struct nf_conn *, nft_ct_pcpu_template);
|
static DEFINE_PER_CPU(struct nf_conn *, nft_ct_pcpu_template);
|
||||||
static unsigned int nft_ct_pcpu_template_refcnt __read_mostly;
|
static unsigned int nft_ct_pcpu_template_refcnt __read_mostly;
|
||||||
@ -730,6 +736,162 @@ static struct nft_expr_type nft_notrack_type __read_mostly = {
|
|||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int nft_ct_helper_obj_init(const struct nft_ctx *ctx,
|
||||||
|
const struct nlattr * const tb[],
|
||||||
|
struct nft_object *obj)
|
||||||
|
{
|
||||||
|
struct nft_ct_helper_obj *priv = nft_obj_data(obj);
|
||||||
|
struct nf_conntrack_helper *help4, *help6;
|
||||||
|
char name[NF_CT_HELPER_NAME_LEN];
|
||||||
|
int family = ctx->afi->family;
|
||||||
|
|
||||||
|
if (!tb[NFTA_CT_HELPER_NAME] || !tb[NFTA_CT_HELPER_L4PROTO])
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
priv->l4proto = nla_get_u8(tb[NFTA_CT_HELPER_L4PROTO]);
|
||||||
|
if (!priv->l4proto)
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
|
nla_strlcpy(name, tb[NFTA_CT_HELPER_NAME], sizeof(name));
|
||||||
|
|
||||||
|
if (tb[NFTA_CT_HELPER_L3PROTO])
|
||||||
|
family = ntohs(nla_get_be16(tb[NFTA_CT_HELPER_L3PROTO]));
|
||||||
|
|
||||||
|
help4 = NULL;
|
||||||
|
help6 = NULL;
|
||||||
|
|
||||||
|
switch (family) {
|
||||||
|
case NFPROTO_IPV4:
|
||||||
|
if (ctx->afi->family == NFPROTO_IPV6)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
help4 = nf_conntrack_helper_try_module_get(name, family,
|
||||||
|
priv->l4proto);
|
||||||
|
break;
|
||||||
|
case NFPROTO_IPV6:
|
||||||
|
if (ctx->afi->family == NFPROTO_IPV4)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
help6 = nf_conntrack_helper_try_module_get(name, family,
|
||||||
|
priv->l4proto);
|
||||||
|
break;
|
||||||
|
case NFPROTO_NETDEV: /* fallthrough */
|
||||||
|
case NFPROTO_BRIDGE: /* same */
|
||||||
|
case NFPROTO_INET:
|
||||||
|
help4 = nf_conntrack_helper_try_module_get(name, NFPROTO_IPV4,
|
||||||
|
priv->l4proto);
|
||||||
|
help6 = nf_conntrack_helper_try_module_get(name, NFPROTO_IPV6,
|
||||||
|
priv->l4proto);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EAFNOSUPPORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* && is intentional; only error if INET found neither ipv4 or ipv6 */
|
||||||
|
if (!help4 && !help6)
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
|
priv->helper4 = help4;
|
||||||
|
priv->helper6 = help6;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nft_ct_helper_obj_destroy(struct nft_object *obj)
|
||||||
|
{
|
||||||
|
struct nft_ct_helper_obj *priv = nft_obj_data(obj);
|
||||||
|
|
||||||
|
if (priv->helper4)
|
||||||
|
module_put(priv->helper4->me);
|
||||||
|
if (priv->helper6)
|
||||||
|
module_put(priv->helper6->me);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nft_ct_helper_obj_eval(struct nft_object *obj,
|
||||||
|
struct nft_regs *regs,
|
||||||
|
const struct nft_pktinfo *pkt)
|
||||||
|
{
|
||||||
|
const struct nft_ct_helper_obj *priv = nft_obj_data(obj);
|
||||||
|
struct nf_conn *ct = (struct nf_conn *)skb_nfct(pkt->skb);
|
||||||
|
struct nf_conntrack_helper *to_assign = NULL;
|
||||||
|
struct nf_conn_help *help;
|
||||||
|
|
||||||
|
if (!ct ||
|
||||||
|
nf_ct_is_confirmed(ct) ||
|
||||||
|
nf_ct_is_template(ct) ||
|
||||||
|
priv->l4proto != nf_ct_protonum(ct))
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (nf_ct_l3num(ct)) {
|
||||||
|
case NFPROTO_IPV4:
|
||||||
|
to_assign = priv->helper4;
|
||||||
|
break;
|
||||||
|
case NFPROTO_IPV6:
|
||||||
|
to_assign = priv->helper6;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
WARN_ON_ONCE(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!to_assign)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (test_bit(IPS_HELPER_BIT, &ct->status))
|
||||||
|
return;
|
||||||
|
|
||||||
|
help = nf_ct_helper_ext_add(ct, to_assign, GFP_ATOMIC);
|
||||||
|
if (help) {
|
||||||
|
rcu_assign_pointer(help->helper, to_assign);
|
||||||
|
set_bit(IPS_HELPER_BIT, &ct->status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nft_ct_helper_obj_dump(struct sk_buff *skb,
|
||||||
|
struct nft_object *obj, bool reset)
|
||||||
|
{
|
||||||
|
const struct nft_ct_helper_obj *priv = nft_obj_data(obj);
|
||||||
|
const struct nf_conntrack_helper *helper = priv->helper4;
|
||||||
|
u16 family;
|
||||||
|
|
||||||
|
if (nla_put_string(skb, NFTA_CT_HELPER_NAME, helper->name))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (nla_put_u8(skb, NFTA_CT_HELPER_L4PROTO, priv->l4proto))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (priv->helper4 && priv->helper6)
|
||||||
|
family = NFPROTO_INET;
|
||||||
|
else if (priv->helper6)
|
||||||
|
family = NFPROTO_IPV6;
|
||||||
|
else
|
||||||
|
family = NFPROTO_IPV4;
|
||||||
|
|
||||||
|
if (nla_put_be16(skb, NFTA_CT_HELPER_L3PROTO, htons(family)))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct nla_policy nft_ct_helper_policy[NFTA_CT_HELPER_MAX + 1] = {
|
||||||
|
[NFTA_CT_HELPER_NAME] = { .type = NLA_STRING,
|
||||||
|
.len = NF_CT_HELPER_NAME_LEN - 1 },
|
||||||
|
[NFTA_CT_HELPER_L3PROTO] = { .type = NLA_U16 },
|
||||||
|
[NFTA_CT_HELPER_L4PROTO] = { .type = NLA_U8 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct nft_object_type nft_ct_helper_obj __read_mostly = {
|
||||||
|
.type = NFT_OBJECT_CT_HELPER,
|
||||||
|
.size = sizeof(struct nft_ct_helper_obj),
|
||||||
|
.maxattr = NFTA_CT_HELPER_MAX,
|
||||||
|
.policy = nft_ct_helper_policy,
|
||||||
|
.eval = nft_ct_helper_obj_eval,
|
||||||
|
.init = nft_ct_helper_obj_init,
|
||||||
|
.destroy = nft_ct_helper_obj_destroy,
|
||||||
|
.dump = nft_ct_helper_obj_dump,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
static int __init nft_ct_module_init(void)
|
static int __init nft_ct_module_init(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
@ -744,7 +906,14 @@ static int __init nft_ct_module_init(void)
|
|||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto err1;
|
goto err1;
|
||||||
|
|
||||||
|
err = nft_register_obj(&nft_ct_helper_obj);
|
||||||
|
if (err < 0)
|
||||||
|
goto err2;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
err2:
|
||||||
|
nft_unregister_expr(&nft_notrack_type);
|
||||||
err1:
|
err1:
|
||||||
nft_unregister_expr(&nft_ct_type);
|
nft_unregister_expr(&nft_ct_type);
|
||||||
return err;
|
return err;
|
||||||
@ -752,6 +921,7 @@ err1:
|
|||||||
|
|
||||||
static void __exit nft_ct_module_exit(void)
|
static void __exit nft_ct_module_exit(void)
|
||||||
{
|
{
|
||||||
|
nft_unregister_obj(&nft_ct_helper_obj);
|
||||||
nft_unregister_expr(&nft_notrack_type);
|
nft_unregister_expr(&nft_notrack_type);
|
||||||
nft_unregister_expr(&nft_ct_type);
|
nft_unregister_expr(&nft_ct_type);
|
||||||
}
|
}
|
||||||
@ -763,3 +933,4 @@ MODULE_LICENSE("GPL");
|
|||||||
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
|
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
|
||||||
MODULE_ALIAS_NFT_EXPR("ct");
|
MODULE_ALIAS_NFT_EXPR("ct");
|
||||||
MODULE_ALIAS_NFT_EXPR("notrack");
|
MODULE_ALIAS_NFT_EXPR("notrack");
|
||||||
|
MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_CT_HELPER);
|
||||||
|
@ -133,16 +133,10 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
|
|||||||
priv->invert = true;
|
priv->invert = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
set = nf_tables_set_lookup(ctx->table, tb[NFTA_DYNSET_SET_NAME],
|
set = nft_set_lookup(ctx->net, ctx->table, tb[NFTA_DYNSET_SET_NAME],
|
||||||
genmask);
|
tb[NFTA_DYNSET_SET_ID], genmask);
|
||||||
if (IS_ERR(set)) {
|
if (IS_ERR(set))
|
||||||
if (tb[NFTA_DYNSET_SET_ID])
|
return PTR_ERR(set);
|
||||||
set = nf_tables_set_lookup_byid(ctx->net,
|
|
||||||
tb[NFTA_DYNSET_SET_ID],
|
|
||||||
genmask);
|
|
||||||
if (IS_ERR(set))
|
|
||||||
return PTR_ERR(set);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (set->ops->update == NULL)
|
if (set->ops->update == NULL)
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
@ -98,14 +98,21 @@ static void nft_exthdr_tcp_eval(const struct nft_expr *expr,
|
|||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
offset = i + priv->offset;
|
offset = i + priv->offset;
|
||||||
dest[priv->len / NFT_REG32_SIZE] = 0;
|
if (priv->flags & NFT_EXTHDR_F_PRESENT) {
|
||||||
memcpy(dest, opt + offset, priv->len);
|
*dest = 1;
|
||||||
|
} else {
|
||||||
|
dest[priv->len / NFT_REG32_SIZE] = 0;
|
||||||
|
memcpy(dest, opt + offset, priv->len);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
err:
|
err:
|
||||||
regs->verdict.code = NFT_BREAK;
|
if (priv->flags & NFT_EXTHDR_F_PRESENT)
|
||||||
|
*dest = 0;
|
||||||
|
else
|
||||||
|
regs->verdict.code = NFT_BREAK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct nla_policy nft_exthdr_policy[NFTA_EXTHDR_MAX + 1] = {
|
static const struct nla_policy nft_exthdr_policy[NFTA_EXTHDR_MAX + 1] = {
|
||||||
|
@ -24,7 +24,8 @@ const struct nla_policy nft_fib_policy[NFTA_FIB_MAX + 1] = {
|
|||||||
EXPORT_SYMBOL(nft_fib_policy);
|
EXPORT_SYMBOL(nft_fib_policy);
|
||||||
|
|
||||||
#define NFTA_FIB_F_ALL (NFTA_FIB_F_SADDR | NFTA_FIB_F_DADDR | \
|
#define NFTA_FIB_F_ALL (NFTA_FIB_F_SADDR | NFTA_FIB_F_DADDR | \
|
||||||
NFTA_FIB_F_MARK | NFTA_FIB_F_IIF | NFTA_FIB_F_OIF)
|
NFTA_FIB_F_MARK | NFTA_FIB_F_IIF | NFTA_FIB_F_OIF | \
|
||||||
|
NFTA_FIB_F_PRESENT)
|
||||||
|
|
||||||
int nft_fib_validate(const struct nft_ctx *ctx, const struct nft_expr *expr,
|
int nft_fib_validate(const struct nft_ctx *ctx, const struct nft_expr *expr,
|
||||||
const struct nft_data **data)
|
const struct nft_data **data)
|
||||||
@ -112,7 +113,7 @@ int nft_fib_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
|
|||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
return nft_fib_validate(ctx, expr, NULL);
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nft_fib_init);
|
EXPORT_SYMBOL_GPL(nft_fib_init);
|
||||||
|
|
||||||
@ -133,19 +134,22 @@ int nft_fib_dump(struct sk_buff *skb, const struct nft_expr *expr)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nft_fib_dump);
|
EXPORT_SYMBOL_GPL(nft_fib_dump);
|
||||||
|
|
||||||
void nft_fib_store_result(void *reg, enum nft_fib_result r,
|
void nft_fib_store_result(void *reg, const struct nft_fib *priv,
|
||||||
const struct nft_pktinfo *pkt, int index)
|
const struct nft_pktinfo *pkt, int index)
|
||||||
{
|
{
|
||||||
struct net_device *dev;
|
struct net_device *dev;
|
||||||
u32 *dreg = reg;
|
u32 *dreg = reg;
|
||||||
|
|
||||||
switch (r) {
|
switch (priv->result) {
|
||||||
case NFT_FIB_RESULT_OIF:
|
case NFT_FIB_RESULT_OIF:
|
||||||
*dreg = index;
|
*dreg = (priv->flags & NFTA_FIB_F_PRESENT) ? !!index : index;
|
||||||
break;
|
break;
|
||||||
case NFT_FIB_RESULT_OIFNAME:
|
case NFT_FIB_RESULT_OIFNAME:
|
||||||
dev = dev_get_by_index_rcu(nft_net(pkt), index);
|
dev = dev_get_by_index_rcu(nft_net(pkt), index);
|
||||||
strncpy(reg, dev ? dev->name : "", IFNAMSIZ);
|
if (priv->flags & NFTA_FIB_F_PRESENT)
|
||||||
|
*dreg = !!dev;
|
||||||
|
else
|
||||||
|
strncpy(reg, dev ? dev->name : "", IFNAMSIZ);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
WARN_ON_ONCE(1);
|
WARN_ON_ONCE(1);
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
#include <net/netfilter/nf_tables_core.h>
|
#include <net/netfilter/nf_tables_core.h>
|
||||||
#include <linux/jhash.h>
|
#include <linux/jhash.h>
|
||||||
|
|
||||||
struct nft_hash {
|
struct nft_jhash {
|
||||||
enum nft_registers sreg:8;
|
enum nft_registers sreg:8;
|
||||||
enum nft_registers dreg:8;
|
enum nft_registers dreg:8;
|
||||||
u8 len;
|
u8 len;
|
||||||
@ -26,11 +26,11 @@ struct nft_hash {
|
|||||||
u32 offset;
|
u32 offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void nft_hash_eval(const struct nft_expr *expr,
|
static void nft_jhash_eval(const struct nft_expr *expr,
|
||||||
struct nft_regs *regs,
|
struct nft_regs *regs,
|
||||||
const struct nft_pktinfo *pkt)
|
const struct nft_pktinfo *pkt)
|
||||||
{
|
{
|
||||||
struct nft_hash *priv = nft_expr_priv(expr);
|
struct nft_jhash *priv = nft_expr_priv(expr);
|
||||||
const void *data = ®s->data[priv->sreg];
|
const void *data = ®s->data[priv->sreg];
|
||||||
u32 h;
|
u32 h;
|
||||||
|
|
||||||
@ -38,6 +38,25 @@ static void nft_hash_eval(const struct nft_expr *expr,
|
|||||||
regs->data[priv->dreg] = h + priv->offset;
|
regs->data[priv->dreg] = h + priv->offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct nft_symhash {
|
||||||
|
enum nft_registers dreg:8;
|
||||||
|
u32 modulus;
|
||||||
|
u32 offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void nft_symhash_eval(const struct nft_expr *expr,
|
||||||
|
struct nft_regs *regs,
|
||||||
|
const struct nft_pktinfo *pkt)
|
||||||
|
{
|
||||||
|
struct nft_symhash *priv = nft_expr_priv(expr);
|
||||||
|
struct sk_buff *skb = pkt->skb;
|
||||||
|
u32 h;
|
||||||
|
|
||||||
|
h = reciprocal_scale(__skb_get_hash_symmetric(skb), priv->modulus);
|
||||||
|
|
||||||
|
regs->data[priv->dreg] = h + priv->offset;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct nla_policy nft_hash_policy[NFTA_HASH_MAX + 1] = {
|
static const struct nla_policy nft_hash_policy[NFTA_HASH_MAX + 1] = {
|
||||||
[NFTA_HASH_SREG] = { .type = NLA_U32 },
|
[NFTA_HASH_SREG] = { .type = NLA_U32 },
|
||||||
[NFTA_HASH_DREG] = { .type = NLA_U32 },
|
[NFTA_HASH_DREG] = { .type = NLA_U32 },
|
||||||
@ -45,13 +64,14 @@ static const struct nla_policy nft_hash_policy[NFTA_HASH_MAX + 1] = {
|
|||||||
[NFTA_HASH_MODULUS] = { .type = NLA_U32 },
|
[NFTA_HASH_MODULUS] = { .type = NLA_U32 },
|
||||||
[NFTA_HASH_SEED] = { .type = NLA_U32 },
|
[NFTA_HASH_SEED] = { .type = NLA_U32 },
|
||||||
[NFTA_HASH_OFFSET] = { .type = NLA_U32 },
|
[NFTA_HASH_OFFSET] = { .type = NLA_U32 },
|
||||||
|
[NFTA_HASH_TYPE] = { .type = NLA_U32 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static int nft_hash_init(const struct nft_ctx *ctx,
|
static int nft_jhash_init(const struct nft_ctx *ctx,
|
||||||
const struct nft_expr *expr,
|
const struct nft_expr *expr,
|
||||||
const struct nlattr * const tb[])
|
const struct nlattr * const tb[])
|
||||||
{
|
{
|
||||||
struct nft_hash *priv = nft_expr_priv(expr);
|
struct nft_jhash *priv = nft_expr_priv(expr);
|
||||||
u32 len;
|
u32 len;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
@ -92,10 +112,36 @@ static int nft_hash_init(const struct nft_ctx *ctx,
|
|||||||
NFT_DATA_VALUE, sizeof(u32));
|
NFT_DATA_VALUE, sizeof(u32));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nft_hash_dump(struct sk_buff *skb,
|
static int nft_symhash_init(const struct nft_ctx *ctx,
|
||||||
const struct nft_expr *expr)
|
const struct nft_expr *expr,
|
||||||
|
const struct nlattr * const tb[])
|
||||||
{
|
{
|
||||||
const struct nft_hash *priv = nft_expr_priv(expr);
|
struct nft_symhash *priv = nft_expr_priv(expr);
|
||||||
|
|
||||||
|
if (!tb[NFTA_HASH_DREG] ||
|
||||||
|
!tb[NFTA_HASH_MODULUS])
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (tb[NFTA_HASH_OFFSET])
|
||||||
|
priv->offset = ntohl(nla_get_be32(tb[NFTA_HASH_OFFSET]));
|
||||||
|
|
||||||
|
priv->dreg = nft_parse_register(tb[NFTA_HASH_DREG]);
|
||||||
|
|
||||||
|
priv->modulus = ntohl(nla_get_be32(tb[NFTA_HASH_MODULUS]));
|
||||||
|
if (priv->modulus <= 1)
|
||||||
|
return -ERANGE;
|
||||||
|
|
||||||
|
if (priv->offset + priv->modulus - 1 < priv->offset)
|
||||||
|
return -EOVERFLOW;
|
||||||
|
|
||||||
|
return nft_validate_register_store(ctx, priv->dreg, NULL,
|
||||||
|
NFT_DATA_VALUE, sizeof(u32));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nft_jhash_dump(struct sk_buff *skb,
|
||||||
|
const struct nft_expr *expr)
|
||||||
|
{
|
||||||
|
const struct nft_jhash *priv = nft_expr_priv(expr);
|
||||||
|
|
||||||
if (nft_dump_register(skb, NFTA_HASH_SREG, priv->sreg))
|
if (nft_dump_register(skb, NFTA_HASH_SREG, priv->sreg))
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
@ -110,6 +156,28 @@ static int nft_hash_dump(struct sk_buff *skb,
|
|||||||
if (priv->offset != 0)
|
if (priv->offset != 0)
|
||||||
if (nla_put_be32(skb, NFTA_HASH_OFFSET, htonl(priv->offset)))
|
if (nla_put_be32(skb, NFTA_HASH_OFFSET, htonl(priv->offset)))
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
|
if (nla_put_be32(skb, NFTA_HASH_TYPE, htonl(NFT_HASH_JENKINS)))
|
||||||
|
goto nla_put_failure;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
nla_put_failure:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nft_symhash_dump(struct sk_buff *skb,
|
||||||
|
const struct nft_expr *expr)
|
||||||
|
{
|
||||||
|
const struct nft_symhash *priv = nft_expr_priv(expr);
|
||||||
|
|
||||||
|
if (nft_dump_register(skb, NFTA_HASH_DREG, priv->dreg))
|
||||||
|
goto nla_put_failure;
|
||||||
|
if (nla_put_be32(skb, NFTA_HASH_MODULUS, htonl(priv->modulus)))
|
||||||
|
goto nla_put_failure;
|
||||||
|
if (priv->offset != 0)
|
||||||
|
if (nla_put_be32(skb, NFTA_HASH_OFFSET, htonl(priv->offset)))
|
||||||
|
goto nla_put_failure;
|
||||||
|
if (nla_put_be32(skb, NFTA_HASH_TYPE, htonl(NFT_HASH_SYM)))
|
||||||
|
goto nla_put_failure;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
nla_put_failure:
|
nla_put_failure:
|
||||||
@ -117,17 +185,46 @@ nla_put_failure:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct nft_expr_type nft_hash_type;
|
static struct nft_expr_type nft_hash_type;
|
||||||
static const struct nft_expr_ops nft_hash_ops = {
|
static const struct nft_expr_ops nft_jhash_ops = {
|
||||||
.type = &nft_hash_type,
|
.type = &nft_hash_type,
|
||||||
.size = NFT_EXPR_SIZE(sizeof(struct nft_hash)),
|
.size = NFT_EXPR_SIZE(sizeof(struct nft_jhash)),
|
||||||
.eval = nft_hash_eval,
|
.eval = nft_jhash_eval,
|
||||||
.init = nft_hash_init,
|
.init = nft_jhash_init,
|
||||||
.dump = nft_hash_dump,
|
.dump = nft_jhash_dump,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct nft_expr_ops nft_symhash_ops = {
|
||||||
|
.type = &nft_hash_type,
|
||||||
|
.size = NFT_EXPR_SIZE(sizeof(struct nft_symhash)),
|
||||||
|
.eval = nft_symhash_eval,
|
||||||
|
.init = nft_symhash_init,
|
||||||
|
.dump = nft_symhash_dump,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct nft_expr_ops *
|
||||||
|
nft_hash_select_ops(const struct nft_ctx *ctx,
|
||||||
|
const struct nlattr * const tb[])
|
||||||
|
{
|
||||||
|
u32 type;
|
||||||
|
|
||||||
|
if (!tb[NFTA_HASH_TYPE])
|
||||||
|
return &nft_jhash_ops;
|
||||||
|
|
||||||
|
type = ntohl(nla_get_be32(tb[NFTA_HASH_TYPE]));
|
||||||
|
switch (type) {
|
||||||
|
case NFT_HASH_SYM:
|
||||||
|
return &nft_symhash_ops;
|
||||||
|
case NFT_HASH_JENKINS:
|
||||||
|
return &nft_jhash_ops;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ERR_PTR(-EOPNOTSUPP);
|
||||||
|
}
|
||||||
|
|
||||||
static struct nft_expr_type nft_hash_type __read_mostly = {
|
static struct nft_expr_type nft_hash_type __read_mostly = {
|
||||||
.name = "hash",
|
.name = "hash",
|
||||||
.ops = &nft_hash_ops,
|
.select_ops = &nft_hash_select_ops,
|
||||||
.policy = nft_hash_policy,
|
.policy = nft_hash_policy,
|
||||||
.maxattr = NFTA_HASH_MAX,
|
.maxattr = NFTA_HASH_MAX,
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
|
@ -17,9 +17,8 @@
|
|||||||
#include <linux/netfilter/nf_tables.h>
|
#include <linux/netfilter/nf_tables.h>
|
||||||
#include <net/netfilter/nf_tables.h>
|
#include <net/netfilter/nf_tables.h>
|
||||||
|
|
||||||
static DEFINE_SPINLOCK(limit_lock);
|
|
||||||
|
|
||||||
struct nft_limit {
|
struct nft_limit {
|
||||||
|
spinlock_t lock;
|
||||||
u64 last;
|
u64 last;
|
||||||
u64 tokens;
|
u64 tokens;
|
||||||
u64 tokens_max;
|
u64 tokens_max;
|
||||||
@ -34,7 +33,7 @@ static inline bool nft_limit_eval(struct nft_limit *limit, u64 cost)
|
|||||||
u64 now, tokens;
|
u64 now, tokens;
|
||||||
s64 delta;
|
s64 delta;
|
||||||
|
|
||||||
spin_lock_bh(&limit_lock);
|
spin_lock_bh(&limit->lock);
|
||||||
now = ktime_get_ns();
|
now = ktime_get_ns();
|
||||||
tokens = limit->tokens + now - limit->last;
|
tokens = limit->tokens + now - limit->last;
|
||||||
if (tokens > limit->tokens_max)
|
if (tokens > limit->tokens_max)
|
||||||
@ -44,11 +43,11 @@ static inline bool nft_limit_eval(struct nft_limit *limit, u64 cost)
|
|||||||
delta = tokens - cost;
|
delta = tokens - cost;
|
||||||
if (delta >= 0) {
|
if (delta >= 0) {
|
||||||
limit->tokens = delta;
|
limit->tokens = delta;
|
||||||
spin_unlock_bh(&limit_lock);
|
spin_unlock_bh(&limit->lock);
|
||||||
return limit->invert;
|
return limit->invert;
|
||||||
}
|
}
|
||||||
limit->tokens = tokens;
|
limit->tokens = tokens;
|
||||||
spin_unlock_bh(&limit_lock);
|
spin_unlock_bh(&limit->lock);
|
||||||
return !limit->invert;
|
return !limit->invert;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,6 +85,7 @@ static int nft_limit_init(struct nft_limit *limit,
|
|||||||
limit->invert = true;
|
limit->invert = true;
|
||||||
}
|
}
|
||||||
limit->last = ktime_get_ns();
|
limit->last = ktime_get_ns();
|
||||||
|
spin_lock_init(&limit->lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -71,16 +71,10 @@ static int nft_lookup_init(const struct nft_ctx *ctx,
|
|||||||
tb[NFTA_LOOKUP_SREG] == NULL)
|
tb[NFTA_LOOKUP_SREG] == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
set = nf_tables_set_lookup(ctx->table, tb[NFTA_LOOKUP_SET], genmask);
|
set = nft_set_lookup(ctx->net, ctx->table, tb[NFTA_LOOKUP_SET],
|
||||||
if (IS_ERR(set)) {
|
tb[NFTA_LOOKUP_SET_ID], genmask);
|
||||||
if (tb[NFTA_LOOKUP_SET_ID]) {
|
if (IS_ERR(set))
|
||||||
set = nf_tables_set_lookup_byid(ctx->net,
|
return PTR_ERR(set);
|
||||||
tb[NFTA_LOOKUP_SET_ID],
|
|
||||||
genmask);
|
|
||||||
}
|
|
||||||
if (IS_ERR(set))
|
|
||||||
return PTR_ERR(set);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (set->flags & NFT_SET_EVAL)
|
if (set->flags & NFT_SET_EVAL)
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
@ -46,10 +46,6 @@ int nft_masq_init(const struct nft_ctx *ctx,
|
|||||||
struct nft_masq *priv = nft_expr_priv(expr);
|
struct nft_masq *priv = nft_expr_priv(expr);
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = nft_masq_validate(ctx, expr, NULL);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
if (tb[NFTA_MASQ_FLAGS]) {
|
if (tb[NFTA_MASQ_FLAGS]) {
|
||||||
priv->flags = ntohl(nla_get_be32(tb[NFTA_MASQ_FLAGS]));
|
priv->flags = ntohl(nla_get_be32(tb[NFTA_MASQ_FLAGS]));
|
||||||
if (priv->flags & ~NF_NAT_RANGE_MASK)
|
if (priv->flags & ~NF_NAT_RANGE_MASK)
|
||||||
|
@ -370,10 +370,6 @@ int nft_meta_set_init(const struct nft_ctx *ctx,
|
|||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = nft_meta_set_validate(ctx, expr, NULL);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
priv->sreg = nft_parse_register(tb[NFTA_META_SREG]);
|
priv->sreg = nft_parse_register(tb[NFTA_META_SREG]);
|
||||||
err = nft_validate_register_load(priv->sreg, len);
|
err = nft_validate_register_load(priv->sreg, len);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
|
@ -138,10 +138,6 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = nft_nat_validate(ctx, expr, NULL);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
if (tb[NFTA_NAT_FAMILY] == NULL)
|
if (tb[NFTA_NAT_FAMILY] == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
@ -116,16 +116,10 @@ static int nft_objref_map_init(const struct nft_ctx *ctx,
|
|||||||
struct nft_set *set;
|
struct nft_set *set;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
set = nf_tables_set_lookup(ctx->table, tb[NFTA_OBJREF_SET_NAME], genmask);
|
set = nft_set_lookup(ctx->net, ctx->table, tb[NFTA_OBJREF_SET_NAME],
|
||||||
if (IS_ERR(set)) {
|
tb[NFTA_OBJREF_SET_ID], genmask);
|
||||||
if (tb[NFTA_OBJREF_SET_ID]) {
|
if (IS_ERR(set))
|
||||||
set = nf_tables_set_lookup_byid(ctx->net,
|
return PTR_ERR(set);
|
||||||
tb[NFTA_OBJREF_SET_ID],
|
|
||||||
genmask);
|
|
||||||
}
|
|
||||||
if (IS_ERR(set))
|
|
||||||
return PTR_ERR(set);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(set->flags & NFT_SET_OBJECT))
|
if (!(set->flags & NFT_SET_OBJECT))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -99,7 +99,8 @@ static int nft_quota_do_init(const struct nlattr * const tb[],
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nft_quota_obj_init(const struct nlattr * const tb[],
|
static int nft_quota_obj_init(const struct nft_ctx *ctx,
|
||||||
|
const struct nlattr * const tb[],
|
||||||
struct nft_object *obj)
|
struct nft_object *obj)
|
||||||
{
|
{
|
||||||
struct nft_quota *priv = nft_obj_data(obj);
|
struct nft_quota *priv = nft_obj_data(obj);
|
||||||
|
@ -47,10 +47,6 @@ int nft_redir_init(const struct nft_ctx *ctx,
|
|||||||
unsigned int plen;
|
unsigned int plen;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = nft_redir_validate(ctx, expr, NULL);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
plen = FIELD_SIZEOF(struct nf_nat_range, min_addr.all);
|
plen = FIELD_SIZEOF(struct nf_nat_range, min_addr.all);
|
||||||
if (tb[NFTA_REDIR_REG_PROTO_MIN]) {
|
if (tb[NFTA_REDIR_REG_PROTO_MIN]) {
|
||||||
priv->sreg_proto_min =
|
priv->sreg_proto_min =
|
||||||
|
@ -42,11 +42,6 @@ int nft_reject_init(const struct nft_ctx *ctx,
|
|||||||
const struct nlattr * const tb[])
|
const struct nlattr * const tb[])
|
||||||
{
|
{
|
||||||
struct nft_reject *priv = nft_expr_priv(expr);
|
struct nft_reject *priv = nft_expr_priv(expr);
|
||||||
int err;
|
|
||||||
|
|
||||||
err = nft_reject_validate(ctx, expr, NULL);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
if (tb[NFTA_REJECT_TYPE] == NULL)
|
if (tb[NFTA_REJECT_TYPE] == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -66,11 +66,7 @@ static int nft_reject_inet_init(const struct nft_ctx *ctx,
|
|||||||
const struct nlattr * const tb[])
|
const struct nlattr * const tb[])
|
||||||
{
|
{
|
||||||
struct nft_reject *priv = nft_expr_priv(expr);
|
struct nft_reject *priv = nft_expr_priv(expr);
|
||||||
int icmp_code, err;
|
int icmp_code;
|
||||||
|
|
||||||
err = nft_reject_validate(ctx, expr, NULL);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
if (tb[NFTA_REJECT_TYPE] == NULL)
|
if (tb[NFTA_REJECT_TYPE] == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -18,9 +18,8 @@
|
|||||||
#include <linux/netfilter/nf_tables.h>
|
#include <linux/netfilter/nf_tables.h>
|
||||||
#include <net/netfilter/nf_tables.h>
|
#include <net/netfilter/nf_tables.h>
|
||||||
|
|
||||||
static DEFINE_SPINLOCK(nft_rbtree_lock);
|
|
||||||
|
|
||||||
struct nft_rbtree {
|
struct nft_rbtree {
|
||||||
|
rwlock_t lock;
|
||||||
struct rb_root root;
|
struct rb_root root;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -44,14 +43,14 @@ static bool nft_rbtree_equal(const struct nft_set *set, const void *this,
|
|||||||
static bool nft_rbtree_lookup(const struct net *net, const struct nft_set *set,
|
static bool nft_rbtree_lookup(const struct net *net, const struct nft_set *set,
|
||||||
const u32 *key, const struct nft_set_ext **ext)
|
const u32 *key, const struct nft_set_ext **ext)
|
||||||
{
|
{
|
||||||
const struct nft_rbtree *priv = nft_set_priv(set);
|
struct nft_rbtree *priv = nft_set_priv(set);
|
||||||
const struct nft_rbtree_elem *rbe, *interval = NULL;
|
const struct nft_rbtree_elem *rbe, *interval = NULL;
|
||||||
u8 genmask = nft_genmask_cur(net);
|
u8 genmask = nft_genmask_cur(net);
|
||||||
const struct rb_node *parent;
|
const struct rb_node *parent;
|
||||||
const void *this;
|
const void *this;
|
||||||
int d;
|
int d;
|
||||||
|
|
||||||
spin_lock_bh(&nft_rbtree_lock);
|
read_lock_bh(&priv->lock);
|
||||||
parent = priv->root.rb_node;
|
parent = priv->root.rb_node;
|
||||||
while (parent != NULL) {
|
while (parent != NULL) {
|
||||||
rbe = rb_entry(parent, struct nft_rbtree_elem, node);
|
rbe = rb_entry(parent, struct nft_rbtree_elem, node);
|
||||||
@ -75,7 +74,7 @@ static bool nft_rbtree_lookup(const struct net *net, const struct nft_set *set,
|
|||||||
}
|
}
|
||||||
if (nft_rbtree_interval_end(rbe))
|
if (nft_rbtree_interval_end(rbe))
|
||||||
goto out;
|
goto out;
|
||||||
spin_unlock_bh(&nft_rbtree_lock);
|
read_unlock_bh(&priv->lock);
|
||||||
|
|
||||||
*ext = &rbe->ext;
|
*ext = &rbe->ext;
|
||||||
return true;
|
return true;
|
||||||
@ -85,12 +84,12 @@ static bool nft_rbtree_lookup(const struct net *net, const struct nft_set *set,
|
|||||||
if (set->flags & NFT_SET_INTERVAL && interval != NULL &&
|
if (set->flags & NFT_SET_INTERVAL && interval != NULL &&
|
||||||
nft_set_elem_active(&interval->ext, genmask) &&
|
nft_set_elem_active(&interval->ext, genmask) &&
|
||||||
!nft_rbtree_interval_end(interval)) {
|
!nft_rbtree_interval_end(interval)) {
|
||||||
spin_unlock_bh(&nft_rbtree_lock);
|
read_unlock_bh(&priv->lock);
|
||||||
*ext = &interval->ext;
|
*ext = &interval->ext;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
spin_unlock_bh(&nft_rbtree_lock);
|
read_unlock_bh(&priv->lock);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,12 +139,13 @@ static int nft_rbtree_insert(const struct net *net, const struct nft_set *set,
|
|||||||
const struct nft_set_elem *elem,
|
const struct nft_set_elem *elem,
|
||||||
struct nft_set_ext **ext)
|
struct nft_set_ext **ext)
|
||||||
{
|
{
|
||||||
|
struct nft_rbtree *priv = nft_set_priv(set);
|
||||||
struct nft_rbtree_elem *rbe = elem->priv;
|
struct nft_rbtree_elem *rbe = elem->priv;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
spin_lock_bh(&nft_rbtree_lock);
|
write_lock_bh(&priv->lock);
|
||||||
err = __nft_rbtree_insert(net, set, rbe, ext);
|
err = __nft_rbtree_insert(net, set, rbe, ext);
|
||||||
spin_unlock_bh(&nft_rbtree_lock);
|
write_unlock_bh(&priv->lock);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -157,9 +157,9 @@ static void nft_rbtree_remove(const struct net *net,
|
|||||||
struct nft_rbtree *priv = nft_set_priv(set);
|
struct nft_rbtree *priv = nft_set_priv(set);
|
||||||
struct nft_rbtree_elem *rbe = elem->priv;
|
struct nft_rbtree_elem *rbe = elem->priv;
|
||||||
|
|
||||||
spin_lock_bh(&nft_rbtree_lock);
|
write_lock_bh(&priv->lock);
|
||||||
rb_erase(&rbe->node, &priv->root);
|
rb_erase(&rbe->node, &priv->root);
|
||||||
spin_unlock_bh(&nft_rbtree_lock);
|
write_unlock_bh(&priv->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nft_rbtree_activate(const struct net *net,
|
static void nft_rbtree_activate(const struct net *net,
|
||||||
@ -224,12 +224,12 @@ static void nft_rbtree_walk(const struct nft_ctx *ctx,
|
|||||||
struct nft_set *set,
|
struct nft_set *set,
|
||||||
struct nft_set_iter *iter)
|
struct nft_set_iter *iter)
|
||||||
{
|
{
|
||||||
const struct nft_rbtree *priv = nft_set_priv(set);
|
struct nft_rbtree *priv = nft_set_priv(set);
|
||||||
struct nft_rbtree_elem *rbe;
|
struct nft_rbtree_elem *rbe;
|
||||||
struct nft_set_elem elem;
|
struct nft_set_elem elem;
|
||||||
struct rb_node *node;
|
struct rb_node *node;
|
||||||
|
|
||||||
spin_lock_bh(&nft_rbtree_lock);
|
read_lock_bh(&priv->lock);
|
||||||
for (node = rb_first(&priv->root); node != NULL; node = rb_next(node)) {
|
for (node = rb_first(&priv->root); node != NULL; node = rb_next(node)) {
|
||||||
rbe = rb_entry(node, struct nft_rbtree_elem, node);
|
rbe = rb_entry(node, struct nft_rbtree_elem, node);
|
||||||
|
|
||||||
@ -242,13 +242,13 @@ static void nft_rbtree_walk(const struct nft_ctx *ctx,
|
|||||||
|
|
||||||
iter->err = iter->fn(ctx, set, iter, &elem);
|
iter->err = iter->fn(ctx, set, iter, &elem);
|
||||||
if (iter->err < 0) {
|
if (iter->err < 0) {
|
||||||
spin_unlock_bh(&nft_rbtree_lock);
|
read_unlock_bh(&priv->lock);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
cont:
|
cont:
|
||||||
iter->count++;
|
iter->count++;
|
||||||
}
|
}
|
||||||
spin_unlock_bh(&nft_rbtree_lock);
|
read_unlock_bh(&priv->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int nft_rbtree_privsize(const struct nlattr * const nla[])
|
static unsigned int nft_rbtree_privsize(const struct nlattr * const nla[])
|
||||||
@ -262,6 +262,7 @@ static int nft_rbtree_init(const struct nft_set *set,
|
|||||||
{
|
{
|
||||||
struct nft_rbtree *priv = nft_set_priv(set);
|
struct nft_rbtree *priv = nft_set_priv(set);
|
||||||
|
|
||||||
|
rwlock_init(&priv->lock);
|
||||||
priv->root = RB_ROOT;
|
priv->root = RB_ROOT;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include <linux/netfilter/xt_limit.h>
|
#include <linux/netfilter/xt_limit.h>
|
||||||
|
|
||||||
struct xt_limit_priv {
|
struct xt_limit_priv {
|
||||||
|
spinlock_t lock;
|
||||||
unsigned long prev;
|
unsigned long prev;
|
||||||
uint32_t credit;
|
uint32_t credit;
|
||||||
};
|
};
|
||||||
@ -32,8 +33,6 @@ MODULE_ALIAS("ip6t_limit");
|
|||||||
* see net/sched/sch_tbf.c in the linux source tree
|
* see net/sched/sch_tbf.c in the linux source tree
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static DEFINE_SPINLOCK(limit_lock);
|
|
||||||
|
|
||||||
/* Rusty: This is my (non-mathematically-inclined) understanding of
|
/* Rusty: This is my (non-mathematically-inclined) understanding of
|
||||||
this algorithm. The `average rate' in jiffies becomes your initial
|
this algorithm. The `average rate' in jiffies becomes your initial
|
||||||
amount of credit `credit' and the most credit you can ever have
|
amount of credit `credit' and the most credit you can ever have
|
||||||
@ -72,7 +71,7 @@ limit_mt(const struct sk_buff *skb, struct xt_action_param *par)
|
|||||||
struct xt_limit_priv *priv = r->master;
|
struct xt_limit_priv *priv = r->master;
|
||||||
unsigned long now = jiffies;
|
unsigned long now = jiffies;
|
||||||
|
|
||||||
spin_lock_bh(&limit_lock);
|
spin_lock_bh(&priv->lock);
|
||||||
priv->credit += (now - xchg(&priv->prev, now)) * CREDITS_PER_JIFFY;
|
priv->credit += (now - xchg(&priv->prev, now)) * CREDITS_PER_JIFFY;
|
||||||
if (priv->credit > r->credit_cap)
|
if (priv->credit > r->credit_cap)
|
||||||
priv->credit = r->credit_cap;
|
priv->credit = r->credit_cap;
|
||||||
@ -80,11 +79,11 @@ limit_mt(const struct sk_buff *skb, struct xt_action_param *par)
|
|||||||
if (priv->credit >= r->cost) {
|
if (priv->credit >= r->cost) {
|
||||||
/* We're not limited. */
|
/* We're not limited. */
|
||||||
priv->credit -= r->cost;
|
priv->credit -= r->cost;
|
||||||
spin_unlock_bh(&limit_lock);
|
spin_unlock_bh(&priv->lock);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock_bh(&limit_lock);
|
spin_unlock_bh(&priv->lock);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,6 +125,8 @@ static int limit_mt_check(const struct xt_mtchk_param *par)
|
|||||||
r->credit_cap = priv->credit; /* Credits full. */
|
r->credit_cap = priv->credit; /* Credits full. */
|
||||||
r->cost = user2credits(r->avg);
|
r->cost = user2credits(r->avg);
|
||||||
}
|
}
|
||||||
|
spin_lock_init(&priv->lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user