Commit 40e10680 authored by David S. Miller's avatar David S. Miller
Browse files


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: default avatarNicolas Dichtel <nicolas.dichtel@6wind.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 7e2832f1 b1842ffd
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -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
+2 −2
Original line number Diff line number Diff line
@@ -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);
+2 −2
Original line number Diff line number Diff line
@@ -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)
{
+4 −9
Original line number Diff line number Diff line
@@ -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;
+20 −24
Original line number Diff line number Diff line
@@ -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,
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 *));

/* 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;

Loading