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

Merge branch 'netns-defrag'

Eric W. Biederman says:

====================
net: Pass net into defragmentation

This is the next installment of my work to pass struct net through the
output path so the code does not need to guess how to figure out which
network namespace it is in, and ultimately routes can have output
devices in another network namespace.

In netfilter and af_packet we defragment packets in the output path,
and there is the usual amount of confusion about how to compute which
net we are processing the packets in.  This patchset clears that
confusion up by explicitly passing in struct net in ip_defrag,
ip_check_defrag, and nf_ct_frag6_gather.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 161642e2 b7277597
...@@ -412,7 +412,7 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb) ...@@ -412,7 +412,7 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb)
port = macvlan_port_get_rcu(skb->dev); port = macvlan_port_get_rcu(skb->dev);
if (is_multicast_ether_addr(eth->h_dest)) { if (is_multicast_ether_addr(eth->h_dest)) {
skb = ip_check_defrag(skb, IP_DEFRAG_MACVLAN); skb = ip_check_defrag(dev_net(skb->dev), skb, IP_DEFRAG_MACVLAN);
if (!skb) if (!skb)
return RX_HANDLER_CONSUMED; return RX_HANDLER_CONSUMED;
eth = eth_hdr(skb); eth = eth_hdr(skb);
......
...@@ -506,11 +506,11 @@ static inline bool ip_defrag_user_in_between(u32 user, ...@@ -506,11 +506,11 @@ static inline bool ip_defrag_user_in_between(u32 user,
return user >= lower_bond && user <= upper_bond; return user >= lower_bond && user <= upper_bond;
} }
int ip_defrag(struct sk_buff *skb, u32 user); int ip_defrag(struct net *net, struct sk_buff *skb, u32 user);
#ifdef CONFIG_INET #ifdef CONFIG_INET
struct sk_buff *ip_check_defrag(struct sk_buff *skb, u32 user); struct sk_buff *ip_check_defrag(struct net *net, struct sk_buff *skb, u32 user);
#else #else
static inline struct sk_buff *ip_check_defrag(struct sk_buff *skb, u32 user) static inline struct sk_buff *ip_check_defrag(struct net *net, struct sk_buff *skb, u32 user)
{ {
return skb; return skb;
} }
......
...@@ -5,7 +5,7 @@ void nf_defrag_ipv6_enable(void); ...@@ -5,7 +5,7 @@ void nf_defrag_ipv6_enable(void);
int nf_ct_frag6_init(void); int nf_ct_frag6_init(void);
void nf_ct_frag6_cleanup(void); void nf_ct_frag6_cleanup(void);
struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user); struct sk_buff *nf_ct_frag6_gather(struct net *net, struct sk_buff *skb, u32 user);
void nf_ct_frag6_consume_orig(struct sk_buff *skb); void nf_ct_frag6_consume_orig(struct sk_buff *skb);
struct inet_frags_ctl; struct inet_frags_ctl;
......
...@@ -654,11 +654,10 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, ...@@ -654,11 +654,10 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
} }
/* Process an incoming IP datagram fragment. */ /* Process an incoming IP datagram fragment. */
int ip_defrag(struct sk_buff *skb, u32 user) int ip_defrag(struct net *net, struct sk_buff *skb, u32 user)
{ {
struct net_device *dev = skb->dev ? : skb_dst(skb)->dev; struct net_device *dev = skb->dev ? : skb_dst(skb)->dev;
int vif = l3mdev_master_ifindex_rcu(dev); int vif = l3mdev_master_ifindex_rcu(dev);
struct net *net = dev_net(dev);
struct ipq *qp; struct ipq *qp;
IP_INC_STATS_BH(net, IPSTATS_MIB_REASMREQDS); IP_INC_STATS_BH(net, IPSTATS_MIB_REASMREQDS);
...@@ -683,7 +682,7 @@ int ip_defrag(struct sk_buff *skb, u32 user) ...@@ -683,7 +682,7 @@ int ip_defrag(struct sk_buff *skb, u32 user)
} }
EXPORT_SYMBOL(ip_defrag); EXPORT_SYMBOL(ip_defrag);
struct sk_buff *ip_check_defrag(struct sk_buff *skb, u32 user) struct sk_buff *ip_check_defrag(struct net *net, struct sk_buff *skb, u32 user)
{ {
struct iphdr iph; struct iphdr iph;
int netoff; int netoff;
...@@ -712,7 +711,7 @@ struct sk_buff *ip_check_defrag(struct sk_buff *skb, u32 user) ...@@ -712,7 +711,7 @@ struct sk_buff *ip_check_defrag(struct sk_buff *skb, u32 user)
if (pskb_trim_rcsum(skb, netoff + len)) if (pskb_trim_rcsum(skb, netoff + len))
return skb; return skb;
memset(IPCB(skb), 0, sizeof(struct inet_skb_parm)); memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
if (ip_defrag(skb, user)) if (ip_defrag(net, skb, user))
return NULL; return NULL;
skb_clear_hash(skb); skb_clear_hash(skb);
} }
......
...@@ -157,6 +157,7 @@ bool ip_call_ra_chain(struct sk_buff *skb) ...@@ -157,6 +157,7 @@ bool ip_call_ra_chain(struct sk_buff *skb)
u8 protocol = ip_hdr(skb)->protocol; u8 protocol = ip_hdr(skb)->protocol;
struct sock *last = NULL; struct sock *last = NULL;
struct net_device *dev = skb->dev; struct net_device *dev = skb->dev;
struct net *net = dev_net(dev);
for (ra = rcu_dereference(ip_ra_chain); ra; ra = rcu_dereference(ra->next)) { for (ra = rcu_dereference(ip_ra_chain); ra; ra = rcu_dereference(ra->next)) {
struct sock *sk = ra->sk; struct sock *sk = ra->sk;
...@@ -167,9 +168,9 @@ bool ip_call_ra_chain(struct sk_buff *skb) ...@@ -167,9 +168,9 @@ bool ip_call_ra_chain(struct sk_buff *skb)
if (sk && inet_sk(sk)->inet_num == protocol && if (sk && inet_sk(sk)->inet_num == protocol &&
(!sk->sk_bound_dev_if || (!sk->sk_bound_dev_if ||
sk->sk_bound_dev_if == dev->ifindex) && sk->sk_bound_dev_if == dev->ifindex) &&
net_eq(sock_net(sk), dev_net(dev))) { net_eq(sock_net(sk), net)) {
if (ip_is_fragment(ip_hdr(skb))) { if (ip_is_fragment(ip_hdr(skb))) {
if (ip_defrag(skb, IP_DEFRAG_CALL_RA_CHAIN)) if (ip_defrag(net, skb, IP_DEFRAG_CALL_RA_CHAIN))
return true; return true;
} }
if (last) { if (last) {
...@@ -246,14 +247,15 @@ int ip_local_deliver(struct sk_buff *skb) ...@@ -246,14 +247,15 @@ int ip_local_deliver(struct sk_buff *skb)
/* /*
* Reassemble IP fragments. * Reassemble IP fragments.
*/ */
struct net *net = dev_net(skb->dev);
if (ip_is_fragment(ip_hdr(skb))) { if (ip_is_fragment(ip_hdr(skb))) {
if (ip_defrag(skb, IP_DEFRAG_LOCAL_DELIVER)) if (ip_defrag(net, skb, IP_DEFRAG_LOCAL_DELIVER))
return 0; return 0;
} }
return NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_IN, return NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_IN,
dev_net(skb->dev), NULL, skb, skb->dev, NULL, net, NULL, skb, skb->dev, NULL,
ip_local_deliver_finish); ip_local_deliver_finish);
} }
......
...@@ -22,14 +22,15 @@ ...@@ -22,14 +22,15 @@
#endif #endif
#include <net/netfilter/nf_conntrack_zones.h> #include <net/netfilter/nf_conntrack_zones.h>
static int nf_ct_ipv4_gather_frags(struct sk_buff *skb, u_int32_t user) static int nf_ct_ipv4_gather_frags(struct net *net, struct sk_buff *skb,
u_int32_t user)
{ {
int err; int err;
skb_orphan(skb); skb_orphan(skb);
local_bh_disable(); local_bh_disable();
err = ip_defrag(skb, user); err = ip_defrag(net, skb, user);
local_bh_enable(); local_bh_enable();
if (!err) { if (!err) {
...@@ -85,7 +86,7 @@ static unsigned int ipv4_conntrack_defrag(void *priv, ...@@ -85,7 +86,7 @@ static unsigned int ipv4_conntrack_defrag(void *priv,
enum ip_defrag_users user = enum ip_defrag_users user =
nf_ct_defrag_user(state->hook, skb); nf_ct_defrag_user(state->hook, skb);
if (nf_ct_ipv4_gather_frags(skb, user)) if (nf_ct_ipv4_gather_frags(state->net, skb, user))
return NF_STOLEN; return NF_STOLEN;
} }
return NF_ACCEPT; return NF_ACCEPT;
......
...@@ -563,12 +563,10 @@ find_prev_fhdr(struct sk_buff *skb, u8 *prevhdrp, int *prevhoff, int *fhoff) ...@@ -563,12 +563,10 @@ find_prev_fhdr(struct sk_buff *skb, u8 *prevhdrp, int *prevhoff, int *fhoff)
return 0; return 0;
} }
struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user) struct sk_buff *nf_ct_frag6_gather(struct net *net, struct sk_buff *skb, u32 user)
{ {
struct sk_buff *clone; struct sk_buff *clone;
struct net_device *dev = skb->dev; struct net_device *dev = skb->dev;
struct net *net = skb_dst(skb) ? dev_net(skb_dst(skb)->dev)
: dev_net(skb->dev);
struct frag_hdr *fhdr; struct frag_hdr *fhdr;
struct frag_queue *fq; struct frag_queue *fq;
struct ipv6hdr *hdr; struct ipv6hdr *hdr;
......
...@@ -63,7 +63,8 @@ static unsigned int ipv6_defrag(void *priv, ...@@ -63,7 +63,8 @@ static unsigned int ipv6_defrag(void *priv,
return NF_ACCEPT; return NF_ACCEPT;
#endif #endif
reasm = nf_ct_frag6_gather(skb, nf_ct6_defrag_user(state->hook, skb)); reasm = nf_ct_frag6_gather(state->net, skb,
nf_ct6_defrag_user(state->hook, skb));
/* queued */ /* queued */
if (reasm == NULL) if (reasm == NULL)
return NF_STOLEN; return NF_STOLEN;
......
...@@ -694,7 +694,7 @@ static inline int ip_vs_gather_frags(struct netns_ipvs *ipvs, ...@@ -694,7 +694,7 @@ static inline int ip_vs_gather_frags(struct netns_ipvs *ipvs,
int err; int err;
local_bh_disable(); local_bh_disable();
err = ip_defrag(skb, user); err = ip_defrag(ipvs->net, skb, user);
local_bh_enable(); local_bh_enable();
if (!err) if (!err)
ip_send_check(ip_hdr(skb)); ip_send_check(ip_hdr(skb));
......
...@@ -304,7 +304,7 @@ static int handle_fragments(struct net *net, struct sw_flow_key *key, ...@@ -304,7 +304,7 @@ static int handle_fragments(struct net *net, struct sw_flow_key *key,
int err; int err;
memset(IPCB(skb), 0, sizeof(struct inet_skb_parm)); memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
err = ip_defrag(skb, user); err = ip_defrag(net, skb, user);
if (err) if (err)
return err; return err;
...@@ -315,7 +315,7 @@ static int handle_fragments(struct net *net, struct sw_flow_key *key, ...@@ -315,7 +315,7 @@ static int handle_fragments(struct net *net, struct sw_flow_key *key,
struct sk_buff *reasm; struct sk_buff *reasm;
memset(IP6CB(skb), 0, sizeof(struct inet6_skb_parm)); memset(IP6CB(skb), 0, sizeof(struct inet6_skb_parm));
reasm = nf_ct_frag6_gather(skb, user); reasm = nf_ct_frag6_gather(net, skb, user);
if (!reasm) if (!reasm)
return -EINPROGRESS; return -EINPROGRESS;
......
...@@ -1439,17 +1439,17 @@ static int packet_rcv_fanout(struct sk_buff *skb, struct net_device *dev, ...@@ -1439,17 +1439,17 @@ static int packet_rcv_fanout(struct sk_buff *skb, struct net_device *dev,
{ {
struct packet_fanout *f = pt->af_packet_priv; struct packet_fanout *f = pt->af_packet_priv;
unsigned int num = READ_ONCE(f->num_members); unsigned int num = READ_ONCE(f->num_members);
struct net *net = read_pnet(&f->net);
struct packet_sock *po; struct packet_sock *po;
unsigned int idx; unsigned int idx;
if (!net_eq(dev_net(dev), read_pnet(&f->net)) || if (!net_eq(dev_net(dev), net) || !num) {
!num) {
kfree_skb(skb); kfree_skb(skb);
return 0; return 0;
} }
if (fanout_has_flag(f, PACKET_FANOUT_FLAG_DEFRAG)) { if (fanout_has_flag(f, PACKET_FANOUT_FLAG_DEFRAG)) {
skb = ip_check_defrag(skb, IP_DEFRAG_AF_PACKET); skb = ip_check_defrag(net, skb, IP_DEFRAG_AF_PACKET);
if (!skb) if (!skb)
return 0; 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