Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

Merge branch 'x-netns'



Nicolas Dichtel says:

====================
This series is a follow up of the previous series whcih adds this
functionality for sit tunnels.

The goal is to add x-netns support for the module ipip and ip6_tunnel,
ie. the encapsulation addresses and the network device are not owned
by the same namespace.

Note that the two first patches are cleanups.

Example to configure an ipip tunnel:

modprobe ipip
ip netns add netns1
ip link add ipip1 type ipip remote 10.16.0.121 local 10.16.0.249
ip l s ipip1 netns netns1
ip netns exec netns1 ip l s lo up
ip netns exec netns1 ip l s ipip1 up
ip netns exec netns1 ip a a dev ipip1 192.168.2.123 remote 192.168.2.121

or an ip6_tunnel:

modprobe ip6_tunnel
ip netns add netns1
ip link add ip6tnl1 type ip6tnl remote 2001:660:3008:c1c3::121 local 2001:660:3008:c1c3::123
ip l s ip6tnl1 netns netns1
ip netns exec netns1 ip l s lo up
ip netns exec netns1 ip l s ip6tnl1 up
ip netns exec netns1 ip a a dev ip6tnl1 192.168.1.123 remote 192.168.1.121
ip netns exec netns1 ip -6 a a dev ip6tnl1 2001:1235::123 remote 2001:1235::121

v2: remove the patch 1/3 of the v1 series (already included)
    use net_eq()
    add patch 1/4 and 2/4
====================-

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents fc4eba58 0bd87628
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ struct __ip6_tnl_parm {
struct ip6_tnl {
	struct ip6_tnl __rcu *next;	/* next tunnel in list */
	struct net_device *dev;	/* virtual device associated with tunnel */
	struct net *net;	/* netns for packet i/o */
	struct __ip6_tnl_parm parms;	/* tunnel configuration parameters */
	struct flowi fl;	/* flowi template for xmit */
	struct dst_entry *dst_cache;    /* cached dst */
+1 −1
Original line number Diff line number Diff line
@@ -102,7 +102,7 @@ void ip_tunnel_dellink(struct net_device *dev, struct list_head *head);
int ip_tunnel_init_net(struct net *net, int ip_tnl_net_id,
		       struct rtnl_link_ops *ops, char *devname);

void ip_tunnel_delete_net(struct ip_tunnel_net *itn);
void ip_tunnel_delete_net(struct ip_tunnel_net *itn, struct rtnl_link_ops *ops);

void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
		    const struct iphdr *tnl_params, const u8 protocol);
+3 −3
Original line number Diff line number Diff line
@@ -1691,13 +1691,13 @@ int dev_forward_skb(struct net_device *dev, struct sk_buff *skb)
		kfree_skb(skb);
		return NET_RX_DROP;
	}
	skb_scrub_packet(skb);
	skb->protocol = eth_type_trans(skb, dev);

	/* eth_type_trans() can set pkt_type.
	 * clear pkt_type _after_ calling eth_type_trans()
	 * call skb_scrub_packet() after it to clear pkt_type _after_ calling
	 * eth_type_trans().
	 */
	skb->pkt_type = PACKET_HOST;
	skb_scrub_packet(skb);

	return netif_rx(skb);
}
+2 −2
Original line number Diff line number Diff line
@@ -534,7 +534,7 @@ static int __net_init ipgre_init_net(struct net *net)
static void __net_exit ipgre_exit_net(struct net *net)
{
	struct ip_tunnel_net *itn = net_generic(net, ipgre_net_id);
	ip_tunnel_delete_net(itn);
	ip_tunnel_delete_net(itn, &ipgre_link_ops);
}

static struct pernet_operations ipgre_net_ops = {
@@ -767,7 +767,7 @@ static int __net_init ipgre_tap_init_net(struct net *net)
static void __net_exit ipgre_tap_exit_net(struct net *net)
{
	struct ip_tunnel_net *itn = net_generic(net, gre_tap_net_id);
	ip_tunnel_delete_net(itn);
	ip_tunnel_delete_net(itn, &ipgre_tap_ops);
}

static struct pernet_operations ipgre_tap_net_ops = {
+33 −19
Original line number Diff line number Diff line
@@ -350,7 +350,7 @@ static int ip_tunnel_bind_dev(struct net_device *dev)
		struct flowi4 fl4;
		struct rtable *rt;

		rt = ip_route_output_tunnel(dev_net(dev), &fl4,
		rt = ip_route_output_tunnel(tunnel->net, &fl4,
					    tunnel->parms.iph.protocol,
					    iph->daddr, iph->saddr,
					    tunnel->parms.o_key,
@@ -365,7 +365,7 @@ static int ip_tunnel_bind_dev(struct net_device *dev)
	}

	if (!tdev && tunnel->parms.link)
		tdev = __dev_get_by_index(dev_net(dev), tunnel->parms.link);
		tdev = __dev_get_by_index(tunnel->net, tunnel->parms.link);

	if (tdev) {
		hlen = tdev->hard_header_len + tdev->needed_headroom;
@@ -454,15 +454,16 @@ int ip_tunnel_rcv(struct ip_tunnel *tunnel, struct sk_buff *skb,
	tstats->rx_bytes += skb->len;
	u64_stats_update_end(&tstats->syncp);

	if (tunnel->net != dev_net(tunnel->dev))
		skb_scrub_packet(skb);

	if (tunnel->dev->type == ARPHRD_ETHER) {
		skb->protocol = eth_type_trans(skb, tunnel->dev);
		skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
	} else {
		skb->dev = tunnel->dev;
	}

	if (!net_eq(tunnel->net, dev_net(tunnel->dev)))
		skb_scrub_packet(skb);

	gro_cells_receive(&tunnel->gro_cells, skb);
	return 0;

@@ -613,7 +614,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
		goto tx_error;
	}

	if (tunnel->net != dev_net(dev))
	if (!net_eq(tunnel->net, dev_net(dev)))
		skb_scrub_packet(skb);

	if (tunnel->err_count > 0) {
@@ -653,7 +654,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
		}
	}

	err = iptunnel_xmit(dev_net(dev), rt, skb,
	err = iptunnel_xmit(tunnel->net, rt, skb,
			    fl4.saddr, fl4.daddr, protocol,
			    ip_tunnel_ecn_encap(tos, inner_iph, skb), ttl, df);
	iptunnel_xmit_stats(err, &dev->stats, dev->tstats);
@@ -820,11 +821,10 @@ static void ip_tunnel_dev_free(struct net_device *dev)

void ip_tunnel_dellink(struct net_device *dev, struct list_head *head)
{
	struct net *net = dev_net(dev);
	struct ip_tunnel *tunnel = netdev_priv(dev);
	struct ip_tunnel_net *itn;

	itn = net_generic(net, tunnel->ip_tnl_net_id);
	itn = net_generic(tunnel->net, tunnel->ip_tnl_net_id);

	if (itn->fb_tunnel_dev != dev) {
		ip_tunnel_del(netdev_priv(dev));
@@ -854,6 +854,10 @@ int ip_tunnel_init_net(struct net *net, int ip_tnl_net_id,

	rtnl_lock();
	itn->fb_tunnel_dev = __ip_tunnel_create(net, ops, &parms);
	/* FB netdevice is special: we have one, and only one per netns.
	 * Allowing to move it to another netns is clearly unsafe.
	 */
	itn->fb_tunnel_dev->features |= NETIF_F_NETNS_LOCAL;
	rtnl_unlock();

	if (IS_ERR(itn->fb_tunnel_dev))
@@ -863,28 +867,39 @@ int ip_tunnel_init_net(struct net *net, int ip_tnl_net_id,
}
EXPORT_SYMBOL_GPL(ip_tunnel_init_net);

static void ip_tunnel_destroy(struct ip_tunnel_net *itn, struct list_head *head)
static void ip_tunnel_destroy(struct ip_tunnel_net *itn, struct list_head *head,
			      struct rtnl_link_ops *ops)
{
	struct net *net = dev_net(itn->fb_tunnel_dev);
	struct net_device *dev, *aux;
	int h;

	for_each_netdev_safe(net, dev, aux)
		if (dev->rtnl_link_ops == ops)
			unregister_netdevice_queue(dev, head);

	for (h = 0; h < IP_TNL_HASH_SIZE; h++) {
		struct ip_tunnel *t;
		struct hlist_node *n;
		struct hlist_head *thead = &itn->tunnels[h];

		hlist_for_each_entry_safe(t, n, thead, hash_node)
			/* If dev is in the same netns, it has already
			 * been added to the list by the previous loop.
			 */
			if (!net_eq(dev_net(t->dev), net))
				unregister_netdevice_queue(t->dev, head);
	}
	if (itn->fb_tunnel_dev)
		unregister_netdevice_queue(itn->fb_tunnel_dev, head);
}

void ip_tunnel_delete_net(struct ip_tunnel_net *itn)
void ip_tunnel_delete_net(struct ip_tunnel_net *itn, struct rtnl_link_ops *ops)
{
	LIST_HEAD(list);

	rtnl_lock();
	ip_tunnel_destroy(itn, &list);
	ip_tunnel_destroy(itn, &list, ops);
	unregister_netdevice_many(&list);
	rtnl_unlock();
}
@@ -928,23 +943,21 @@ EXPORT_SYMBOL_GPL(ip_tunnel_newlink);
int ip_tunnel_changelink(struct net_device *dev, struct nlattr *tb[],
			 struct ip_tunnel_parm *p)
{
	struct ip_tunnel *t, *nt;
	struct net *net = dev_net(dev);
	struct ip_tunnel *t;
	struct ip_tunnel *tunnel = netdev_priv(dev);
	struct net *net = tunnel->net;
	struct ip_tunnel_net *itn = net_generic(net, tunnel->ip_tnl_net_id);

	if (dev == itn->fb_tunnel_dev)
		return -EINVAL;

	nt = netdev_priv(dev);

	t = ip_tunnel_find(itn, p, dev->type);

	if (t) {
		if (t->dev != dev)
			return -EEXIST;
	} else {
		t = nt;
		t = tunnel;

		if (dev->type != ARPHRD_ETHER) {
			unsigned int nflags = 0;
@@ -983,6 +996,7 @@ int ip_tunnel_init(struct net_device *dev)
	}

	tunnel->dev = dev;
	tunnel->net = dev_net(dev);
	strcpy(tunnel->parms.name, dev->name);
	iph->version		= 4;
	iph->ihl		= 5;
@@ -993,8 +1007,8 @@ EXPORT_SYMBOL_GPL(ip_tunnel_init);

void ip_tunnel_uninit(struct net_device *dev)
{
	struct net *net = dev_net(dev);
	struct ip_tunnel *tunnel = netdev_priv(dev);
	struct net *net = tunnel->net;
	struct ip_tunnel_net *itn;

	itn = net_generic(net, tunnel->ip_tnl_net_id);
Loading