mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-22 10:34:55 +08:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next
Pablo Neira Ayuso says: ==================== Netfilter updates for net-next The following batch contains Netfilter updates for net-next: 1) Split flowtable workqueues per events, from Oz Shlomo. 2) fall-through warnings for clang, from Gustavo A. R. Silva 3) Remove unused declaration in conntrack, from YueHaibing. 4) Consolidate skb_try_make_writable() in flowtable datapath, simplify some of the existing codebase. 5) Call dst_check() to fall back to static classic forwarding path. 6) Update table flags from commit phase. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
9a255a0635
@ -4,7 +4,4 @@
|
||||
|
||||
extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6;
|
||||
|
||||
#include <linux/sysctl.h>
|
||||
extern struct ctl_table nf_ct_ipv6_sysctl_table[];
|
||||
|
||||
#endif /* _NF_CONNTRACK_IPV6_H*/
|
||||
|
@ -86,8 +86,8 @@ static inline bool nf_flowtable_hw_offload(struct nf_flowtable *flowtable)
|
||||
enum flow_offload_tuple_dir {
|
||||
FLOW_OFFLOAD_DIR_ORIGINAL = IP_CT_DIR_ORIGINAL,
|
||||
FLOW_OFFLOAD_DIR_REPLY = IP_CT_DIR_REPLY,
|
||||
FLOW_OFFLOAD_DIR_MAX = IP_CT_DIR_MAX
|
||||
};
|
||||
#define FLOW_OFFLOAD_DIR_MAX IP_CT_DIR_MAX
|
||||
|
||||
struct flow_offload_tuple {
|
||||
union {
|
||||
@ -229,12 +229,12 @@ void nf_flow_table_free(struct nf_flowtable *flow_table);
|
||||
|
||||
void flow_offload_teardown(struct flow_offload *flow);
|
||||
|
||||
int nf_flow_snat_port(const struct flow_offload *flow,
|
||||
struct sk_buff *skb, unsigned int thoff,
|
||||
u8 protocol, enum flow_offload_tuple_dir dir);
|
||||
int nf_flow_dnat_port(const struct flow_offload *flow,
|
||||
struct sk_buff *skb, unsigned int thoff,
|
||||
u8 protocol, enum flow_offload_tuple_dir dir);
|
||||
void nf_flow_snat_port(const struct flow_offload *flow,
|
||||
struct sk_buff *skb, unsigned int thoff,
|
||||
u8 protocol, enum flow_offload_tuple_dir dir);
|
||||
void nf_flow_dnat_port(const struct flow_offload *flow,
|
||||
struct sk_buff *skb, unsigned int thoff,
|
||||
u8 protocol, enum flow_offload_tuple_dir dir);
|
||||
|
||||
struct flow_ports {
|
||||
__be16 source, dest;
|
||||
|
@ -1498,13 +1498,16 @@ struct nft_trans_chain {
|
||||
|
||||
struct nft_trans_table {
|
||||
bool update;
|
||||
bool enable;
|
||||
u8 state;
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
#define nft_trans_table_update(trans) \
|
||||
(((struct nft_trans_table *)trans->data)->update)
|
||||
#define nft_trans_table_enable(trans) \
|
||||
(((struct nft_trans_table *)trans->data)->enable)
|
||||
#define nft_trans_table_state(trans) \
|
||||
(((struct nft_trans_table *)trans->data)->state)
|
||||
#define nft_trans_table_flags(trans) \
|
||||
(((struct nft_trans_table *)trans->data)->flags)
|
||||
|
||||
struct nft_trans_elem {
|
||||
struct nft_set *set;
|
||||
|
@ -397,6 +397,7 @@ dccp_new(struct nf_conn *ct, const struct sk_buff *skb,
|
||||
msg = "not picking up existing connection ";
|
||||
goto out_invalid;
|
||||
}
|
||||
break;
|
||||
case CT_DCCP_REQUEST:
|
||||
break;
|
||||
case CT_DCCP_INVALID:
|
||||
|
@ -389,29 +389,20 @@ static void nf_flow_offload_work_gc(struct work_struct *work)
|
||||
queue_delayed_work(system_power_efficient_wq, &flow_table->gc_work, HZ);
|
||||
}
|
||||
|
||||
|
||||
static int nf_flow_nat_port_tcp(struct sk_buff *skb, unsigned int thoff,
|
||||
__be16 port, __be16 new_port)
|
||||
static void nf_flow_nat_port_tcp(struct sk_buff *skb, unsigned int thoff,
|
||||
__be16 port, __be16 new_port)
|
||||
{
|
||||
struct tcphdr *tcph;
|
||||
|
||||
if (skb_try_make_writable(skb, thoff + sizeof(*tcph)))
|
||||
return -1;
|
||||
|
||||
tcph = (void *)(skb_network_header(skb) + thoff);
|
||||
inet_proto_csum_replace2(&tcph->check, skb, port, new_port, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nf_flow_nat_port_udp(struct sk_buff *skb, unsigned int thoff,
|
||||
__be16 port, __be16 new_port)
|
||||
static void nf_flow_nat_port_udp(struct sk_buff *skb, unsigned int thoff,
|
||||
__be16 port, __be16 new_port)
|
||||
{
|
||||
struct udphdr *udph;
|
||||
|
||||
if (skb_try_make_writable(skb, thoff + sizeof(*udph)))
|
||||
return -1;
|
||||
|
||||
udph = (void *)(skb_network_header(skb) + thoff);
|
||||
if (udph->check || skb->ip_summed == CHECKSUM_PARTIAL) {
|
||||
inet_proto_csum_replace2(&udph->check, skb, port,
|
||||
@ -419,37 +410,28 @@ static int nf_flow_nat_port_udp(struct sk_buff *skb, unsigned int thoff,
|
||||
if (!udph->check)
|
||||
udph->check = CSUM_MANGLED_0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nf_flow_nat_port(struct sk_buff *skb, unsigned int thoff,
|
||||
u8 protocol, __be16 port, __be16 new_port)
|
||||
static void nf_flow_nat_port(struct sk_buff *skb, unsigned int thoff,
|
||||
u8 protocol, __be16 port, __be16 new_port)
|
||||
{
|
||||
switch (protocol) {
|
||||
case IPPROTO_TCP:
|
||||
if (nf_flow_nat_port_tcp(skb, thoff, port, new_port) < 0)
|
||||
return NF_DROP;
|
||||
nf_flow_nat_port_tcp(skb, thoff, port, new_port);
|
||||
break;
|
||||
case IPPROTO_UDP:
|
||||
if (nf_flow_nat_port_udp(skb, thoff, port, new_port) < 0)
|
||||
return NF_DROP;
|
||||
nf_flow_nat_port_udp(skb, thoff, port, new_port);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nf_flow_snat_port(const struct flow_offload *flow,
|
||||
struct sk_buff *skb, unsigned int thoff,
|
||||
u8 protocol, enum flow_offload_tuple_dir dir)
|
||||
void nf_flow_snat_port(const struct flow_offload *flow,
|
||||
struct sk_buff *skb, unsigned int thoff,
|
||||
u8 protocol, enum flow_offload_tuple_dir dir)
|
||||
{
|
||||
struct flow_ports *hdr;
|
||||
__be16 port, new_port;
|
||||
|
||||
if (skb_try_make_writable(skb, thoff + sizeof(*hdr)))
|
||||
return -1;
|
||||
|
||||
hdr = (void *)(skb_network_header(skb) + thoff);
|
||||
|
||||
switch (dir) {
|
||||
@ -463,24 +445,19 @@ int nf_flow_snat_port(const struct flow_offload *flow,
|
||||
new_port = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.src_port;
|
||||
hdr->dest = new_port;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return nf_flow_nat_port(skb, thoff, protocol, port, new_port);
|
||||
nf_flow_nat_port(skb, thoff, protocol, port, new_port);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_flow_snat_port);
|
||||
|
||||
int nf_flow_dnat_port(const struct flow_offload *flow,
|
||||
struct sk_buff *skb, unsigned int thoff,
|
||||
u8 protocol, enum flow_offload_tuple_dir dir)
|
||||
void nf_flow_dnat_port(const struct flow_offload *flow, struct sk_buff *skb,
|
||||
unsigned int thoff, u8 protocol,
|
||||
enum flow_offload_tuple_dir dir)
|
||||
{
|
||||
struct flow_ports *hdr;
|
||||
__be16 port, new_port;
|
||||
|
||||
if (skb_try_make_writable(skb, thoff + sizeof(*hdr)))
|
||||
return -1;
|
||||
|
||||
hdr = (void *)(skb_network_header(skb) + thoff);
|
||||
|
||||
switch (dir) {
|
||||
@ -494,11 +471,9 @@ int nf_flow_dnat_port(const struct flow_offload *flow,
|
||||
new_port = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.dst_port;
|
||||
hdr->source = new_port;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return nf_flow_nat_port(skb, thoff, protocol, port, new_port);
|
||||
nf_flow_nat_port(skb, thoff, protocol, port, new_port);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_flow_dnat_port);
|
||||
|
||||
|
@ -34,28 +34,20 @@ static int nf_flow_state_check(struct flow_offload *flow, int proto,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nf_flow_nat_ip_tcp(struct sk_buff *skb, unsigned int thoff,
|
||||
__be32 addr, __be32 new_addr)
|
||||
static void nf_flow_nat_ip_tcp(struct sk_buff *skb, unsigned int thoff,
|
||||
__be32 addr, __be32 new_addr)
|
||||
{
|
||||
struct tcphdr *tcph;
|
||||
|
||||
if (skb_try_make_writable(skb, thoff + sizeof(*tcph)))
|
||||
return -1;
|
||||
|
||||
tcph = (void *)(skb_network_header(skb) + thoff);
|
||||
inet_proto_csum_replace4(&tcph->check, skb, addr, new_addr, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nf_flow_nat_ip_udp(struct sk_buff *skb, unsigned int thoff,
|
||||
__be32 addr, __be32 new_addr)
|
||||
static void nf_flow_nat_ip_udp(struct sk_buff *skb, unsigned int thoff,
|
||||
__be32 addr, __be32 new_addr)
|
||||
{
|
||||
struct udphdr *udph;
|
||||
|
||||
if (skb_try_make_writable(skb, thoff + sizeof(*udph)))
|
||||
return -1;
|
||||
|
||||
udph = (void *)(skb_network_header(skb) + thoff);
|
||||
if (udph->check || skb->ip_summed == CHECKSUM_PARTIAL) {
|
||||
inet_proto_csum_replace4(&udph->check, skb, addr,
|
||||
@ -63,31 +55,25 @@ static int nf_flow_nat_ip_udp(struct sk_buff *skb, unsigned int thoff,
|
||||
if (!udph->check)
|
||||
udph->check = CSUM_MANGLED_0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nf_flow_nat_ip_l4proto(struct sk_buff *skb, struct iphdr *iph,
|
||||
unsigned int thoff, __be32 addr,
|
||||
__be32 new_addr)
|
||||
static void nf_flow_nat_ip_l4proto(struct sk_buff *skb, struct iphdr *iph,
|
||||
unsigned int thoff, __be32 addr,
|
||||
__be32 new_addr)
|
||||
{
|
||||
switch (iph->protocol) {
|
||||
case IPPROTO_TCP:
|
||||
if (nf_flow_nat_ip_tcp(skb, thoff, addr, new_addr) < 0)
|
||||
return NF_DROP;
|
||||
nf_flow_nat_ip_tcp(skb, thoff, addr, new_addr);
|
||||
break;
|
||||
case IPPROTO_UDP:
|
||||
if (nf_flow_nat_ip_udp(skb, thoff, addr, new_addr) < 0)
|
||||
return NF_DROP;
|
||||
nf_flow_nat_ip_udp(skb, thoff, addr, new_addr);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nf_flow_snat_ip(const struct flow_offload *flow, struct sk_buff *skb,
|
||||
struct iphdr *iph, unsigned int thoff,
|
||||
enum flow_offload_tuple_dir dir)
|
||||
static void nf_flow_snat_ip(const struct flow_offload *flow,
|
||||
struct sk_buff *skb, struct iphdr *iph,
|
||||
unsigned int thoff, enum flow_offload_tuple_dir dir)
|
||||
{
|
||||
__be32 addr, new_addr;
|
||||
|
||||
@ -102,17 +88,15 @@ static int nf_flow_snat_ip(const struct flow_offload *flow, struct sk_buff *skb,
|
||||
new_addr = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.src_v4.s_addr;
|
||||
iph->daddr = new_addr;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
csum_replace4(&iph->check, addr, new_addr);
|
||||
|
||||
return nf_flow_nat_ip_l4proto(skb, iph, thoff, addr, new_addr);
|
||||
nf_flow_nat_ip_l4proto(skb, iph, thoff, addr, new_addr);
|
||||
}
|
||||
|
||||
static int nf_flow_dnat_ip(const struct flow_offload *flow, struct sk_buff *skb,
|
||||
struct iphdr *iph, unsigned int thoff,
|
||||
enum flow_offload_tuple_dir dir)
|
||||
static void nf_flow_dnat_ip(const struct flow_offload *flow,
|
||||
struct sk_buff *skb, struct iphdr *iph,
|
||||
unsigned int thoff, enum flow_offload_tuple_dir dir)
|
||||
{
|
||||
__be32 addr, new_addr;
|
||||
|
||||
@ -127,31 +111,24 @@ static int nf_flow_dnat_ip(const struct flow_offload *flow, struct sk_buff *skb,
|
||||
new_addr = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.dst_v4.s_addr;
|
||||
iph->saddr = new_addr;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
csum_replace4(&iph->check, addr, new_addr);
|
||||
|
||||
return nf_flow_nat_ip_l4proto(skb, iph, thoff, addr, new_addr);
|
||||
nf_flow_nat_ip_l4proto(skb, iph, thoff, addr, new_addr);
|
||||
}
|
||||
|
||||
static int nf_flow_nat_ip(const struct flow_offload *flow, struct sk_buff *skb,
|
||||
unsigned int thoff, enum flow_offload_tuple_dir dir)
|
||||
static void nf_flow_nat_ip(const struct flow_offload *flow, struct sk_buff *skb,
|
||||
unsigned int thoff, enum flow_offload_tuple_dir dir,
|
||||
struct iphdr *iph)
|
||||
{
|
||||
struct iphdr *iph = ip_hdr(skb);
|
||||
|
||||
if (test_bit(NF_FLOW_SNAT, &flow->flags) &&
|
||||
(nf_flow_snat_port(flow, skb, thoff, iph->protocol, dir) < 0 ||
|
||||
nf_flow_snat_ip(flow, skb, ip_hdr(skb), thoff, dir) < 0))
|
||||
return -1;
|
||||
|
||||
iph = ip_hdr(skb);
|
||||
if (test_bit(NF_FLOW_DNAT, &flow->flags) &&
|
||||
(nf_flow_dnat_port(flow, skb, thoff, iph->protocol, dir) < 0 ||
|
||||
nf_flow_dnat_ip(flow, skb, ip_hdr(skb), thoff, dir) < 0))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
if (test_bit(NF_FLOW_SNAT, &flow->flags)) {
|
||||
nf_flow_snat_port(flow, skb, thoff, iph->protocol, dir);
|
||||
nf_flow_snat_ip(flow, skb, iph, thoff, dir);
|
||||
}
|
||||
if (test_bit(NF_FLOW_DNAT, &flow->flags)) {
|
||||
nf_flow_dnat_port(flow, skb, thoff, iph->protocol, dir);
|
||||
nf_flow_dnat_ip(flow, skb, iph, thoff, dir);
|
||||
}
|
||||
}
|
||||
|
||||
static bool ip_has_options(unsigned int thoff)
|
||||
@ -160,10 +137,10 @@ static bool ip_has_options(unsigned int thoff)
|
||||
}
|
||||
|
||||
static int nf_flow_tuple_ip(struct sk_buff *skb, const struct net_device *dev,
|
||||
struct flow_offload_tuple *tuple)
|
||||
struct flow_offload_tuple *tuple, u32 *hdrsize)
|
||||
{
|
||||
unsigned int thoff, hdrsize;
|
||||
struct flow_ports *ports;
|
||||
unsigned int thoff;
|
||||
struct iphdr *iph;
|
||||
|
||||
if (!pskb_may_pull(skb, sizeof(*iph)))
|
||||
@ -178,10 +155,10 @@ static int nf_flow_tuple_ip(struct sk_buff *skb, const struct net_device *dev,
|
||||
|
||||
switch (iph->protocol) {
|
||||
case IPPROTO_TCP:
|
||||
hdrsize = sizeof(struct tcphdr);
|
||||
*hdrsize = sizeof(struct tcphdr);
|
||||
break;
|
||||
case IPPROTO_UDP:
|
||||
hdrsize = sizeof(struct udphdr);
|
||||
*hdrsize = sizeof(struct udphdr);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
@ -191,7 +168,7 @@ static int nf_flow_tuple_ip(struct sk_buff *skb, const struct net_device *dev,
|
||||
return -1;
|
||||
|
||||
thoff = iph->ihl * 4;
|
||||
if (!pskb_may_pull(skb, thoff + hdrsize))
|
||||
if (!pskb_may_pull(skb, thoff + *hdrsize))
|
||||
return -1;
|
||||
|
||||
iph = ip_hdr(skb);
|
||||
@ -220,14 +197,6 @@ static bool nf_flow_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu)
|
||||
return true;
|
||||
}
|
||||
|
||||
static int nf_flow_offload_dst_check(struct dst_entry *dst)
|
||||
{
|
||||
if (unlikely(dst_xfrm(dst)))
|
||||
return dst_check(dst, 0) ? 0 : -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int nf_flow_xmit_xfrm(struct sk_buff *skb,
|
||||
const struct nf_hook_state *state,
|
||||
struct dst_entry *dst)
|
||||
@ -252,11 +221,12 @@ nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
|
||||
unsigned int thoff;
|
||||
struct iphdr *iph;
|
||||
__be32 nexthop;
|
||||
u32 hdrsize;
|
||||
|
||||
if (skb->protocol != htons(ETH_P_IP))
|
||||
return NF_ACCEPT;
|
||||
|
||||
if (nf_flow_tuple_ip(skb, state->in, &tuple) < 0)
|
||||
if (nf_flow_tuple_ip(skb, state->in, &tuple, &hdrsize) < 0)
|
||||
return NF_ACCEPT;
|
||||
|
||||
tuplehash = flow_offload_lookup(flow_table, &tuple);
|
||||
@ -271,24 +241,24 @@ nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
|
||||
if (unlikely(nf_flow_exceeds_mtu(skb, flow->tuplehash[dir].tuple.mtu)))
|
||||
return NF_ACCEPT;
|
||||
|
||||
if (skb_try_make_writable(skb, sizeof(*iph)))
|
||||
return NF_DROP;
|
||||
|
||||
thoff = ip_hdr(skb)->ihl * 4;
|
||||
if (nf_flow_state_check(flow, ip_hdr(skb)->protocol, skb, thoff))
|
||||
iph = ip_hdr(skb);
|
||||
thoff = iph->ihl * 4;
|
||||
if (nf_flow_state_check(flow, iph->protocol, skb, thoff))
|
||||
return NF_ACCEPT;
|
||||
|
||||
flow_offload_refresh(flow_table, flow);
|
||||
|
||||
if (nf_flow_offload_dst_check(&rt->dst)) {
|
||||
if (!dst_check(&rt->dst, 0)) {
|
||||
flow_offload_teardown(flow);
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
if (nf_flow_nat_ip(flow, skb, thoff, dir) < 0)
|
||||
if (skb_try_make_writable(skb, thoff + hdrsize))
|
||||
return NF_DROP;
|
||||
|
||||
flow_offload_refresh(flow_table, flow);
|
||||
|
||||
iph = ip_hdr(skb);
|
||||
nf_flow_nat_ip(flow, skb, thoff, dir, iph);
|
||||
|
||||
ip_decrease_ttl(iph);
|
||||
skb->tstamp = 0;
|
||||
|
||||
@ -311,31 +281,24 @@ nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_flow_offload_ip_hook);
|
||||
|
||||
static int nf_flow_nat_ipv6_tcp(struct sk_buff *skb, unsigned int thoff,
|
||||
struct in6_addr *addr,
|
||||
struct in6_addr *new_addr)
|
||||
static void nf_flow_nat_ipv6_tcp(struct sk_buff *skb, unsigned int thoff,
|
||||
struct in6_addr *addr,
|
||||
struct in6_addr *new_addr,
|
||||
struct ipv6hdr *ip6h)
|
||||
{
|
||||
struct tcphdr *tcph;
|
||||
|
||||
if (skb_try_make_writable(skb, thoff + sizeof(*tcph)))
|
||||
return -1;
|
||||
|
||||
tcph = (void *)(skb_network_header(skb) + thoff);
|
||||
inet_proto_csum_replace16(&tcph->check, skb, addr->s6_addr32,
|
||||
new_addr->s6_addr32, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nf_flow_nat_ipv6_udp(struct sk_buff *skb, unsigned int thoff,
|
||||
struct in6_addr *addr,
|
||||
struct in6_addr *new_addr)
|
||||
static void nf_flow_nat_ipv6_udp(struct sk_buff *skb, unsigned int thoff,
|
||||
struct in6_addr *addr,
|
||||
struct in6_addr *new_addr)
|
||||
{
|
||||
struct udphdr *udph;
|
||||
|
||||
if (skb_try_make_writable(skb, thoff + sizeof(*udph)))
|
||||
return -1;
|
||||
|
||||
udph = (void *)(skb_network_header(skb) + thoff);
|
||||
if (udph->check || skb->ip_summed == CHECKSUM_PARTIAL) {
|
||||
inet_proto_csum_replace16(&udph->check, skb, addr->s6_addr32,
|
||||
@ -343,32 +306,26 @@ static int nf_flow_nat_ipv6_udp(struct sk_buff *skb, unsigned int thoff,
|
||||
if (!udph->check)
|
||||
udph->check = CSUM_MANGLED_0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nf_flow_nat_ipv6_l4proto(struct sk_buff *skb, struct ipv6hdr *ip6h,
|
||||
unsigned int thoff, struct in6_addr *addr,
|
||||
struct in6_addr *new_addr)
|
||||
static void nf_flow_nat_ipv6_l4proto(struct sk_buff *skb, struct ipv6hdr *ip6h,
|
||||
unsigned int thoff, struct in6_addr *addr,
|
||||
struct in6_addr *new_addr)
|
||||
{
|
||||
switch (ip6h->nexthdr) {
|
||||
case IPPROTO_TCP:
|
||||
if (nf_flow_nat_ipv6_tcp(skb, thoff, addr, new_addr) < 0)
|
||||
return NF_DROP;
|
||||
nf_flow_nat_ipv6_tcp(skb, thoff, addr, new_addr, ip6h);
|
||||
break;
|
||||
case IPPROTO_UDP:
|
||||
if (nf_flow_nat_ipv6_udp(skb, thoff, addr, new_addr) < 0)
|
||||
return NF_DROP;
|
||||
nf_flow_nat_ipv6_udp(skb, thoff, addr, new_addr);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nf_flow_snat_ipv6(const struct flow_offload *flow,
|
||||
struct sk_buff *skb, struct ipv6hdr *ip6h,
|
||||
unsigned int thoff,
|
||||
enum flow_offload_tuple_dir dir)
|
||||
static void nf_flow_snat_ipv6(const struct flow_offload *flow,
|
||||
struct sk_buff *skb, struct ipv6hdr *ip6h,
|
||||
unsigned int thoff,
|
||||
enum flow_offload_tuple_dir dir)
|
||||
{
|
||||
struct in6_addr addr, new_addr;
|
||||
|
||||
@ -383,17 +340,15 @@ static int nf_flow_snat_ipv6(const struct flow_offload *flow,
|
||||
new_addr = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.src_v6;
|
||||
ip6h->daddr = new_addr;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return nf_flow_nat_ipv6_l4proto(skb, ip6h, thoff, &addr, &new_addr);
|
||||
nf_flow_nat_ipv6_l4proto(skb, ip6h, thoff, &addr, &new_addr);
|
||||
}
|
||||
|
||||
static int nf_flow_dnat_ipv6(const struct flow_offload *flow,
|
||||
struct sk_buff *skb, struct ipv6hdr *ip6h,
|
||||
unsigned int thoff,
|
||||
enum flow_offload_tuple_dir dir)
|
||||
static void nf_flow_dnat_ipv6(const struct flow_offload *flow,
|
||||
struct sk_buff *skb, struct ipv6hdr *ip6h,
|
||||
unsigned int thoff,
|
||||
enum flow_offload_tuple_dir dir)
|
||||
{
|
||||
struct in6_addr addr, new_addr;
|
||||
|
||||
@ -408,40 +363,34 @@ static int nf_flow_dnat_ipv6(const struct flow_offload *flow,
|
||||
new_addr = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.dst_v6;
|
||||
ip6h->saddr = new_addr;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return nf_flow_nat_ipv6_l4proto(skb, ip6h, thoff, &addr, &new_addr);
|
||||
nf_flow_nat_ipv6_l4proto(skb, ip6h, thoff, &addr, &new_addr);
|
||||
}
|
||||
|
||||
static int nf_flow_nat_ipv6(const struct flow_offload *flow,
|
||||
struct sk_buff *skb,
|
||||
enum flow_offload_tuple_dir dir)
|
||||
static void nf_flow_nat_ipv6(const struct flow_offload *flow,
|
||||
struct sk_buff *skb,
|
||||
enum flow_offload_tuple_dir dir,
|
||||
struct ipv6hdr *ip6h)
|
||||
{
|
||||
struct ipv6hdr *ip6h = ipv6_hdr(skb);
|
||||
unsigned int thoff = sizeof(*ip6h);
|
||||
|
||||
if (test_bit(NF_FLOW_SNAT, &flow->flags) &&
|
||||
(nf_flow_snat_port(flow, skb, thoff, ip6h->nexthdr, dir) < 0 ||
|
||||
nf_flow_snat_ipv6(flow, skb, ipv6_hdr(skb), thoff, dir) < 0))
|
||||
return -1;
|
||||
|
||||
ip6h = ipv6_hdr(skb);
|
||||
if (test_bit(NF_FLOW_DNAT, &flow->flags) &&
|
||||
(nf_flow_dnat_port(flow, skb, thoff, ip6h->nexthdr, dir) < 0 ||
|
||||
nf_flow_dnat_ipv6(flow, skb, ipv6_hdr(skb), thoff, dir) < 0))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
if (test_bit(NF_FLOW_SNAT, &flow->flags)) {
|
||||
nf_flow_snat_port(flow, skb, thoff, ip6h->nexthdr, dir);
|
||||
nf_flow_snat_ipv6(flow, skb, ip6h, thoff, dir);
|
||||
}
|
||||
if (test_bit(NF_FLOW_DNAT, &flow->flags)) {
|
||||
nf_flow_dnat_port(flow, skb, thoff, ip6h->nexthdr, dir);
|
||||
nf_flow_dnat_ipv6(flow, skb, ip6h, thoff, dir);
|
||||
}
|
||||
}
|
||||
|
||||
static int nf_flow_tuple_ipv6(struct sk_buff *skb, const struct net_device *dev,
|
||||
struct flow_offload_tuple *tuple)
|
||||
struct flow_offload_tuple *tuple, u32 *hdrsize)
|
||||
{
|
||||
unsigned int thoff, hdrsize;
|
||||
struct flow_ports *ports;
|
||||
struct ipv6hdr *ip6h;
|
||||
unsigned int thoff;
|
||||
|
||||
if (!pskb_may_pull(skb, sizeof(*ip6h)))
|
||||
return -1;
|
||||
@ -450,10 +399,10 @@ static int nf_flow_tuple_ipv6(struct sk_buff *skb, const struct net_device *dev,
|
||||
|
||||
switch (ip6h->nexthdr) {
|
||||
case IPPROTO_TCP:
|
||||
hdrsize = sizeof(struct tcphdr);
|
||||
*hdrsize = sizeof(struct tcphdr);
|
||||
break;
|
||||
case IPPROTO_UDP:
|
||||
hdrsize = sizeof(struct udphdr);
|
||||
*hdrsize = sizeof(struct udphdr);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
@ -463,7 +412,7 @@ static int nf_flow_tuple_ipv6(struct sk_buff *skb, const struct net_device *dev,
|
||||
return -1;
|
||||
|
||||
thoff = sizeof(*ip6h);
|
||||
if (!pskb_may_pull(skb, thoff + hdrsize))
|
||||
if (!pskb_may_pull(skb, thoff + *hdrsize))
|
||||
return -1;
|
||||
|
||||
ip6h = ipv6_hdr(skb);
|
||||
@ -493,11 +442,12 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
|
||||
struct net_device *outdev;
|
||||
struct ipv6hdr *ip6h;
|
||||
struct rt6_info *rt;
|
||||
u32 hdrsize;
|
||||
|
||||
if (skb->protocol != htons(ETH_P_IPV6))
|
||||
return NF_ACCEPT;
|
||||
|
||||
if (nf_flow_tuple_ipv6(skb, state->in, &tuple) < 0)
|
||||
if (nf_flow_tuple_ipv6(skb, state->in, &tuple, &hdrsize) < 0)
|
||||
return NF_ACCEPT;
|
||||
|
||||
tuplehash = flow_offload_lookup(flow_table, &tuple);
|
||||
@ -516,20 +466,19 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
|
||||
sizeof(*ip6h)))
|
||||
return NF_ACCEPT;
|
||||
|
||||
flow_offload_refresh(flow_table, flow);
|
||||
|
||||
if (nf_flow_offload_dst_check(&rt->dst)) {
|
||||
if (!dst_check(&rt->dst, 0)) {
|
||||
flow_offload_teardown(flow);
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
if (skb_try_make_writable(skb, sizeof(*ip6h)))
|
||||
if (skb_try_make_writable(skb, sizeof(*ip6h) + hdrsize))
|
||||
return NF_DROP;
|
||||
|
||||
if (nf_flow_nat_ipv6(flow, skb, dir) < 0)
|
||||
return NF_DROP;
|
||||
flow_offload_refresh(flow_table, flow);
|
||||
|
||||
ip6h = ipv6_hdr(skb);
|
||||
nf_flow_nat_ipv6(flow, skb, dir, ip6h);
|
||||
|
||||
ip6h->hop_limit--;
|
||||
skb->tstamp = 0;
|
||||
|
||||
|
@ -13,7 +13,9 @@
|
||||
#include <net/netfilter/nf_conntrack_core.h>
|
||||
#include <net/netfilter/nf_conntrack_tuple.h>
|
||||
|
||||
static struct workqueue_struct *nf_flow_offload_wq;
|
||||
static struct workqueue_struct *nf_flow_offload_add_wq;
|
||||
static struct workqueue_struct *nf_flow_offload_del_wq;
|
||||
static struct workqueue_struct *nf_flow_offload_stats_wq;
|
||||
|
||||
struct flow_offload_work {
|
||||
struct list_head list;
|
||||
@ -826,7 +828,12 @@ static void flow_offload_work_handler(struct work_struct *work)
|
||||
|
||||
static void flow_offload_queue_work(struct flow_offload_work *offload)
|
||||
{
|
||||
queue_work(nf_flow_offload_wq, &offload->work);
|
||||
if (offload->cmd == FLOW_CLS_REPLACE)
|
||||
queue_work(nf_flow_offload_add_wq, &offload->work);
|
||||
else if (offload->cmd == FLOW_CLS_DESTROY)
|
||||
queue_work(nf_flow_offload_del_wq, &offload->work);
|
||||
else
|
||||
queue_work(nf_flow_offload_stats_wq, &offload->work);
|
||||
}
|
||||
|
||||
static struct flow_offload_work *
|
||||
@ -898,8 +905,11 @@ void nf_flow_offload_stats(struct nf_flowtable *flowtable,
|
||||
|
||||
void nf_flow_table_offload_flush(struct nf_flowtable *flowtable)
|
||||
{
|
||||
if (nf_flowtable_hw_offload(flowtable))
|
||||
flush_workqueue(nf_flow_offload_wq);
|
||||
if (nf_flowtable_hw_offload(flowtable)) {
|
||||
flush_workqueue(nf_flow_offload_add_wq);
|
||||
flush_workqueue(nf_flow_offload_del_wq);
|
||||
flush_workqueue(nf_flow_offload_stats_wq);
|
||||
}
|
||||
}
|
||||
|
||||
static int nf_flow_table_block_setup(struct nf_flowtable *flowtable,
|
||||
@ -1011,15 +1021,33 @@ EXPORT_SYMBOL_GPL(nf_flow_table_offload_setup);
|
||||
|
||||
int nf_flow_table_offload_init(void)
|
||||
{
|
||||
nf_flow_offload_wq = alloc_workqueue("nf_flow_table_offload",
|
||||
WQ_UNBOUND, 0);
|
||||
if (!nf_flow_offload_wq)
|
||||
nf_flow_offload_add_wq = alloc_workqueue("nf_ft_offload_add",
|
||||
WQ_UNBOUND | WQ_SYSFS, 0);
|
||||
if (!nf_flow_offload_add_wq)
|
||||
return -ENOMEM;
|
||||
|
||||
nf_flow_offload_del_wq = alloc_workqueue("nf_ft_offload_del",
|
||||
WQ_UNBOUND | WQ_SYSFS, 0);
|
||||
if (!nf_flow_offload_del_wq)
|
||||
goto err_del_wq;
|
||||
|
||||
nf_flow_offload_stats_wq = alloc_workqueue("nf_ft_offload_stats",
|
||||
WQ_UNBOUND | WQ_SYSFS, 0);
|
||||
if (!nf_flow_offload_stats_wq)
|
||||
goto err_stats_wq;
|
||||
|
||||
return 0;
|
||||
|
||||
err_stats_wq:
|
||||
destroy_workqueue(nf_flow_offload_del_wq);
|
||||
err_del_wq:
|
||||
destroy_workqueue(nf_flow_offload_add_wq);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
void nf_flow_table_offload_exit(void)
|
||||
{
|
||||
destroy_workqueue(nf_flow_offload_wq);
|
||||
destroy_workqueue(nf_flow_offload_add_wq);
|
||||
destroy_workqueue(nf_flow_offload_del_wq);
|
||||
destroy_workqueue(nf_flow_offload_stats_wq);
|
||||
}
|
||||
|
@ -900,6 +900,12 @@ static void nf_tables_table_disable(struct net *net, struct nft_table *table)
|
||||
nft_table_disable(net, table, 0);
|
||||
}
|
||||
|
||||
enum {
|
||||
NFT_TABLE_STATE_UNCHANGED = 0,
|
||||
NFT_TABLE_STATE_DORMANT,
|
||||
NFT_TABLE_STATE_WAKEUP
|
||||
};
|
||||
|
||||
static int nf_tables_updtable(struct nft_ctx *ctx)
|
||||
{
|
||||
struct nft_trans *trans;
|
||||
@ -929,19 +935,17 @@ static int nf_tables_updtable(struct nft_ctx *ctx)
|
||||
|
||||
if ((flags & NFT_TABLE_F_DORMANT) &&
|
||||
!(ctx->table->flags & NFT_TABLE_F_DORMANT)) {
|
||||
nft_trans_table_enable(trans) = false;
|
||||
nft_trans_table_state(trans) = NFT_TABLE_STATE_DORMANT;
|
||||
} else if (!(flags & NFT_TABLE_F_DORMANT) &&
|
||||
ctx->table->flags & NFT_TABLE_F_DORMANT) {
|
||||
ctx->table->flags &= ~NFT_TABLE_F_DORMANT;
|
||||
ret = nf_tables_table_enable(ctx->net, ctx->table);
|
||||
if (ret >= 0)
|
||||
nft_trans_table_enable(trans) = true;
|
||||
else
|
||||
ctx->table->flags |= NFT_TABLE_F_DORMANT;
|
||||
nft_trans_table_state(trans) = NFT_TABLE_STATE_WAKEUP;
|
||||
}
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
nft_trans_table_flags(trans) = flags;
|
||||
nft_trans_table_update(trans) = true;
|
||||
list_add_tail(&trans->list, &ctx->net->nft.commit_list);
|
||||
return 0;
|
||||
@ -8068,11 +8072,10 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
|
||||
switch (trans->msg_type) {
|
||||
case NFT_MSG_NEWTABLE:
|
||||
if (nft_trans_table_update(trans)) {
|
||||
if (!nft_trans_table_enable(trans)) {
|
||||
nf_tables_table_disable(net,
|
||||
trans->ctx.table);
|
||||
trans->ctx.table->flags |= NFT_TABLE_F_DORMANT;
|
||||
}
|
||||
if (nft_trans_table_state(trans) == NFT_TABLE_STATE_DORMANT)
|
||||
nf_tables_table_disable(net, trans->ctx.table);
|
||||
|
||||
trans->ctx.table->flags = nft_trans_table_flags(trans);
|
||||
} else {
|
||||
nft_clear(net, trans->ctx.table);
|
||||
}
|
||||
@ -8283,11 +8286,9 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
|
||||
switch (trans->msg_type) {
|
||||
case NFT_MSG_NEWTABLE:
|
||||
if (nft_trans_table_update(trans)) {
|
||||
if (nft_trans_table_enable(trans)) {
|
||||
nf_tables_table_disable(net,
|
||||
trans->ctx.table);
|
||||
trans->ctx.table->flags |= NFT_TABLE_F_DORMANT;
|
||||
}
|
||||
if (nft_trans_table_state(trans) == NFT_TABLE_STATE_WAKEUP)
|
||||
nf_tables_table_disable(net, trans->ctx.table);
|
||||
|
||||
nft_trans_destroy(trans);
|
||||
} else {
|
||||
list_del_rcu(&trans->ctx.table->list);
|
||||
@ -8557,6 +8558,7 @@ static int nf_tables_check_loops(const struct nft_ctx *ctx,
|
||||
data->verdict.chain);
|
||||
if (err < 0)
|
||||
return err;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -527,6 +527,7 @@ static void __nft_ct_set_destroy(const struct nft_ctx *ctx, struct nft_ct *priv)
|
||||
case NFT_CT_ZONE:
|
||||
if (--nft_ct_pcpu_template_refcnt == 0)
|
||||
nft_ct_tmpl_put_pcpu();
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user