Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next
Pablo Neira Ayuso says: ==================== Netfilter updates for net-next The following patchset contains Netfilter updates for net-next: 1) Support for SCTP chunks matching on nf_tables, from Phil Sutter. 2) Skip LDMXCSR, we don't need a valid MXCSR state. From Stefano Brivio. 3) CONFIG_RETPOLINE for nf_tables set lookups, from Florian Westphal. 4) A few Kconfig leading spaces removal, from Juerg Haefliger. 5) Remove spinlock from xt_limit, from Jason Baron. 6) Remove useless initialization in xt_CT, oneliner from Yang Li. 7) Tree-wide replacement of netlink_unicast() by nfnetlink_unicast(). 8) Reduce footprint of several structures: xt_action_param, nft_pktinfo and nf_hook_state, from Florian. 10) Add nft_thoff() and nft_sk() helpers and use them, also from Florian. 11) Fix documentation in nf_tables pipapo avx2, from Florian Westphal. 12) Fix clang-12 fmt string warnings, also from Florian. ====================
This commit is contained in:
Коммит
5fe8e519e4
|
@ -65,8 +65,8 @@ struct nf_hook_ops;
|
|||
struct sock;
|
||||
|
||||
struct nf_hook_state {
|
||||
unsigned int hook;
|
||||
u_int8_t pf;
|
||||
u8 hook;
|
||||
u8 pf;
|
||||
struct net_device *in;
|
||||
struct net_device *out;
|
||||
struct sock *sk;
|
||||
|
|
|
@ -36,8 +36,8 @@ struct xt_action_param {
|
|||
const void *matchinfo, *targinfo;
|
||||
};
|
||||
const struct nf_hook_state *state;
|
||||
int fragoff;
|
||||
unsigned int thoff;
|
||||
u16 fragoff;
|
||||
bool hotdrop;
|
||||
};
|
||||
|
||||
|
|
|
@ -23,35 +23,46 @@ struct module;
|
|||
|
||||
struct nft_pktinfo {
|
||||
struct sk_buff *skb;
|
||||
const struct nf_hook_state *state;
|
||||
bool tprot_set;
|
||||
u8 tprot;
|
||||
/* for x_tables compatibility */
|
||||
struct xt_action_param xt;
|
||||
u16 fragoff;
|
||||
unsigned int thoff;
|
||||
};
|
||||
|
||||
static inline struct sock *nft_sk(const struct nft_pktinfo *pkt)
|
||||
{
|
||||
return pkt->state->sk;
|
||||
}
|
||||
|
||||
static inline unsigned int nft_thoff(const struct nft_pktinfo *pkt)
|
||||
{
|
||||
return pkt->thoff;
|
||||
}
|
||||
|
||||
static inline struct net *nft_net(const struct nft_pktinfo *pkt)
|
||||
{
|
||||
return pkt->xt.state->net;
|
||||
return pkt->state->net;
|
||||
}
|
||||
|
||||
static inline unsigned int nft_hook(const struct nft_pktinfo *pkt)
|
||||
{
|
||||
return pkt->xt.state->hook;
|
||||
return pkt->state->hook;
|
||||
}
|
||||
|
||||
static inline u8 nft_pf(const struct nft_pktinfo *pkt)
|
||||
{
|
||||
return pkt->xt.state->pf;
|
||||
return pkt->state->pf;
|
||||
}
|
||||
|
||||
static inline const struct net_device *nft_in(const struct nft_pktinfo *pkt)
|
||||
{
|
||||
return pkt->xt.state->in;
|
||||
return pkt->state->in;
|
||||
}
|
||||
|
||||
static inline const struct net_device *nft_out(const struct nft_pktinfo *pkt)
|
||||
{
|
||||
return pkt->xt.state->out;
|
||||
return pkt->state->out;
|
||||
}
|
||||
|
||||
static inline void nft_set_pktinfo(struct nft_pktinfo *pkt,
|
||||
|
@ -59,16 +70,15 @@ static inline void nft_set_pktinfo(struct nft_pktinfo *pkt,
|
|||
const struct nf_hook_state *state)
|
||||
{
|
||||
pkt->skb = skb;
|
||||
pkt->xt.state = state;
|
||||
pkt->state = state;
|
||||
}
|
||||
|
||||
static inline void nft_set_pktinfo_unspec(struct nft_pktinfo *pkt,
|
||||
struct sk_buff *skb)
|
||||
static inline void nft_set_pktinfo_unspec(struct nft_pktinfo *pkt)
|
||||
{
|
||||
pkt->tprot_set = false;
|
||||
pkt->tprot = 0;
|
||||
pkt->xt.thoff = 0;
|
||||
pkt->xt.fragoff = 0;
|
||||
pkt->thoff = 0;
|
||||
pkt->fragoff = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#define _NET_NF_TABLES_CORE_H
|
||||
|
||||
#include <net/netfilter/nf_tables.h>
|
||||
#include <linux/indirect_call_wrapper.h>
|
||||
|
||||
extern struct nft_expr_type nft_imm_type;
|
||||
extern struct nft_expr_type nft_cmp_type;
|
||||
|
@ -88,6 +89,36 @@ extern const struct nft_set_type nft_set_bitmap_type;
|
|||
extern const struct nft_set_type nft_set_pipapo_type;
|
||||
extern const struct nft_set_type nft_set_pipapo_avx2_type;
|
||||
|
||||
#ifdef CONFIG_RETPOLINE
|
||||
bool nft_rhash_lookup(const struct net *net, const struct nft_set *set,
|
||||
const u32 *key, const struct nft_set_ext **ext);
|
||||
bool nft_rbtree_lookup(const struct net *net, const struct nft_set *set,
|
||||
const u32 *key, const struct nft_set_ext **ext);
|
||||
bool nft_bitmap_lookup(const struct net *net, const struct nft_set *set,
|
||||
const u32 *key, const struct nft_set_ext **ext);
|
||||
bool nft_hash_lookup_fast(const struct net *net,
|
||||
const struct nft_set *set,
|
||||
const u32 *key, const struct nft_set_ext **ext);
|
||||
bool nft_hash_lookup(const struct net *net, const struct nft_set *set,
|
||||
const u32 *key, const struct nft_set_ext **ext);
|
||||
bool nft_set_do_lookup(const struct net *net, const struct nft_set *set,
|
||||
const u32 *key, const struct nft_set_ext **ext);
|
||||
#else
|
||||
static inline bool
|
||||
nft_set_do_lookup(const struct net *net, const struct nft_set *set,
|
||||
const u32 *key, const struct nft_set_ext **ext)
|
||||
{
|
||||
return set->ops->lookup(net, set, key, ext);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* called from nft_pipapo_avx2.c */
|
||||
bool nft_pipapo_lookup(const struct net *net, const struct nft_set *set,
|
||||
const u32 *key, const struct nft_set_ext **ext);
|
||||
/* called from nft_set_pipapo.c */
|
||||
bool nft_pipapo_avx2_lookup(const struct net *net, const struct nft_set *set,
|
||||
const u32 *key, const struct nft_set_ext **ext);
|
||||
|
||||
struct nft_expr;
|
||||
struct nft_regs;
|
||||
struct nft_pktinfo;
|
||||
|
|
|
@ -5,26 +5,24 @@
|
|||
#include <net/netfilter/nf_tables.h>
|
||||
#include <net/ip.h>
|
||||
|
||||
static inline void nft_set_pktinfo_ipv4(struct nft_pktinfo *pkt,
|
||||
struct sk_buff *skb)
|
||||
static inline void nft_set_pktinfo_ipv4(struct nft_pktinfo *pkt)
|
||||
{
|
||||
struct iphdr *ip;
|
||||
|
||||
ip = ip_hdr(pkt->skb);
|
||||
pkt->tprot_set = true;
|
||||
pkt->tprot = ip->protocol;
|
||||
pkt->xt.thoff = ip_hdrlen(pkt->skb);
|
||||
pkt->xt.fragoff = ntohs(ip->frag_off) & IP_OFFSET;
|
||||
pkt->thoff = ip_hdrlen(pkt->skb);
|
||||
pkt->fragoff = ntohs(ip->frag_off) & IP_OFFSET;
|
||||
}
|
||||
|
||||
static inline int __nft_set_pktinfo_ipv4_validate(struct nft_pktinfo *pkt,
|
||||
struct sk_buff *skb)
|
||||
static inline int __nft_set_pktinfo_ipv4_validate(struct nft_pktinfo *pkt)
|
||||
{
|
||||
struct iphdr *iph, _iph;
|
||||
u32 len, thoff;
|
||||
|
||||
iph = skb_header_pointer(skb, skb_network_offset(skb), sizeof(*iph),
|
||||
&_iph);
|
||||
iph = skb_header_pointer(pkt->skb, skb_network_offset(pkt->skb),
|
||||
sizeof(*iph), &_iph);
|
||||
if (!iph)
|
||||
return -1;
|
||||
|
||||
|
@ -33,42 +31,40 @@ static inline int __nft_set_pktinfo_ipv4_validate(struct nft_pktinfo *pkt,
|
|||
|
||||
len = ntohs(iph->tot_len);
|
||||
thoff = iph->ihl * 4;
|
||||
if (skb->len < len)
|
||||
if (pkt->skb->len < len)
|
||||
return -1;
|
||||
else if (len < thoff)
|
||||
return -1;
|
||||
|
||||
pkt->tprot_set = true;
|
||||
pkt->tprot = iph->protocol;
|
||||
pkt->xt.thoff = thoff;
|
||||
pkt->xt.fragoff = ntohs(iph->frag_off) & IP_OFFSET;
|
||||
pkt->thoff = thoff;
|
||||
pkt->fragoff = ntohs(iph->frag_off) & IP_OFFSET;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void nft_set_pktinfo_ipv4_validate(struct nft_pktinfo *pkt,
|
||||
struct sk_buff *skb)
|
||||
static inline void nft_set_pktinfo_ipv4_validate(struct nft_pktinfo *pkt)
|
||||
{
|
||||
if (__nft_set_pktinfo_ipv4_validate(pkt, skb) < 0)
|
||||
nft_set_pktinfo_unspec(pkt, skb);
|
||||
if (__nft_set_pktinfo_ipv4_validate(pkt) < 0)
|
||||
nft_set_pktinfo_unspec(pkt);
|
||||
}
|
||||
|
||||
static inline int nft_set_pktinfo_ipv4_ingress(struct nft_pktinfo *pkt,
|
||||
struct sk_buff *skb)
|
||||
static inline int nft_set_pktinfo_ipv4_ingress(struct nft_pktinfo *pkt)
|
||||
{
|
||||
struct iphdr *iph;
|
||||
u32 len, thoff;
|
||||
|
||||
if (!pskb_may_pull(skb, sizeof(*iph)))
|
||||
if (!pskb_may_pull(pkt->skb, sizeof(*iph)))
|
||||
return -1;
|
||||
|
||||
iph = ip_hdr(skb);
|
||||
iph = ip_hdr(pkt->skb);
|
||||
if (iph->ihl < 5 || iph->version != 4)
|
||||
goto inhdr_error;
|
||||
|
||||
len = ntohs(iph->tot_len);
|
||||
thoff = iph->ihl * 4;
|
||||
if (skb->len < len) {
|
||||
if (pkt->skb->len < len) {
|
||||
__IP_INC_STATS(nft_net(pkt), IPSTATS_MIB_INTRUNCATEDPKTS);
|
||||
return -1;
|
||||
} else if (len < thoff) {
|
||||
|
@ -77,8 +73,8 @@ static inline int nft_set_pktinfo_ipv4_ingress(struct nft_pktinfo *pkt,
|
|||
|
||||
pkt->tprot_set = true;
|
||||
pkt->tprot = iph->protocol;
|
||||
pkt->xt.thoff = thoff;
|
||||
pkt->xt.fragoff = ntohs(iph->frag_off) & IP_OFFSET;
|
||||
pkt->thoff = thoff;
|
||||
pkt->fragoff = ntohs(iph->frag_off) & IP_OFFSET;
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -6,8 +6,7 @@
|
|||
#include <net/ipv6.h>
|
||||
#include <net/netfilter/nf_tables.h>
|
||||
|
||||
static inline void nft_set_pktinfo_ipv6(struct nft_pktinfo *pkt,
|
||||
struct sk_buff *skb)
|
||||
static inline void nft_set_pktinfo_ipv6(struct nft_pktinfo *pkt)
|
||||
{
|
||||
unsigned int flags = IP6_FH_F_AUTH;
|
||||
int protohdr, thoff = 0;
|
||||
|
@ -15,18 +14,17 @@ static inline void nft_set_pktinfo_ipv6(struct nft_pktinfo *pkt,
|
|||
|
||||
protohdr = ipv6_find_hdr(pkt->skb, &thoff, -1, &frag_off, &flags);
|
||||
if (protohdr < 0) {
|
||||
nft_set_pktinfo_unspec(pkt, skb);
|
||||
nft_set_pktinfo_unspec(pkt);
|
||||
return;
|
||||
}
|
||||
|
||||
pkt->tprot_set = true;
|
||||
pkt->tprot = protohdr;
|
||||
pkt->xt.thoff = thoff;
|
||||
pkt->xt.fragoff = frag_off;
|
||||
pkt->thoff = thoff;
|
||||
pkt->fragoff = frag_off;
|
||||
}
|
||||
|
||||
static inline int __nft_set_pktinfo_ipv6_validate(struct nft_pktinfo *pkt,
|
||||
struct sk_buff *skb)
|
||||
static inline int __nft_set_pktinfo_ipv6_validate(struct nft_pktinfo *pkt)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
unsigned int flags = IP6_FH_F_AUTH;
|
||||
|
@ -36,8 +34,8 @@ static inline int __nft_set_pktinfo_ipv6_validate(struct nft_pktinfo *pkt,
|
|||
int protohdr;
|
||||
u32 pkt_len;
|
||||
|
||||
ip6h = skb_header_pointer(skb, skb_network_offset(skb), sizeof(*ip6h),
|
||||
&_ip6h);
|
||||
ip6h = skb_header_pointer(pkt->skb, skb_network_offset(pkt->skb),
|
||||
sizeof(*ip6h), &_ip6h);
|
||||
if (!ip6h)
|
||||
return -1;
|
||||
|
||||
|
@ -45,7 +43,7 @@ static inline int __nft_set_pktinfo_ipv6_validate(struct nft_pktinfo *pkt,
|
|||
return -1;
|
||||
|
||||
pkt_len = ntohs(ip6h->payload_len);
|
||||
if (pkt_len + sizeof(*ip6h) > skb->len)
|
||||
if (pkt_len + sizeof(*ip6h) > pkt->skb->len)
|
||||
return -1;
|
||||
|
||||
protohdr = ipv6_find_hdr(pkt->skb, &thoff, -1, &frag_off, &flags);
|
||||
|
@ -54,8 +52,8 @@ static inline int __nft_set_pktinfo_ipv6_validate(struct nft_pktinfo *pkt,
|
|||
|
||||
pkt->tprot_set = true;
|
||||
pkt->tprot = protohdr;
|
||||
pkt->xt.thoff = thoff;
|
||||
pkt->xt.fragoff = frag_off;
|
||||
pkt->thoff = thoff;
|
||||
pkt->fragoff = frag_off;
|
||||
|
||||
return 0;
|
||||
#else
|
||||
|
@ -63,15 +61,13 @@ static inline int __nft_set_pktinfo_ipv6_validate(struct nft_pktinfo *pkt,
|
|||
#endif
|
||||
}
|
||||
|
||||
static inline void nft_set_pktinfo_ipv6_validate(struct nft_pktinfo *pkt,
|
||||
struct sk_buff *skb)
|
||||
static inline void nft_set_pktinfo_ipv6_validate(struct nft_pktinfo *pkt)
|
||||
{
|
||||
if (__nft_set_pktinfo_ipv6_validate(pkt, skb) < 0)
|
||||
nft_set_pktinfo_unspec(pkt, skb);
|
||||
if (__nft_set_pktinfo_ipv6_validate(pkt) < 0)
|
||||
nft_set_pktinfo_unspec(pkt);
|
||||
}
|
||||
|
||||
static inline int nft_set_pktinfo_ipv6_ingress(struct nft_pktinfo *pkt,
|
||||
struct sk_buff *skb)
|
||||
static inline int nft_set_pktinfo_ipv6_ingress(struct nft_pktinfo *pkt)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
unsigned int flags = IP6_FH_F_AUTH;
|
||||
|
@ -82,15 +78,15 @@ static inline int nft_set_pktinfo_ipv6_ingress(struct nft_pktinfo *pkt,
|
|||
int protohdr;
|
||||
u32 pkt_len;
|
||||
|
||||
if (!pskb_may_pull(skb, sizeof(*ip6h)))
|
||||
if (!pskb_may_pull(pkt->skb, sizeof(*ip6h)))
|
||||
return -1;
|
||||
|
||||
ip6h = ipv6_hdr(skb);
|
||||
ip6h = ipv6_hdr(pkt->skb);
|
||||
if (ip6h->version != 6)
|
||||
goto inhdr_error;
|
||||
|
||||
pkt_len = ntohs(ip6h->payload_len);
|
||||
if (pkt_len + sizeof(*ip6h) > skb->len) {
|
||||
if (pkt_len + sizeof(*ip6h) > pkt->skb->len) {
|
||||
idev = __in6_dev_get(nft_in(pkt));
|
||||
__IP6_INC_STATS(nft_net(pkt), idev, IPSTATS_MIB_INTRUNCATEDPKTS);
|
||||
return -1;
|
||||
|
@ -102,8 +98,8 @@ static inline int nft_set_pktinfo_ipv6_ingress(struct nft_pktinfo *pkt,
|
|||
|
||||
pkt->tprot_set = true;
|
||||
pkt->tprot = protohdr;
|
||||
pkt->xt.thoff = thoff;
|
||||
pkt->xt.fragoff = frag_off;
|
||||
pkt->thoff = thoff;
|
||||
pkt->fragoff = frag_off;
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -813,11 +813,13 @@ enum nft_exthdr_flags {
|
|||
* @NFT_EXTHDR_OP_IPV6: match against ipv6 extension headers
|
||||
* @NFT_EXTHDR_OP_TCP: match against tcp options
|
||||
* @NFT_EXTHDR_OP_IPV4: match against ipv4 options
|
||||
* @NFT_EXTHDR_OP_SCTP: match against sctp chunks
|
||||
*/
|
||||
enum nft_exthdr_op {
|
||||
NFT_EXTHDR_OP_IPV6,
|
||||
NFT_EXTHDR_OP_TCPOPT,
|
||||
NFT_EXTHDR_OP_IPV4,
|
||||
NFT_EXTHDR_OP_SCTP,
|
||||
__NFT_EXTHDR_OP_MAX
|
||||
};
|
||||
#define NFT_EXTHDR_OP_MAX (__NFT_EXTHDR_OP_MAX - 1)
|
||||
|
|
|
@ -27,7 +27,7 @@ static void nft_reject_ipv4_eval(const struct nft_expr *expr,
|
|||
nf_send_unreach(pkt->skb, priv->icmp_code, nft_hook(pkt));
|
||||
break;
|
||||
case NFT_REJECT_TCP_RST:
|
||||
nf_send_reset(nft_net(pkt), pkt->xt.state->sk, pkt->skb,
|
||||
nf_send_reset(nft_net(pkt), nft_sk(pkt), pkt->skb,
|
||||
nft_hook(pkt));
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -51,7 +51,7 @@ ip6_packet_match(const struct sk_buff *skb,
|
|||
const char *outdev,
|
||||
const struct ip6t_ip6 *ip6info,
|
||||
unsigned int *protoff,
|
||||
int *fragoff, bool *hotdrop)
|
||||
u16 *fragoff, bool *hotdrop)
|
||||
{
|
||||
unsigned long ret;
|
||||
const struct ipv6hdr *ipv6 = ipv6_hdr(skb);
|
||||
|
|
|
@ -28,7 +28,7 @@ static void nft_reject_ipv6_eval(const struct nft_expr *expr,
|
|||
nft_hook(pkt));
|
||||
break;
|
||||
case NFT_REJECT_TCP_RST:
|
||||
nf_send_reset6(nft_net(pkt), pkt->xt.state->sk, pkt->skb,
|
||||
nf_send_reset6(nft_net(pkt), nft_sk(pkt), pkt->skb,
|
||||
nft_hook(pkt));
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -816,7 +816,7 @@ config NETFILTER_XT_TARGET_CLASSIFY
|
|||
the priority of a packet. Some qdiscs can use this value for
|
||||
classification, among these are:
|
||||
|
||||
atm, cbq, dsmark, pfifo_fast, htb, prio
|
||||
atm, cbq, dsmark, pfifo_fast, htb, prio
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
|
||||
|
|
|
@ -1685,8 +1685,8 @@ static const struct nla_policy ip_set_adt_policy[IPSET_ATTR_CMD_MAX + 1] = {
|
|||
};
|
||||
|
||||
static int
|
||||
call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set,
|
||||
struct nlattr *tb[], enum ipset_adt adt,
|
||||
call_ad(struct net *net, struct sock *ctnl, struct sk_buff *skb,
|
||||
struct ip_set *set, struct nlattr *tb[], enum ipset_adt adt,
|
||||
u32 flags, bool use_lineno)
|
||||
{
|
||||
int ret;
|
||||
|
@ -1738,8 +1738,7 @@ call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set,
|
|||
|
||||
*errline = lineno;
|
||||
|
||||
netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid,
|
||||
MSG_DONTWAIT);
|
||||
nfnetlink_unicast(skb2, net, NETLINK_CB(skb).portid);
|
||||
/* Signal netlink not to send its ACK/errmsg. */
|
||||
return -EINTR;
|
||||
}
|
||||
|
@ -1783,7 +1782,7 @@ static int ip_set_ad(struct net *net, struct sock *ctnl,
|
|||
attr[IPSET_ATTR_DATA],
|
||||
set->type->adt_policy, NULL))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
ret = call_ad(ctnl, skb, set, tb, adt, flags,
|
||||
ret = call_ad(net, ctnl, skb, set, tb, adt, flags,
|
||||
use_lineno);
|
||||
} else {
|
||||
int nla_rem;
|
||||
|
@ -1794,7 +1793,7 @@ static int ip_set_ad(struct net *net, struct sock *ctnl,
|
|||
nla_parse_nested(tb, IPSET_ATTR_ADT_MAX, nla,
|
||||
set->type->adt_policy, NULL))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
ret = call_ad(ctnl, skb, set, tb, adt,
|
||||
ret = call_ad(net, ctnl, skb, set, tb, adt,
|
||||
flags, use_lineno);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -1859,7 +1858,6 @@ static int ip_set_header(struct sk_buff *skb, const struct nfnl_info *info,
|
|||
const struct ip_set *set;
|
||||
struct sk_buff *skb2;
|
||||
struct nlmsghdr *nlh2;
|
||||
int ret = 0;
|
||||
|
||||
if (unlikely(protocol_min_failed(attr) ||
|
||||
!attr[IPSET_ATTR_SETNAME]))
|
||||
|
@ -1885,12 +1883,7 @@ static int ip_set_header(struct sk_buff *skb, const struct nfnl_info *info,
|
|||
goto nla_put_failure;
|
||||
nlmsg_end(skb2, nlh2);
|
||||
|
||||
ret = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
|
||||
MSG_DONTWAIT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
return nfnetlink_unicast(skb2, info->net, NETLINK_CB(skb).portid);
|
||||
|
||||
nla_put_failure:
|
||||
nlmsg_cancel(skb2, nlh2);
|
||||
|
@ -1945,12 +1938,7 @@ static int ip_set_type(struct sk_buff *skb, const struct nfnl_info *info,
|
|||
nlmsg_end(skb2, nlh2);
|
||||
|
||||
pr_debug("Send TYPE, nlmsg_len: %u\n", nlh2->nlmsg_len);
|
||||
ret = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
|
||||
MSG_DONTWAIT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
return nfnetlink_unicast(skb2, info->net, NETLINK_CB(skb).portid);
|
||||
|
||||
nla_put_failure:
|
||||
nlmsg_cancel(skb2, nlh2);
|
||||
|
@ -1971,7 +1959,6 @@ static int ip_set_protocol(struct sk_buff *skb, const struct nfnl_info *info,
|
|||
{
|
||||
struct sk_buff *skb2;
|
||||
struct nlmsghdr *nlh2;
|
||||
int ret = 0;
|
||||
|
||||
if (unlikely(!attr[IPSET_ATTR_PROTOCOL]))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
@ -1990,12 +1977,7 @@ static int ip_set_protocol(struct sk_buff *skb, const struct nfnl_info *info,
|
|||
goto nla_put_failure;
|
||||
nlmsg_end(skb2, nlh2);
|
||||
|
||||
ret = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
|
||||
MSG_DONTWAIT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
return nfnetlink_unicast(skb2, info->net, NETLINK_CB(skb).portid);
|
||||
|
||||
nla_put_failure:
|
||||
nlmsg_cancel(skb2, nlh2);
|
||||
|
@ -2014,7 +1996,6 @@ static int ip_set_byname(struct sk_buff *skb, const struct nfnl_info *info,
|
|||
struct nlmsghdr *nlh2;
|
||||
ip_set_id_t id = IPSET_INVALID_ID;
|
||||
const struct ip_set *set;
|
||||
int ret = 0;
|
||||
|
||||
if (unlikely(protocol_failed(attr) ||
|
||||
!attr[IPSET_ATTR_SETNAME]))
|
||||
|
@ -2038,12 +2019,7 @@ static int ip_set_byname(struct sk_buff *skb, const struct nfnl_info *info,
|
|||
goto nla_put_failure;
|
||||
nlmsg_end(skb2, nlh2);
|
||||
|
||||
ret = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
|
||||
MSG_DONTWAIT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
return nfnetlink_unicast(skb2, info->net, NETLINK_CB(skb).portid);
|
||||
|
||||
nla_put_failure:
|
||||
nlmsg_cancel(skb2, nlh2);
|
||||
|
@ -2065,7 +2041,6 @@ static int ip_set_byindex(struct sk_buff *skb, const struct nfnl_info *info,
|
|||
struct nlmsghdr *nlh2;
|
||||
ip_set_id_t id = IPSET_INVALID_ID;
|
||||
const struct ip_set *set;
|
||||
int ret = 0;
|
||||
|
||||
if (unlikely(protocol_failed(attr) ||
|
||||
!attr[IPSET_ATTR_INDEX]))
|
||||
|
@ -2091,12 +2066,7 @@ static int ip_set_byindex(struct sk_buff *skb, const struct nfnl_info *info,
|
|||
goto nla_put_failure;
|
||||
nlmsg_end(skb2, nlh2);
|
||||
|
||||
ret = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
|
||||
MSG_DONTWAIT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
return nfnetlink_unicast(skb2, info->net, NETLINK_CB(skb).portid);
|
||||
|
||||
nla_put_failure:
|
||||
nlmsg_cancel(skb2, nlh2);
|
||||
|
|
|
@ -318,7 +318,7 @@ config IP_VS_MH_TAB_INDEX
|
|||
comment 'IPVS application helper'
|
||||
|
||||
config IP_VS_FTP
|
||||
tristate "FTP protocol helper"
|
||||
tristate "FTP protocol helper"
|
||||
depends on IP_VS_PROTO_TCP && NF_CONNTRACK && NF_NAT && \
|
||||
NF_CONNTRACK_FTP
|
||||
select IP_VS_NFCT
|
||||
|
|
|
@ -194,7 +194,7 @@ static int get_tpkt_data(struct sk_buff *skb, unsigned int protoff,
|
|||
if (tcpdatalen == 4) { /* Separate TPKT header */
|
||||
/* Netmeeting sends TPKT header and data separately */
|
||||
pr_debug("nf_ct_h323: separate TPKT header indicates "
|
||||
"there will be TPKT data of %hu bytes\n",
|
||||
"there will be TPKT data of %d bytes\n",
|
||||
tpktlen - 4);
|
||||
info->tpkt_len[dir] = tpktlen - 4;
|
||||
return 0;
|
||||
|
|
|
@ -1628,9 +1628,8 @@ static int ctnetlink_get_conntrack(struct sk_buff *skb,
|
|||
|
||||
ct = nf_ct_tuplehash_to_ctrack(h);
|
||||
|
||||
err = -ENOMEM;
|
||||
skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||||
if (skb2 == NULL) {
|
||||
if (!skb2) {
|
||||
nf_ct_put(ct);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
@ -1640,21 +1639,12 @@ static int ctnetlink_get_conntrack(struct sk_buff *skb,
|
|||
NFNL_MSG_TYPE(info->nlh->nlmsg_type), ct,
|
||||
true, 0);
|
||||
nf_ct_put(ct);
|
||||
if (err <= 0)
|
||||
goto free;
|
||||
if (err <= 0) {
|
||||
kfree_skb(skb2);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
err = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
|
||||
MSG_DONTWAIT);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
return 0;
|
||||
|
||||
free:
|
||||
kfree_skb(skb2);
|
||||
out:
|
||||
/* this avoids a loop in nfnetlink. */
|
||||
return err == -EAGAIN ? -ENOBUFS : err;
|
||||
return nfnetlink_unicast(skb2, info->net, NETLINK_CB(skb).portid);
|
||||
}
|
||||
|
||||
static int ctnetlink_done_list(struct netlink_callback *cb)
|
||||
|
@ -2590,21 +2580,12 @@ static int ctnetlink_stat_ct(struct sk_buff *skb, const struct nfnl_info *info,
|
|||
info->nlh->nlmsg_seq,
|
||||
NFNL_MSG_TYPE(info->nlh->nlmsg_type),
|
||||
sock_net(skb->sk));
|
||||
if (err <= 0)
|
||||
goto free;
|
||||
if (err <= 0) {
|
||||
kfree_skb(skb2);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
err = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
|
||||
MSG_DONTWAIT);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
return 0;
|
||||
|
||||
free:
|
||||
kfree_skb(skb2);
|
||||
out:
|
||||
/* this avoids a loop in nfnetlink. */
|
||||
return err == -EAGAIN ? -ENOBUFS : err;
|
||||
return nfnetlink_unicast(skb2, info->net, NETLINK_CB(skb).portid);
|
||||
}
|
||||
|
||||
static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = {
|
||||
|
@ -3329,11 +3310,10 @@ static int ctnetlink_get_expect(struct sk_buff *skb,
|
|||
}
|
||||
}
|
||||
|
||||
err = -ENOMEM;
|
||||
skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||||
if (skb2 == NULL) {
|
||||
if (!skb2) {
|
||||
nf_ct_expect_put(exp);
|
||||
goto out;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
|
@ -3342,21 +3322,12 @@ static int ctnetlink_get_expect(struct sk_buff *skb,
|
|||
exp);
|
||||
rcu_read_unlock();
|
||||
nf_ct_expect_put(exp);
|
||||
if (err <= 0)
|
||||
goto free;
|
||||
if (err <= 0) {
|
||||
kfree_skb(skb2);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
err = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
|
||||
MSG_DONTWAIT);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
return 0;
|
||||
|
||||
free:
|
||||
kfree_skb(skb2);
|
||||
out:
|
||||
/* this avoids a loop in nfnetlink. */
|
||||
return err == -EAGAIN ? -ENOBUFS : err;
|
||||
return nfnetlink_unicast(skb2, info->net, NETLINK_CB(skb).portid);
|
||||
}
|
||||
|
||||
static bool expect_iter_name(struct nf_conntrack_expect *exp, void *data)
|
||||
|
|
|
@ -81,7 +81,7 @@ static bool nft_payload_fast_eval(const struct nft_expr *expr,
|
|||
else {
|
||||
if (!pkt->tprot_set)
|
||||
return false;
|
||||
ptr = skb_network_header(skb) + pkt->xt.thoff;
|
||||
ptr = skb_network_header(skb) + nft_thoff(pkt);
|
||||
}
|
||||
|
||||
ptr += priv->offset;
|
||||
|
|
|
@ -113,17 +113,17 @@ static int nf_trace_fill_pkt_info(struct sk_buff *nlskb,
|
|||
int off = skb_network_offset(skb);
|
||||
unsigned int len, nh_end;
|
||||
|
||||
nh_end = pkt->tprot_set ? pkt->xt.thoff : skb->len;
|
||||
nh_end = pkt->tprot_set ? nft_thoff(pkt) : skb->len;
|
||||
len = min_t(unsigned int, nh_end - skb_network_offset(skb),
|
||||
NFT_TRACETYPE_NETWORK_HSIZE);
|
||||
if (trace_fill_header(nlskb, NFTA_TRACE_NETWORK_HEADER, skb, off, len))
|
||||
return -1;
|
||||
|
||||
if (pkt->tprot_set) {
|
||||
len = min_t(unsigned int, skb->len - pkt->xt.thoff,
|
||||
len = min_t(unsigned int, skb->len - nft_thoff(pkt),
|
||||
NFT_TRACETYPE_TRANSPORT_HSIZE);
|
||||
if (trace_fill_header(nlskb, NFTA_TRACE_TRANSPORT_HEADER, skb,
|
||||
pkt->xt.thoff, len))
|
||||
nft_thoff(pkt), len))
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -314,14 +314,11 @@ static int nfnl_acct_get(struct sk_buff *skb, const struct nfnl_info *info,
|
|||
kfree_skb(skb2);
|
||||
break;
|
||||
}
|
||||
ret = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
|
||||
MSG_DONTWAIT);
|
||||
if (ret > 0)
|
||||
ret = 0;
|
||||
|
||||
/* this avoids a loop in nfnetlink. */
|
||||
return ret == -EAGAIN ? -ENOBUFS : ret;
|
||||
ret = nfnetlink_unicast(skb2, info->net, NETLINK_CB(skb).portid);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -663,14 +663,10 @@ static int nfnl_cthelper_get(struct sk_buff *skb, const struct nfnl_info *info,
|
|||
break;
|
||||
}
|
||||
|
||||
ret = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
|
||||
MSG_DONTWAIT);
|
||||
if (ret > 0)
|
||||
ret = 0;
|
||||
|
||||
/* this avoids a loop in nfnetlink. */
|
||||
return ret == -EAGAIN ? -ENOBUFS : ret;
|
||||
ret = nfnetlink_unicast(skb2, info->net, NETLINK_CB(skb).portid);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -287,14 +287,11 @@ static int cttimeout_get_timeout(struct sk_buff *skb,
|
|||
kfree_skb(skb2);
|
||||
break;
|
||||
}
|
||||
ret = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
|
||||
MSG_DONTWAIT);
|
||||
if (ret > 0)
|
||||
ret = 0;
|
||||
|
||||
/* this avoids a loop in nfnetlink. */
|
||||
return ret == -EAGAIN ? -ENOBUFS : ret;
|
||||
ret = nfnetlink_unicast(skb2, info->net, NETLINK_CB(skb).portid);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -427,9 +424,9 @@ static int cttimeout_default_get(struct sk_buff *skb,
|
|||
const struct nf_conntrack_l4proto *l4proto;
|
||||
unsigned int *timeouts = NULL;
|
||||
struct sk_buff *skb2;
|
||||
int ret, err;
|
||||
__u16 l3num;
|
||||
__u8 l4num;
|
||||
int ret;
|
||||
|
||||
if (!cda[CTA_TIMEOUT_L3PROTO] || !cda[CTA_TIMEOUT_L4PROTO])
|
||||
return -EINVAL;
|
||||
|
@ -438,9 +435,8 @@ static int cttimeout_default_get(struct sk_buff *skb,
|
|||
l4num = nla_get_u8(cda[CTA_TIMEOUT_L4PROTO]);
|
||||
l4proto = nf_ct_l4proto_find(l4num);
|
||||
|
||||
err = -EOPNOTSUPP;
|
||||
if (l4proto->l4proto != l4num)
|
||||
goto err;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
switch (l4proto->l4proto) {
|
||||
case IPPROTO_ICMP:
|
||||
|
@ -480,13 +476,11 @@ static int cttimeout_default_get(struct sk_buff *skb,
|
|||
}
|
||||
|
||||
if (!timeouts)
|
||||
goto err;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||||
if (skb2 == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
if (!skb2)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = cttimeout_default_fill_info(info->net, skb2,
|
||||
NETLINK_CB(skb).portid,
|
||||
|
@ -496,18 +490,10 @@ static int cttimeout_default_get(struct sk_buff *skb,
|
|||
l3num, l4proto, timeouts);
|
||||
if (ret <= 0) {
|
||||
kfree_skb(skb2);
|
||||
err = -ENOMEM;
|
||||
goto err;
|
||||
return -ENOMEM;
|
||||
}
|
||||
ret = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
|
||||
MSG_DONTWAIT);
|
||||
if (ret > 0)
|
||||
ret = 0;
|
||||
|
||||
/* this avoids a loop in nfnetlink. */
|
||||
return ret == -EAGAIN ? -ENOBUFS : ret;
|
||||
err:
|
||||
return err;
|
||||
return nfnetlink_unicast(skb2, info->net, NETLINK_CB(skb).portid);
|
||||
}
|
||||
|
||||
static struct nf_ct_timeout *ctnl_timeout_find_get(struct net *net,
|
||||
|
|
|
@ -18,7 +18,7 @@ static unsigned int nft_do_chain_ipv4(void *priv,
|
|||
struct nft_pktinfo pkt;
|
||||
|
||||
nft_set_pktinfo(&pkt, skb, state);
|
||||
nft_set_pktinfo_ipv4(&pkt, skb);
|
||||
nft_set_pktinfo_ipv4(&pkt);
|
||||
|
||||
return nft_do_chain(&pkt, priv);
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ static unsigned int nft_do_chain_arp(void *priv, struct sk_buff *skb,
|
|||
struct nft_pktinfo pkt;
|
||||
|
||||
nft_set_pktinfo(&pkt, skb, state);
|
||||
nft_set_pktinfo_unspec(&pkt, skb);
|
||||
nft_set_pktinfo_unspec(&pkt);
|
||||
|
||||
return nft_do_chain(&pkt, priv);
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ static unsigned int nft_do_chain_ipv6(void *priv,
|
|||
struct nft_pktinfo pkt;
|
||||
|
||||
nft_set_pktinfo(&pkt, skb, state);
|
||||
nft_set_pktinfo_ipv6(&pkt, skb);
|
||||
nft_set_pktinfo_ipv6(&pkt);
|
||||
|
||||
return nft_do_chain(&pkt, priv);
|
||||
}
|
||||
|
@ -149,10 +149,10 @@ static unsigned int nft_do_chain_inet(void *priv, struct sk_buff *skb,
|
|||
|
||||
switch (state->pf) {
|
||||
case NFPROTO_IPV4:
|
||||
nft_set_pktinfo_ipv4(&pkt, skb);
|
||||
nft_set_pktinfo_ipv4(&pkt);
|
||||
break;
|
||||
case NFPROTO_IPV6:
|
||||
nft_set_pktinfo_ipv6(&pkt, skb);
|
||||
nft_set_pktinfo_ipv6(&pkt);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -174,7 +174,7 @@ static unsigned int nft_do_chain_inet_ingress(void *priv, struct sk_buff *skb,
|
|||
ingress_state.hook = NF_INET_INGRESS;
|
||||
nft_set_pktinfo(&pkt, skb, &ingress_state);
|
||||
|
||||
if (nft_set_pktinfo_ipv4_ingress(&pkt, skb) < 0)
|
||||
if (nft_set_pktinfo_ipv4_ingress(&pkt) < 0)
|
||||
return NF_DROP;
|
||||
break;
|
||||
case htons(ETH_P_IPV6):
|
||||
|
@ -182,7 +182,7 @@ static unsigned int nft_do_chain_inet_ingress(void *priv, struct sk_buff *skb,
|
|||
ingress_state.hook = NF_INET_INGRESS;
|
||||
nft_set_pktinfo(&pkt, skb, &ingress_state);
|
||||
|
||||
if (nft_set_pktinfo_ipv6_ingress(&pkt, skb) < 0)
|
||||
if (nft_set_pktinfo_ipv6_ingress(&pkt) < 0)
|
||||
return NF_DROP;
|
||||
break;
|
||||
default:
|
||||
|
@ -238,13 +238,13 @@ nft_do_chain_bridge(void *priv,
|
|||
|
||||
switch (eth_hdr(skb)->h_proto) {
|
||||
case htons(ETH_P_IP):
|
||||
nft_set_pktinfo_ipv4_validate(&pkt, skb);
|
||||
nft_set_pktinfo_ipv4_validate(&pkt);
|
||||
break;
|
||||
case htons(ETH_P_IPV6):
|
||||
nft_set_pktinfo_ipv6_validate(&pkt, skb);
|
||||
nft_set_pktinfo_ipv6_validate(&pkt);
|
||||
break;
|
||||
default:
|
||||
nft_set_pktinfo_unspec(&pkt, skb);
|
||||
nft_set_pktinfo_unspec(&pkt);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -293,13 +293,13 @@ static unsigned int nft_do_chain_netdev(void *priv, struct sk_buff *skb,
|
|||
|
||||
switch (skb->protocol) {
|
||||
case htons(ETH_P_IP):
|
||||
nft_set_pktinfo_ipv4_validate(&pkt, skb);
|
||||
nft_set_pktinfo_ipv4_validate(&pkt);
|
||||
break;
|
||||
case htons(ETH_P_IPV6):
|
||||
nft_set_pktinfo_ipv6_validate(&pkt, skb);
|
||||
nft_set_pktinfo_ipv6_validate(&pkt);
|
||||
break;
|
||||
default:
|
||||
nft_set_pktinfo_unspec(&pkt, skb);
|
||||
nft_set_pktinfo_unspec(&pkt);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,12 +17,12 @@ static unsigned int nft_nat_do_chain(void *priv, struct sk_buff *skb,
|
|||
switch (state->pf) {
|
||||
#ifdef CONFIG_NF_TABLES_IPV4
|
||||
case NFPROTO_IPV4:
|
||||
nft_set_pktinfo_ipv4(&pkt, skb);
|
||||
nft_set_pktinfo_ipv4(&pkt);
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_NF_TABLES_IPV6
|
||||
case NFPROTO_IPV6:
|
||||
nft_set_pktinfo_ipv6(&pkt, skb);
|
||||
nft_set_pktinfo_ipv6(&pkt);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
|
|
|
@ -26,7 +26,7 @@ static unsigned int nf_route_table_hook4(void *priv,
|
|||
u8 tos;
|
||||
|
||||
nft_set_pktinfo(&pkt, skb, state);
|
||||
nft_set_pktinfo_ipv4(&pkt, skb);
|
||||
nft_set_pktinfo_ipv4(&pkt);
|
||||
|
||||
mark = skb->mark;
|
||||
iph = ip_hdr(skb);
|
||||
|
@ -74,7 +74,7 @@ static unsigned int nf_route_table_hook6(void *priv,
|
|||
int err;
|
||||
|
||||
nft_set_pktinfo(&pkt, skb, state);
|
||||
nft_set_pktinfo_ipv6(&pkt, skb);
|
||||
nft_set_pktinfo_ipv6(&pkt);
|
||||
|
||||
/* save source/dest address, mark, hoplimit, flowlabel, priority */
|
||||
memcpy(&saddr, &ipv6_hdr(skb)->saddr, sizeof(saddr));
|
||||
|
|
|
@ -57,8 +57,13 @@ union nft_entry {
|
|||
};
|
||||
|
||||
static inline void
|
||||
nft_compat_set_par(struct xt_action_param *par, void *xt, const void *xt_info)
|
||||
nft_compat_set_par(struct xt_action_param *par,
|
||||
const struct nft_pktinfo *pkt,
|
||||
const void *xt, const void *xt_info)
|
||||
{
|
||||
par->state = pkt->state;
|
||||
par->thoff = nft_thoff(pkt);
|
||||
par->fragoff = pkt->fragoff;
|
||||
par->target = xt;
|
||||
par->targinfo = xt_info;
|
||||
par->hotdrop = false;
|
||||
|
@ -71,13 +76,14 @@ static void nft_target_eval_xt(const struct nft_expr *expr,
|
|||
void *info = nft_expr_priv(expr);
|
||||
struct xt_target *target = expr->ops->data;
|
||||
struct sk_buff *skb = pkt->skb;
|
||||
struct xt_action_param xt;
|
||||
int ret;
|
||||
|
||||
nft_compat_set_par((struct xt_action_param *)&pkt->xt, target, info);
|
||||
nft_compat_set_par(&xt, pkt, target, info);
|
||||
|
||||
ret = target->target(skb, &pkt->xt);
|
||||
ret = target->target(skb, &xt);
|
||||
|
||||
if (pkt->xt.hotdrop)
|
||||
if (xt.hotdrop)
|
||||
ret = NF_DROP;
|
||||
|
||||
switch (ret) {
|
||||
|
@ -97,13 +103,14 @@ static void nft_target_eval_bridge(const struct nft_expr *expr,
|
|||
void *info = nft_expr_priv(expr);
|
||||
struct xt_target *target = expr->ops->data;
|
||||
struct sk_buff *skb = pkt->skb;
|
||||
struct xt_action_param xt;
|
||||
int ret;
|
||||
|
||||
nft_compat_set_par((struct xt_action_param *)&pkt->xt, target, info);
|
||||
nft_compat_set_par(&xt, pkt, target, info);
|
||||
|
||||
ret = target->target(skb, &pkt->xt);
|
||||
ret = target->target(skb, &xt);
|
||||
|
||||
if (pkt->xt.hotdrop)
|
||||
if (xt.hotdrop)
|
||||
ret = NF_DROP;
|
||||
|
||||
switch (ret) {
|
||||
|
@ -350,13 +357,14 @@ static void __nft_match_eval(const struct nft_expr *expr,
|
|||
{
|
||||
struct xt_match *match = expr->ops->data;
|
||||
struct sk_buff *skb = pkt->skb;
|
||||
struct xt_action_param xt;
|
||||
bool ret;
|
||||
|
||||
nft_compat_set_par((struct xt_action_param *)&pkt->xt, match, info);
|
||||
nft_compat_set_par(&xt, pkt, match, info);
|
||||
|
||||
ret = match->match(skb, (struct xt_action_param *)&pkt->xt);
|
||||
ret = match->match(skb, &xt);
|
||||
|
||||
if (pkt->xt.hotdrop) {
|
||||
if (xt.hotdrop) {
|
||||
regs->verdict.code = NF_DROP;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -10,8 +10,10 @@
|
|||
#include <linux/netlink.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter/nf_tables.h>
|
||||
#include <linux/sctp.h>
|
||||
#include <net/netfilter/nf_tables_core.h>
|
||||
#include <net/netfilter/nf_tables.h>
|
||||
#include <net/sctp/sctp.h>
|
||||
#include <net/tcp.h>
|
||||
|
||||
struct nft_exthdr {
|
||||
|
@ -165,7 +167,7 @@ nft_tcp_header_pointer(const struct nft_pktinfo *pkt,
|
|||
if (!pkt->tprot_set || pkt->tprot != IPPROTO_TCP)
|
||||
return NULL;
|
||||
|
||||
tcph = skb_header_pointer(pkt->skb, pkt->xt.thoff, sizeof(*tcph), buffer);
|
||||
tcph = skb_header_pointer(pkt->skb, nft_thoff(pkt), sizeof(*tcph), buffer);
|
||||
if (!tcph)
|
||||
return NULL;
|
||||
|
||||
|
@ -173,7 +175,7 @@ nft_tcp_header_pointer(const struct nft_pktinfo *pkt,
|
|||
if (*tcphdr_len < sizeof(*tcph) || *tcphdr_len > len)
|
||||
return NULL;
|
||||
|
||||
return skb_header_pointer(pkt->skb, pkt->xt.thoff, *tcphdr_len, buffer);
|
||||
return skb_header_pointer(pkt->skb, nft_thoff(pkt), *tcphdr_len, buffer);
|
||||
}
|
||||
|
||||
static void nft_exthdr_tcp_eval(const struct nft_expr *expr,
|
||||
|
@ -249,7 +251,7 @@ static void nft_exthdr_tcp_set_eval(const struct nft_expr *expr,
|
|||
return;
|
||||
|
||||
if (skb_ensure_writable(pkt->skb,
|
||||
pkt->xt.thoff + i + priv->len))
|
||||
nft_thoff(pkt) + i + priv->len))
|
||||
return;
|
||||
|
||||
tcph = nft_tcp_header_pointer(pkt, sizeof(buff), buff,
|
||||
|
@ -300,6 +302,43 @@ static void nft_exthdr_tcp_set_eval(const struct nft_expr *expr,
|
|||
}
|
||||
}
|
||||
|
||||
static void nft_exthdr_sctp_eval(const struct nft_expr *expr,
|
||||
struct nft_regs *regs,
|
||||
const struct nft_pktinfo *pkt)
|
||||
{
|
||||
unsigned int offset = nft_thoff(pkt) + sizeof(struct sctphdr);
|
||||
struct nft_exthdr *priv = nft_expr_priv(expr);
|
||||
u32 *dest = ®s->data[priv->dreg];
|
||||
const struct sctp_chunkhdr *sch;
|
||||
struct sctp_chunkhdr _sch;
|
||||
|
||||
do {
|
||||
sch = skb_header_pointer(pkt->skb, offset, sizeof(_sch), &_sch);
|
||||
if (!sch || !sch->length)
|
||||
break;
|
||||
|
||||
if (sch->type == priv->type) {
|
||||
if (priv->flags & NFT_EXTHDR_F_PRESENT) {
|
||||
nft_reg_store8(dest, true);
|
||||
return;
|
||||
}
|
||||
if (priv->offset + priv->len > ntohs(sch->length) ||
|
||||
offset + ntohs(sch->length) > pkt->skb->len)
|
||||
break;
|
||||
|
||||
dest[priv->len / NFT_REG32_SIZE] = 0;
|
||||
memcpy(dest, (char *)sch + priv->offset, priv->len);
|
||||
return;
|
||||
}
|
||||
offset += SCTP_PAD4(ntohs(sch->length));
|
||||
} while (offset < pkt->skb->len);
|
||||
|
||||
if (priv->flags & NFT_EXTHDR_F_PRESENT)
|
||||
nft_reg_store8(dest, false);
|
||||
else
|
||||
regs->verdict.code = NFT_BREAK;
|
||||
}
|
||||
|
||||
static const struct nla_policy nft_exthdr_policy[NFTA_EXTHDR_MAX + 1] = {
|
||||
[NFTA_EXTHDR_DREG] = { .type = NLA_U32 },
|
||||
[NFTA_EXTHDR_TYPE] = { .type = NLA_U8 },
|
||||
|
@ -499,6 +538,14 @@ static const struct nft_expr_ops nft_exthdr_tcp_set_ops = {
|
|||
.dump = nft_exthdr_dump_set,
|
||||
};
|
||||
|
||||
static const struct nft_expr_ops nft_exthdr_sctp_ops = {
|
||||
.type = &nft_exthdr_type,
|
||||
.size = NFT_EXPR_SIZE(sizeof(struct nft_exthdr)),
|
||||
.eval = nft_exthdr_sctp_eval,
|
||||
.init = nft_exthdr_init,
|
||||
.dump = nft_exthdr_dump,
|
||||
};
|
||||
|
||||
static const struct nft_expr_ops *
|
||||
nft_exthdr_select_ops(const struct nft_ctx *ctx,
|
||||
const struct nlattr * const tb[])
|
||||
|
@ -529,6 +576,10 @@ nft_exthdr_select_ops(const struct nft_ctx *ctx,
|
|||
return &nft_exthdr_ipv4_ops;
|
||||
}
|
||||
break;
|
||||
case NFT_EXTHDR_OP_SCTP:
|
||||
if (tb[NFTA_EXTHDR_DREG])
|
||||
return &nft_exthdr_sctp_ops;
|
||||
break;
|
||||
}
|
||||
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
|
|
|
@ -291,7 +291,7 @@ static void nft_flow_offload_eval(const struct nft_expr *expr,
|
|||
|
||||
switch (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum) {
|
||||
case IPPROTO_TCP:
|
||||
tcph = skb_header_pointer(pkt->skb, pkt->xt.thoff,
|
||||
tcph = skb_header_pointer(pkt->skb, nft_thoff(pkt),
|
||||
sizeof(_tcph), &_tcph);
|
||||
if (unlikely(!tcph || tcph->fin || tcph->rst))
|
||||
goto out;
|
||||
|
|
|
@ -23,6 +23,37 @@ struct nft_lookup {
|
|||
struct nft_set_binding binding;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_RETPOLINE
|
||||
bool nft_set_do_lookup(const struct net *net, const struct nft_set *set,
|
||||
const u32 *key, const struct nft_set_ext **ext)
|
||||
{
|
||||
if (set->ops == &nft_set_hash_fast_type.ops)
|
||||
return nft_hash_lookup_fast(net, set, key, ext);
|
||||
if (set->ops == &nft_set_hash_type.ops)
|
||||
return nft_hash_lookup(net, set, key, ext);
|
||||
|
||||
if (set->ops == &nft_set_rhash_type.ops)
|
||||
return nft_rhash_lookup(net, set, key, ext);
|
||||
|
||||
if (set->ops == &nft_set_bitmap_type.ops)
|
||||
return nft_bitmap_lookup(net, set, key, ext);
|
||||
|
||||
if (set->ops == &nft_set_pipapo_type.ops)
|
||||
return nft_pipapo_lookup(net, set, key, ext);
|
||||
#if defined(CONFIG_X86_64) && !defined(CONFIG_UML)
|
||||
if (set->ops == &nft_set_pipapo_avx2_type.ops)
|
||||
return nft_pipapo_avx2_lookup(net, set, key, ext);
|
||||
#endif
|
||||
|
||||
if (set->ops == &nft_set_rbtree_type.ops)
|
||||
return nft_rbtree_lookup(net, set, key, ext);
|
||||
|
||||
WARN_ON_ONCE(1);
|
||||
return set->ops->lookup(net, set, key, ext);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nft_set_do_lookup);
|
||||
#endif
|
||||
|
||||
void nft_lookup_eval(const struct nft_expr *expr,
|
||||
struct nft_regs *regs,
|
||||
const struct nft_pktinfo *pkt)
|
||||
|
@ -33,8 +64,8 @@ void nft_lookup_eval(const struct nft_expr *expr,
|
|||
const struct net *net = nft_net(pkt);
|
||||
bool found;
|
||||
|
||||
found = set->ops->lookup(net, set, ®s->data[priv->sreg], &ext) ^
|
||||
priv->invert;
|
||||
found = nft_set_do_lookup(net, set, ®s->data[priv->sreg], &ext) ^
|
||||
priv->invert;
|
||||
if (!found) {
|
||||
ext = nft_set_catchall_lookup(net, set);
|
||||
if (!ext) {
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#include <linux/netlink.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter/nf_tables.h>
|
||||
#include <net/netfilter/nf_tables.h>
|
||||
#include <net/netfilter/nf_tables_core.h>
|
||||
|
||||
#define nft_objref_priv(expr) *((struct nft_object **)nft_expr_priv(expr))
|
||||
|
||||
|
@ -110,7 +110,7 @@ static void nft_objref_map_eval(const struct nft_expr *expr,
|
|||
struct nft_object *obj;
|
||||
bool found;
|
||||
|
||||
found = set->ops->lookup(net, set, ®s->data[priv->sreg], &ext);
|
||||
found = nft_set_do_lookup(net, set, ®s->data[priv->sreg], &ext);
|
||||
if (!found) {
|
||||
ext = nft_set_catchall_lookup(net, set);
|
||||
if (!ext) {
|
||||
|
|
|
@ -110,7 +110,7 @@ void nft_payload_eval(const struct nft_expr *expr,
|
|||
case NFT_PAYLOAD_TRANSPORT_HEADER:
|
||||
if (!pkt->tprot_set)
|
||||
goto err;
|
||||
offset = pkt->xt.thoff;
|
||||
offset = nft_thoff(pkt);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
|
@ -507,7 +507,7 @@ static int nft_payload_l4csum_offset(const struct nft_pktinfo *pkt,
|
|||
*l4csum_offset = offsetof(struct tcphdr, check);
|
||||
break;
|
||||
case IPPROTO_UDP:
|
||||
if (!nft_payload_udp_checksum(skb, pkt->xt.thoff))
|
||||
if (!nft_payload_udp_checksum(skb, nft_thoff(pkt)))
|
||||
return -1;
|
||||
fallthrough;
|
||||
case IPPROTO_UDPLITE:
|
||||
|
@ -520,7 +520,7 @@ static int nft_payload_l4csum_offset(const struct nft_pktinfo *pkt,
|
|||
return -1;
|
||||
}
|
||||
|
||||
*l4csum_offset += pkt->xt.thoff;
|
||||
*l4csum_offset += nft_thoff(pkt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -612,7 +612,7 @@ static void nft_payload_set_eval(const struct nft_expr *expr,
|
|||
case NFT_PAYLOAD_TRANSPORT_HEADER:
|
||||
if (!pkt->tprot_set)
|
||||
goto err;
|
||||
offset = pkt->xt.thoff;
|
||||
offset = nft_thoff(pkt);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
|
@ -643,7 +643,7 @@ static void nft_payload_set_eval(const struct nft_expr *expr,
|
|||
if (priv->csum_type == NFT_PAYLOAD_CSUM_SCTP &&
|
||||
pkt->tprot == IPPROTO_SCTP &&
|
||||
skb->ip_summed != CHECKSUM_PARTIAL) {
|
||||
if (nft_payload_csum_sctp(skb, pkt->xt.thoff))
|
||||
if (nft_payload_csum_sctp(skb, nft_thoff(pkt)))
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ static void nft_reject_inet_eval(const struct nft_expr *expr,
|
|||
nft_hook(pkt));
|
||||
break;
|
||||
case NFT_REJECT_TCP_RST:
|
||||
nf_send_reset(nft_net(pkt), pkt->xt.state->sk,
|
||||
nf_send_reset(nft_net(pkt), nft_sk(pkt),
|
||||
pkt->skb, nft_hook(pkt));
|
||||
break;
|
||||
case NFT_REJECT_ICMPX_UNREACH:
|
||||
|
@ -45,7 +45,7 @@ static void nft_reject_inet_eval(const struct nft_expr *expr,
|
|||
priv->icmp_code, nft_hook(pkt));
|
||||
break;
|
||||
case NFT_REJECT_TCP_RST:
|
||||
nf_send_reset6(nft_net(pkt), pkt->xt.state->sk,
|
||||
nf_send_reset6(nft_net(pkt), nft_sk(pkt),
|
||||
pkt->skb, nft_hook(pkt));
|
||||
break;
|
||||
case NFT_REJECT_ICMPX_UNREACH:
|
||||
|
|
|
@ -73,8 +73,9 @@ nft_bitmap_active(const u8 *bitmap, u32 idx, u32 off, u8 genmask)
|
|||
return (bitmap[idx] & (0x3 << off)) & (genmask << off);
|
||||
}
|
||||
|
||||
static bool nft_bitmap_lookup(const struct net *net, const struct nft_set *set,
|
||||
const u32 *key, const struct nft_set_ext **ext)
|
||||
INDIRECT_CALLABLE_SCOPE
|
||||
bool nft_bitmap_lookup(const struct net *net, const struct nft_set *set,
|
||||
const u32 *key, const struct nft_set_ext **ext)
|
||||
{
|
||||
const struct nft_bitmap *priv = nft_set_priv(set);
|
||||
u8 genmask = nft_genmask_cur(net);
|
||||
|
|
|
@ -74,8 +74,9 @@ static const struct rhashtable_params nft_rhash_params = {
|
|||
.automatic_shrinking = true,
|
||||
};
|
||||
|
||||
static bool nft_rhash_lookup(const struct net *net, const struct nft_set *set,
|
||||
const u32 *key, const struct nft_set_ext **ext)
|
||||
INDIRECT_CALLABLE_SCOPE
|
||||
bool nft_rhash_lookup(const struct net *net, const struct nft_set *set,
|
||||
const u32 *key, const struct nft_set_ext **ext)
|
||||
{
|
||||
struct nft_rhash *priv = nft_set_priv(set);
|
||||
const struct nft_rhash_elem *he;
|
||||
|
@ -446,8 +447,9 @@ struct nft_hash_elem {
|
|||
struct nft_set_ext ext;
|
||||
};
|
||||
|
||||
static bool nft_hash_lookup(const struct net *net, const struct nft_set *set,
|
||||
const u32 *key, const struct nft_set_ext **ext)
|
||||
INDIRECT_CALLABLE_SCOPE
|
||||
bool nft_hash_lookup(const struct net *net, const struct nft_set *set,
|
||||
const u32 *key, const struct nft_set_ext **ext)
|
||||
{
|
||||
struct nft_hash *priv = nft_set_priv(set);
|
||||
u8 genmask = nft_genmask_cur(net);
|
||||
|
@ -484,9 +486,10 @@ static void *nft_hash_get(const struct net *net, const struct nft_set *set,
|
|||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
|
||||
static bool nft_hash_lookup_fast(const struct net *net,
|
||||
const struct nft_set *set,
|
||||
const u32 *key, const struct nft_set_ext **ext)
|
||||
INDIRECT_CALLABLE_SCOPE
|
||||
bool nft_hash_lookup_fast(const struct net *net,
|
||||
const struct nft_set *set,
|
||||
const u32 *key, const struct nft_set_ext **ext)
|
||||
{
|
||||
struct nft_hash *priv = nft_set_priv(set);
|
||||
u8 genmask = nft_genmask_cur(net);
|
||||
|
|
|
@ -178,8 +178,6 @@ struct nft_pipapo_elem {
|
|||
|
||||
int pipapo_refill(unsigned long *map, int len, int rules, unsigned long *dst,
|
||||
union nft_pipapo_map_bucket *mt, bool match_only);
|
||||
bool nft_pipapo_lookup(const struct net *net, const struct nft_set *set,
|
||||
const u32 *key, const struct nft_set_ext **ext);
|
||||
|
||||
/**
|
||||
* pipapo_and_field_buckets_4bit() - Intersect 4-bit buckets
|
||||
|
|
|
@ -142,7 +142,6 @@ static void nft_pipapo_avx2_fill(unsigned long *data, int start, int len)
|
|||
* @map: Bitmap to be scanned for set bits
|
||||
* @dst: Destination bitmap
|
||||
* @mt: Mapping table containing bit set specifiers
|
||||
* @len: Length of bitmap in longs
|
||||
* @last: Return index of first set bit, if this is the last field
|
||||
*
|
||||
* This is an alternative implementation of pipapo_refill() suitable for usage
|
||||
|
@ -1109,7 +1108,7 @@ bool nft_pipapo_avx2_estimate(const struct nft_set_desc *desc, u32 features,
|
|||
* nft_pipapo_avx2_lookup() - Lookup function for AVX2 implementation
|
||||
* @net: Network namespace
|
||||
* @set: nftables API set representation
|
||||
* @elem: nftables API element representation containing key data
|
||||
* @key: nftables API element representation containing key data
|
||||
* @ext: nftables API extension pointer, filled with matching reference
|
||||
*
|
||||
* For more details, see DOC: Theory of Operation in nft_set_pipapo.c.
|
||||
|
@ -1136,8 +1135,13 @@ bool nft_pipapo_avx2_lookup(const struct net *net, const struct nft_set *set,
|
|||
|
||||
m = rcu_dereference(priv->match);
|
||||
|
||||
/* This also protects access to all data related to scratch maps */
|
||||
kernel_fpu_begin();
|
||||
/* This also protects access to all data related to scratch maps.
|
||||
*
|
||||
* Note that we don't need a valid MXCSR state for any of the
|
||||
* operations we use here, so pass 0 as mask and spare a LDMXCSR
|
||||
* instruction.
|
||||
*/
|
||||
kernel_fpu_begin_mask(0);
|
||||
|
||||
scratch = *raw_cpu_ptr(m->scratch_aligned);
|
||||
if (unlikely(!scratch)) {
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
#include <asm/fpu/xstate.h>
|
||||
#define NFT_PIPAPO_ALIGN (XSAVE_YMM_SIZE / BITS_PER_BYTE)
|
||||
|
||||
bool nft_pipapo_avx2_lookup(const struct net *net, const struct nft_set *set,
|
||||
const u32 *key, const struct nft_set_ext **ext);
|
||||
bool nft_pipapo_avx2_estimate(const struct nft_set_desc *desc, u32 features,
|
||||
struct nft_set_estimate *est);
|
||||
#endif /* defined(CONFIG_X86_64) && !defined(CONFIG_UML) */
|
||||
|
|
|
@ -107,8 +107,9 @@ static bool __nft_rbtree_lookup(const struct net *net, const struct nft_set *set
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool nft_rbtree_lookup(const struct net *net, const struct nft_set *set,
|
||||
const u32 *key, const struct nft_set_ext **ext)
|
||||
INDIRECT_CALLABLE_SCOPE
|
||||
bool nft_rbtree_lookup(const struct net *net, const struct nft_set *set,
|
||||
const u32 *key, const struct nft_set_ext **ext)
|
||||
{
|
||||
struct nft_rbtree *priv = nft_set_priv(set);
|
||||
unsigned int seq = read_seqcount_begin(&priv->count);
|
||||
|
|
|
@ -109,7 +109,7 @@ static void nft_synproxy_do_eval(const struct nft_synproxy *priv,
|
|||
{
|
||||
struct synproxy_options opts = {};
|
||||
struct sk_buff *skb = pkt->skb;
|
||||
int thoff = pkt->xt.thoff;
|
||||
int thoff = nft_thoff(pkt);
|
||||
const struct tcphdr *tcp;
|
||||
struct tcphdr _tcph;
|
||||
|
||||
|
@ -123,7 +123,7 @@ static void nft_synproxy_do_eval(const struct nft_synproxy *priv,
|
|||
return;
|
||||
}
|
||||
|
||||
tcp = skb_header_pointer(skb, pkt->xt.thoff,
|
||||
tcp = skb_header_pointer(skb, thoff,
|
||||
sizeof(struct tcphdr),
|
||||
&_tcph);
|
||||
if (!tcp) {
|
||||
|
|
|
@ -82,9 +82,9 @@ static void nft_tproxy_eval_v6(const struct nft_expr *expr,
|
|||
const struct nft_tproxy *priv = nft_expr_priv(expr);
|
||||
struct sk_buff *skb = pkt->skb;
|
||||
const struct ipv6hdr *iph = ipv6_hdr(skb);
|
||||
struct in6_addr taddr;
|
||||
int thoff = pkt->xt.thoff;
|
||||
int thoff = nft_thoff(pkt);
|
||||
struct udphdr _hdr, *hp;
|
||||
struct in6_addr taddr;
|
||||
__be16 tport = 0;
|
||||
struct sock *sk;
|
||||
int l4proto;
|
||||
|
|
|
@ -117,7 +117,7 @@ static int audit_tg_check(const struct xt_tgchk_param *par)
|
|||
const struct xt_audit_info *info = par->targinfo;
|
||||
|
||||
if (info->type > XT_AUDIT_TYPE_MAX) {
|
||||
pr_info_ratelimited("Audit type out of range (valid range: 0..%hhu)\n",
|
||||
pr_info_ratelimited("Audit type out of range (valid range: 0..%u)\n",
|
||||
XT_AUDIT_TYPE_MAX);
|
||||
return -ERANGE;
|
||||
}
|
||||
|
|
|
@ -172,7 +172,6 @@ static int xt_ct_tg_check(const struct xt_tgchk_param *par,
|
|||
goto err2;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
if ((info->ct_events || info->exp_events) &&
|
||||
!nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events,
|
||||
GFP_KERNEL)) {
|
||||
|
|
|
@ -8,16 +8,14 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter/xt_limit.h>
|
||||
|
||||
struct xt_limit_priv {
|
||||
spinlock_t lock;
|
||||
unsigned long prev;
|
||||
uint32_t credit;
|
||||
u32 credit;
|
||||
};
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -66,22 +64,31 @@ limit_mt(const struct sk_buff *skb, struct xt_action_param *par)
|
|||
{
|
||||
const struct xt_rateinfo *r = par->matchinfo;
|
||||
struct xt_limit_priv *priv = r->master;
|
||||
unsigned long now = jiffies;
|
||||
unsigned long now;
|
||||
u32 old_credit, new_credit, credit_increase = 0;
|
||||
bool ret;
|
||||
|
||||
spin_lock_bh(&priv->lock);
|
||||
priv->credit += (now - xchg(&priv->prev, now)) * CREDITS_PER_JIFFY;
|
||||
if (priv->credit > r->credit_cap)
|
||||
priv->credit = r->credit_cap;
|
||||
/* fastpath if there is nothing to update */
|
||||
if ((READ_ONCE(priv->credit) < r->cost) && (READ_ONCE(priv->prev) == jiffies))
|
||||
return false;
|
||||
|
||||
if (priv->credit >= r->cost) {
|
||||
/* We're not limited. */
|
||||
priv->credit -= r->cost;
|
||||
spin_unlock_bh(&priv->lock);
|
||||
return true;
|
||||
}
|
||||
do {
|
||||
now = jiffies;
|
||||
credit_increase += (now - xchg(&priv->prev, now)) * CREDITS_PER_JIFFY;
|
||||
old_credit = READ_ONCE(priv->credit);
|
||||
new_credit = old_credit;
|
||||
new_credit += credit_increase;
|
||||
if (new_credit > r->credit_cap)
|
||||
new_credit = r->credit_cap;
|
||||
if (new_credit >= r->cost) {
|
||||
ret = true;
|
||||
new_credit -= r->cost;
|
||||
} else {
|
||||
ret = false;
|
||||
}
|
||||
} while (cmpxchg(&priv->credit, old_credit, new_credit) != old_credit);
|
||||
|
||||
spin_unlock_bh(&priv->lock);
|
||||
return false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Precision saver. */
|
||||
|
@ -122,7 +129,6 @@ static int limit_mt_check(const struct xt_mtchk_param *par)
|
|||
r->credit_cap = priv->credit; /* Credits full. */
|
||||
r->cost = user2credits(r->avg);
|
||||
}
|
||||
spin_lock_init(&priv->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче