Commit 5fe8e519 authored by David S. Miller's avatar David S. Miller

Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next

Pablo Neira Ayuso says:

====================
Netfilter updates for net-next

The following patchset contains Netfilter updates for net-next:

1) 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.
====================
parents 92c35cfd 8a1c08ad
......@@ -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;
err = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
MSG_DONTWAIT);
if (err < 0)
goto out;
return 0;
if (err <= 0) {
kfree_skb(skb2);
return -ENOMEM;
}
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;
err = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
MSG_DONTWAIT);
if (err < 0)
goto out;
return 0;
if (err <= 0) {
kfree_skb(skb2);
return -ENOMEM;
}
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;
err = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
MSG_DONTWAIT);
if (err < 0)
goto out;
return 0;
if (err <= 0) {
kfree_skb(skb2);
return -ENOMEM;
}
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 = &regs->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, &regs->data[priv->sreg], &ext) ^
priv->invert;
found = nft_set_do_lookup(net, set, &regs->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, &regs->data[priv->sreg], &ext);
found = nft_set_do_lookup(net, set, &regs->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;
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;
if (priv->credit >= r->cost) {
/* We're not limited. */
priv->credit -= r->cost;
spin_unlock_bh(&priv->lock);
return true;
}
spin_unlock_bh(&priv->lock);
return false;
unsigned long now;
u32 old_credit, new_credit, credit_increase = 0;
bool ret;
/* fastpath if there is nothing to update */
if ((READ_ONCE(priv->credit) < r->cost) && (READ_ONCE(priv->prev) == jiffies))
return false;
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);
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;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment