Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/net-next
Eric W. Biederman says: ==================== net: Pass net through ip fragmention 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. This round focuses on passing net through ip fragmentation which we seem to call from about everywhere. That is the main ip output paths, the bridge netfilter code, and openvswitch. This has to happend at once accross the tree as function pointers are involved. First some prep work is done, then ipv4 and ipv6 are converted and then temporary helper functions are removed. ==================== Acked-by: Nicolas Dichtel <nicolas.dichtel@6wind.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Коммит
40e106801e
|
@ -17,8 +17,8 @@ struct nf_ipv6_ops {
|
|||
int (*chk_addr)(struct net *net, const struct in6_addr *addr,
|
||||
const struct net_device *dev, int strict);
|
||||
void (*route_input)(struct sk_buff *skb);
|
||||
int (*fragment)(struct sock *sk, struct sk_buff *skb,
|
||||
int (*output)(struct sock *, struct sk_buff *));
|
||||
int (*fragment)(struct net *net, struct sock *sk, struct sk_buff *skb,
|
||||
int (*output)(struct net *, struct sock *, struct sk_buff *));
|
||||
};
|
||||
|
||||
#ifdef CONFIG_NETFILTER
|
||||
|
|
|
@ -109,8 +109,8 @@ int ip_local_deliver(struct sk_buff *skb);
|
|||
int ip_mr_input(struct sk_buff *skb);
|
||||
int ip_output(struct sock *sk, struct sk_buff *skb);
|
||||
int ip_mc_output(struct sock *sk, struct sk_buff *skb);
|
||||
int ip_do_fragment(struct sock *sk, struct sk_buff *skb,
|
||||
int (*output)(struct sock *, struct sk_buff *));
|
||||
int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
|
||||
int (*output)(struct net *, struct sock *, struct sk_buff *));
|
||||
void ip_send_check(struct iphdr *ip);
|
||||
int __ip_local_out(struct sk_buff *skb);
|
||||
int ip_local_out_sk(struct sock *sk, struct sk_buff *skb);
|
||||
|
|
|
@ -173,8 +173,8 @@ static inline bool ipv6_anycast_destination(const struct dst_entry *dst,
|
|||
ipv6_addr_equal(&rt->rt6i_dst.addr, daddr));
|
||||
}
|
||||
|
||||
int ip6_fragment(struct sock *sk, struct sk_buff *skb,
|
||||
int (*output)(struct sock *, struct sk_buff *));
|
||||
int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
|
||||
int (*output)(struct net *, struct sock *, struct sk_buff *));
|
||||
|
||||
static inline int ip6_skb_dst_mtu(struct sk_buff *skb)
|
||||
{
|
||||
|
|
|
@ -691,17 +691,12 @@ static int br_nf_push_frag_xmit(struct net *net, struct sock *sk, struct sk_buff
|
|||
nf_bridge_info_free(skb);
|
||||
return br_dev_queue_push_xmit(net, sk, skb);
|
||||
}
|
||||
static int br_nf_push_frag_xmit_sk(struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct net *net = dev_net(skb_dst(skb)->dev);
|
||||
return br_nf_push_frag_xmit(net, sk, skb);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV4)
|
||||
static int
|
||||
br_nf_ip_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
|
||||
int (*output)(struct sock *, struct sk_buff *))
|
||||
int (*output)(struct net *, struct sock *, struct sk_buff *))
|
||||
{
|
||||
unsigned int mtu = ip_skb_dst_mtu(skb);
|
||||
struct iphdr *iph = ip_hdr(skb);
|
||||
|
@ -714,7 +709,7 @@ br_nf_ip_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
|
|||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
return ip_do_fragment(sk, skb, output);
|
||||
return ip_do_fragment(net, sk, skb, output);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -763,7 +758,7 @@ static int br_nf_dev_queue_xmit(struct net *net, struct sock *sk, struct sk_buff
|
|||
skb_copy_from_linear_data_offset(skb, -data->size, data->mac,
|
||||
data->size);
|
||||
|
||||
return br_nf_ip_fragment(net, sk, skb, br_nf_push_frag_xmit_sk);
|
||||
return br_nf_ip_fragment(net, sk, skb, br_nf_push_frag_xmit);
|
||||
}
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
|
||||
|
@ -786,7 +781,7 @@ static int br_nf_dev_queue_xmit(struct net *net, struct sock *sk, struct sk_buff
|
|||
data->size);
|
||||
|
||||
if (v6ops)
|
||||
return v6ops->fragment(sk, skb, br_nf_push_frag_xmit_sk);
|
||||
return v6ops->fragment(net, sk, skb, br_nf_push_frag_xmit);
|
||||
|
||||
kfree_skb(skb);
|
||||
return -EMSGSIZE;
|
||||
|
|
|
@ -83,9 +83,10 @@
|
|||
int sysctl_ip_default_ttl __read_mostly = IPDEFTTL;
|
||||
EXPORT_SYMBOL(sysctl_ip_default_ttl);
|
||||
|
||||
static int ip_fragment(struct sock *sk, struct sk_buff *skb,
|
||||
unsigned int mtu,
|
||||
int (*output)(struct sock *, struct sk_buff *));
|
||||
static int
|
||||
ip_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
|
||||
unsigned int mtu,
|
||||
int (*output)(struct net *, struct sock *, struct sk_buff *));
|
||||
|
||||
/* Generate a checksum for an outgoing IP datagram. */
|
||||
void ip_send_check(struct iphdr *iph)
|
||||
|
@ -176,12 +177,11 @@ int ip_build_and_send_pkt(struct sk_buff *skb, const struct sock *sk,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(ip_build_and_send_pkt);
|
||||
|
||||
static int ip_finish_output2(struct sock *sk, struct sk_buff *skb)
|
||||
static int ip_finish_output2(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct dst_entry *dst = skb_dst(skb);
|
||||
struct rtable *rt = (struct rtable *)dst;
|
||||
struct net_device *dev = dst->dev;
|
||||
struct net *net = dev_net(dev);
|
||||
unsigned int hh_len = LL_RESERVED_SPACE(dev);
|
||||
struct neighbour *neigh;
|
||||
u32 nexthop;
|
||||
|
@ -225,8 +225,8 @@ static int ip_finish_output2(struct sock *sk, struct sk_buff *skb)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int ip_finish_output_gso(struct sock *sk, struct sk_buff *skb,
|
||||
unsigned int mtu)
|
||||
static int ip_finish_output_gso(struct net *net, struct sock *sk,
|
||||
struct sk_buff *skb, unsigned int mtu)
|
||||
{
|
||||
netdev_features_t features;
|
||||
struct sk_buff *segs;
|
||||
|
@ -235,7 +235,7 @@ static int ip_finish_output_gso(struct sock *sk, struct sk_buff *skb,
|
|||
/* common case: locally created skb or seglen is <= mtu */
|
||||
if (((IPCB(skb)->flags & IPSKB_FORWARDED) == 0) ||
|
||||
skb_gso_network_seglen(skb) <= mtu)
|
||||
return ip_finish_output2(sk, skb);
|
||||
return ip_finish_output2(net, sk, skb);
|
||||
|
||||
/* Slowpath - GSO segment length is exceeding the dst MTU.
|
||||
*
|
||||
|
@ -258,7 +258,7 @@ static int ip_finish_output_gso(struct sock *sk, struct sk_buff *skb,
|
|||
int err;
|
||||
|
||||
segs->next = NULL;
|
||||
err = ip_fragment(sk, segs, mtu, ip_finish_output2);
|
||||
err = ip_fragment(net, sk, segs, mtu, ip_finish_output2);
|
||||
|
||||
if (err && ret == 0)
|
||||
ret = err;
|
||||
|
@ -281,12 +281,12 @@ static int ip_finish_output(struct net *net, struct sock *sk, struct sk_buff *sk
|
|||
#endif
|
||||
mtu = ip_skb_dst_mtu(skb);
|
||||
if (skb_is_gso(skb))
|
||||
return ip_finish_output_gso(sk, skb, mtu);
|
||||
return ip_finish_output_gso(net, sk, skb, mtu);
|
||||
|
||||
if (skb->len > mtu || (IPCB(skb)->flags & IPSKB_FRAG_PMTU))
|
||||
return ip_fragment(sk, skb, mtu, ip_finish_output2);
|
||||
return ip_fragment(net, sk, skb, mtu, ip_finish_output2);
|
||||
|
||||
return ip_finish_output2(sk, skb);
|
||||
return ip_finish_output2(net, sk, skb);
|
||||
}
|
||||
|
||||
int ip_mc_output(struct sock *sk, struct sk_buff *skb)
|
||||
|
@ -495,20 +495,18 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from)
|
|||
skb_copy_secmark(to, from);
|
||||
}
|
||||
|
||||
static int ip_fragment(struct sock *sk, struct sk_buff *skb,
|
||||
static int ip_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
|
||||
unsigned int mtu,
|
||||
int (*output)(struct sock *, struct sk_buff *))
|
||||
int (*output)(struct net *, struct sock *, struct sk_buff *))
|
||||
{
|
||||
struct iphdr *iph = ip_hdr(skb);
|
||||
|
||||
if ((iph->frag_off & htons(IP_DF)) == 0)
|
||||
return ip_do_fragment(sk, skb, output);
|
||||
return ip_do_fragment(net, sk, skb, output);
|
||||
|
||||
if (unlikely(!skb->ignore_df ||
|
||||
(IPCB(skb)->frag_max_size &&
|
||||
IPCB(skb)->frag_max_size > mtu))) {
|
||||
struct net *net = dev_net(skb_rtable(skb)->dst.dev);
|
||||
|
||||
IP_INC_STATS(net, IPSTATS_MIB_FRAGFAILS);
|
||||
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
|
||||
htonl(mtu));
|
||||
|
@ -516,7 +514,7 @@ static int ip_fragment(struct sock *sk, struct sk_buff *skb,
|
|||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
return ip_do_fragment(sk, skb, output);
|
||||
return ip_do_fragment(net, sk, skb, output);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -526,8 +524,8 @@ static int ip_fragment(struct sock *sk, struct sk_buff *skb,
|
|||
* single device frame, and queue such a frame for sending.
|
||||
*/
|
||||
|
||||
int ip_do_fragment(struct sock *sk, struct sk_buff *skb,
|
||||
int (*output)(struct sock *, struct sk_buff *))
|
||||
int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
|
||||
int (*output)(struct net *, struct sock *, struct sk_buff *))
|
||||
{
|
||||
struct iphdr *iph;
|
||||
int ptr;
|
||||
|
@ -537,11 +535,9 @@ int ip_do_fragment(struct sock *sk, struct sk_buff *skb,
|
|||
int offset;
|
||||
__be16 not_last_frag;
|
||||
struct rtable *rt = skb_rtable(skb);
|
||||
struct net *net;
|
||||
int err = 0;
|
||||
|
||||
dev = rt->dst.dev;
|
||||
net = dev_net(dev);
|
||||
|
||||
/*
|
||||
* Point into the IP datagram header.
|
||||
|
@ -631,7 +627,7 @@ int ip_do_fragment(struct sock *sk, struct sk_buff *skb,
|
|||
ip_send_check(iph);
|
||||
}
|
||||
|
||||
err = output(sk, skb);
|
||||
err = output(net, sk, skb);
|
||||
|
||||
if (!err)
|
||||
IP_INC_STATS(net, IPSTATS_MIB_FRAGCREATES);
|
||||
|
@ -771,7 +767,7 @@ slow_path:
|
|||
|
||||
ip_send_check(iph);
|
||||
|
||||
err = output(sk, skb2);
|
||||
err = output(net, sk, skb2);
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
|
|
|
@ -56,11 +56,10 @@
|
|||
#include <net/checksum.h>
|
||||
#include <linux/mroute6.h>
|
||||
|
||||
static int ip6_finish_output2(struct sock *sk, struct sk_buff *skb)
|
||||
static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct dst_entry *dst = skb_dst(skb);
|
||||
struct net_device *dev = dst->dev;
|
||||
struct net *net = dev_net(dev);
|
||||
struct neighbour *neigh;
|
||||
struct in6_addr *nexthop;
|
||||
int ret;
|
||||
|
@ -126,9 +125,9 @@ static int ip6_finish_output(struct net *net, struct sock *sk, struct sk_buff *s
|
|||
if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) ||
|
||||
dst_allfrag(skb_dst(skb)) ||
|
||||
(IP6CB(skb)->frag_max_size && skb->len > IP6CB(skb)->frag_max_size))
|
||||
return ip6_fragment(sk, skb, ip6_finish_output2);
|
||||
return ip6_fragment(net, sk, skb, ip6_finish_output2);
|
||||
else
|
||||
return ip6_finish_output2(sk, skb);
|
||||
return ip6_finish_output2(net, sk, skb);
|
||||
}
|
||||
|
||||
int ip6_output(struct sock *sk, struct sk_buff *skb)
|
||||
|
@ -554,8 +553,8 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from)
|
|||
skb_copy_secmark(to, from);
|
||||
}
|
||||
|
||||
int ip6_fragment(struct sock *sk, struct sk_buff *skb,
|
||||
int (*output)(struct sock *, struct sk_buff *))
|
||||
int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
|
||||
int (*output)(struct net *, struct sock *, struct sk_buff *))
|
||||
{
|
||||
struct sk_buff *frag;
|
||||
struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
|
||||
|
@ -568,7 +567,6 @@ int ip6_fragment(struct sock *sk, struct sk_buff *skb,
|
|||
__be32 frag_id;
|
||||
int ptr, offset = 0, err = 0;
|
||||
u8 *prevhdr, nexthdr = 0;
|
||||
struct net *net = dev_net(skb_dst(skb)->dev);
|
||||
|
||||
hlen = ip6_find_1stfragopt(skb, &prevhdr);
|
||||
nexthdr = *prevhdr;
|
||||
|
@ -688,7 +686,7 @@ int ip6_fragment(struct sock *sk, struct sk_buff *skb,
|
|||
ip6_copy_metadata(frag, skb);
|
||||
}
|
||||
|
||||
err = output(sk, skb);
|
||||
err = output(net, sk, skb);
|
||||
if (!err)
|
||||
IP6_INC_STATS(net, ip6_dst_idev(&rt->dst),
|
||||
IPSTATS_MIB_FRAGCREATES);
|
||||
|
@ -816,7 +814,7 @@ slow_path:
|
|||
/*
|
||||
* Put this fragment into the sending queue.
|
||||
*/
|
||||
err = output(sk, frag);
|
||||
err = output(net, sk, frag);
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
|
|
|
@ -131,6 +131,13 @@ int xfrm6_output_finish(struct sock *sk, struct sk_buff *skb)
|
|||
return xfrm_output(sk, skb);
|
||||
}
|
||||
|
||||
static int __xfrm6_output_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct xfrm_state *x = skb_dst(skb)->xfrm;
|
||||
|
||||
return x->outer_mode->afinfo->output_finish(sk, skb);
|
||||
}
|
||||
|
||||
static int __xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct dst_entry *dst = skb_dst(skb);
|
||||
|
@ -160,8 +167,8 @@ static int __xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
|
|||
if (x->props.mode == XFRM_MODE_TUNNEL &&
|
||||
((skb->len > mtu && !skb_is_gso(skb)) ||
|
||||
dst_allfrag(skb_dst(skb)))) {
|
||||
return ip6_fragment(sk, skb,
|
||||
x->outer_mode->afinfo->output_finish);
|
||||
return ip6_fragment(net, sk, skb,
|
||||
__xfrm6_output_finish);
|
||||
}
|
||||
return x->outer_mode->afinfo->output_finish(sk, skb);
|
||||
}
|
||||
|
|
|
@ -620,7 +620,7 @@ static int set_sctp(struct sk_buff *skb, struct sw_flow_key *flow_key,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ovs_vport_output(struct sock *sock, struct sk_buff *skb)
|
||||
static int ovs_vport_output(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct ovs_frag_data *data = this_cpu_ptr(&ovs_frag_data_storage);
|
||||
struct vport *vport = data->vport;
|
||||
|
@ -679,8 +679,8 @@ static void prepare_frag(struct vport *vport, struct sk_buff *skb)
|
|||
skb_pull(skb, hlen);
|
||||
}
|
||||
|
||||
static void ovs_fragment(struct vport *vport, struct sk_buff *skb, u16 mru,
|
||||
__be16 ethertype)
|
||||
static void ovs_fragment(struct net *net, struct vport *vport,
|
||||
struct sk_buff *skb, u16 mru, __be16 ethertype)
|
||||
{
|
||||
if (skb_network_offset(skb) > MAX_L2_LEN) {
|
||||
OVS_NLERR(1, "L2 header too long to fragment");
|
||||
|
@ -700,7 +700,7 @@ static void ovs_fragment(struct vport *vport, struct sk_buff *skb, u16 mru,
|
|||
skb_dst_set_noref(skb, &ovs_dst);
|
||||
IPCB(skb)->frag_max_size = mru;
|
||||
|
||||
ip_do_fragment(skb->sk, skb, ovs_vport_output);
|
||||
ip_do_fragment(net, skb->sk, skb, ovs_vport_output);
|
||||
refdst_drop(orig_dst);
|
||||
} else if (ethertype == htons(ETH_P_IPV6)) {
|
||||
const struct nf_ipv6_ops *v6ops = nf_get_ipv6_ops();
|
||||
|
@ -722,7 +722,7 @@ static void ovs_fragment(struct vport *vport, struct sk_buff *skb, u16 mru,
|
|||
skb_dst_set_noref(skb, &ovs_rt.dst);
|
||||
IP6CB(skb)->frag_max_size = mru;
|
||||
|
||||
v6ops->fragment(skb->sk, skb, ovs_vport_output);
|
||||
v6ops->fragment(net, skb->sk, skb, ovs_vport_output);
|
||||
refdst_drop(orig_dst);
|
||||
} else {
|
||||
WARN_ONCE(1, "Failed fragment ->%s: eth=%04x, MRU=%d, MTU=%d.",
|
||||
|
@ -743,6 +743,7 @@ static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port,
|
|||
if (likely(!mru || (skb->len <= mru + ETH_HLEN))) {
|
||||
ovs_vport_send(vport, skb);
|
||||
} else if (mru <= vport->dev->mtu) {
|
||||
struct net *net = read_pnet(&dp->net);
|
||||
__be16 ethertype = key->eth.type;
|
||||
|
||||
if (!is_flow_key_valid(key)) {
|
||||
|
@ -752,7 +753,7 @@ static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port,
|
|||
ethertype = vlan_get_protocol(skb);
|
||||
}
|
||||
|
||||
ovs_fragment(vport, skb, mru, ethertype);
|
||||
ovs_fragment(net, vport, skb, mru, ethertype);
|
||||
} else {
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче