All of lore.kernel.org
 help / color / mirror / Atom feed
From: ebiederm@xmission.com (Eric W. Biederman)
To: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Cc: netdev@vger.kernel.org, davem@davemloft.net, bcrl@kvack.org,
	ravi.mlists@gmail.com
Subject: Re: [RFC PATCH net-next 2/2] sit: add support of x-netns
Date: Mon, 24 Jun 2013 12:28:20 -0700	[thread overview]
Message-ID: <878v1zjokr.fsf@xmission.com> (raw)
In-Reply-To: <1372083239-9451-3-git-send-email-nicolas.dichtel@6wind.com> (Nicolas Dichtel's message of "Mon, 24 Jun 2013 16:13:59 +0200")

Nicolas Dichtel <nicolas.dichtel@6wind.com> writes:

> This patch allows to switch the netns when packet is encapsulated or
> decapsulated. In other word, the encapsulated packet is received in a netns,
> where the lookup is done to find the tunnel. Once the tunnel is found, the
> packet is decapsulated and injecting into the corresponding interface which
> stands to another netns.
>
> When one of the two netns is removed, the tunnel is destroyed.

I don't see any fundamental problems with this code.  There are bugs
with the cleanup noted below.

The primary sit interface is marked as NETNS_LOCAL which is good.  A
comment might be nice explaining the reasonsing but for code
archeologists.

Conditionally calling dev_cleanup_skb bugs me.  The extra conditional
looks like a maintenance hazard.   Unless I have missed some subtle
detail either we don't need the cleanup at all or actually it is a bug
that we aren't scrubbing our packets as they progress through tunnels
even in the same network namespace.

Can we just make that function the skb scrubbing needed for packets to
traverse a tunnel?

My concern going into this was that we would get code that would break
because it would not be tested enough.  If we can remove the conditional
from dev_cleanup_skb we won't have any code that is conditionally run
and the logic looks simple enough not to bitrot in routine maintenance.

Eric

> Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
> ---
>  include/net/ip_tunnels.h |  1 +
>  net/ipv4/ip_tunnel.c     |  7 ++++++-
>  net/ipv6/sit.c           | 49 ++++++++++++++++++++++++------------------------
>  3 files changed, 32 insertions(+), 25 deletions(-)
>
> diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h
> index b0d9824..781b3cf 100644
> --- a/include/net/ip_tunnels.h
> +++ b/include/net/ip_tunnels.h
> @@ -42,6 +42,7 @@ struct ip_tunnel {
>  	struct ip_tunnel __rcu	*next;
>  	struct hlist_node hash_node;
>  	struct net_device	*dev;
> +	struct net		*net;	/* netns for packet i/o */
>  
>  	int		err_count;	/* Number of arrived ICMP errors */
>  	unsigned long	err_time;	/* Time when the last ICMP error
> diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c
> index bd227e5..b6a7704 100644
> --- a/net/ipv4/ip_tunnel.c
> +++ b/net/ipv4/ip_tunnel.c
> @@ -304,6 +304,7 @@ static struct net_device *__ip_tunnel_create(struct net *net,
>  
>  	tunnel = netdev_priv(dev);
>  	tunnel->parms = *parms;
> +	tunnel->net = net;
>  
>  	err = register_netdevice(dev);
>  	if (err)
> @@ -453,6 +454,9 @@ 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))
> +		dev_cleanup_skb(skb);
> +
>  	if (tunnel->dev->type == ARPHRD_ETHER) {
>  		skb->protocol = eth_type_trans(skb, tunnel->dev);
>  		skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
> @@ -541,7 +545,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
>  			tos = ipv6_get_dsfield((const struct ipv6hdr *)inner_iph);
>  	}
>  
> -	rt = ip_route_output_tunnel(dev_net(dev), &fl4,
> +	rt = ip_route_output_tunnel(tunnel->net, &fl4,
>  				    tunnel->parms.iph.protocol,
>  				    dst, tnl_params->saddr,
>  				    tunnel->parms.o_key,
> @@ -888,6 +892,7 @@ int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[],
>  	if (ip_tunnel_find(itn, p, dev->type))
>  		return -EEXIST;
>  
> +	nt->net = net;
>  	nt->parms = *p;
>  	err = register_netdevice(dev);
>  	if (err)
> diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
> index f639866..4e03904 100644
> --- a/net/ipv6/sit.c
> +++ b/net/ipv6/sit.c
> @@ -466,14 +466,14 @@ isatap_chksrc(struct sk_buff *skb, const struct iphdr *iph, struct ip_tunnel *t)
>  
>  static void ipip6_tunnel_uninit(struct net_device *dev)
>  {
> -	struct net *net = dev_net(dev);
> -	struct sit_net *sitn = net_generic(net, sit_net_id);
> +	struct ip_tunnel *tunnel = netdev_priv(dev);
> +	struct sit_net *sitn = net_generic(tunnel->net, sit_net_id);
>  
>  	if (dev == sitn->fb_tunnel_dev) {
>  		RCU_INIT_POINTER(sitn->tunnels_wc[0], NULL);
>  	} else {
> -		ipip6_tunnel_unlink(sitn, netdev_priv(dev));
> -		ipip6_tunnel_del_prl(netdev_priv(dev), NULL);
> +		ipip6_tunnel_unlink(sitn, tunnel);
> +		ipip6_tunnel_del_prl(tunnel, NULL);
>  	}
>  	dev_put(dev);
>  }
> @@ -621,6 +621,8 @@ static int ipip6_rcv(struct sk_buff *skb)
>  		tstats->rx_packets++;
>  		tstats->rx_bytes += skb->len;
>  
> +		if (tunnel->net != dev_net(tunnel->dev))
> +			dev_cleanup_skb(skb);
>  		netif_rx(skb);
>  
>  		return 0;
> @@ -803,7 +805,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
>  			goto tx_error;
>  	}
>  
> -	rt = ip_route_output_ports(dev_net(dev), &fl4, NULL,
> +	rt = ip_route_output_ports(tunnel->net, &fl4, NULL,
>  				   dst, tiph->saddr,
>  				   0, 0,
>  				   IPPROTO_IPV6, RT_TOS(tos),
> @@ -858,6 +860,9 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
>  			tunnel->err_count = 0;
>  	}
>  
> +	if (tunnel->net != dev_net(dev))
> +		dev_cleanup_skb(skb);
> +
>  	/*
>  	 * Okay, now see if we can stuff it in the buffer as-is.
>  	 */
> @@ -944,7 +949,8 @@ static void ipip6_tunnel_bind_dev(struct net_device *dev)
>  	iph = &tunnel->parms.iph;
>  
>  	if (iph->daddr) {
> -		struct rtable *rt = ip_route_output_ports(dev_net(dev), &fl4, NULL,
> +		struct rtable *rt = ip_route_output_ports(tunnel->net, &fl4,
> +							  NULL,
>  							  iph->daddr, iph->saddr,
>  							  0, 0,
>  							  IPPROTO_IPV6,
> @@ -959,7 +965,7 @@ static void ipip6_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) {
>  		dev->hard_header_len = tdev->hard_header_len + sizeof(struct iphdr);
> @@ -972,7 +978,7 @@ static void ipip6_tunnel_bind_dev(struct net_device *dev)
>  
>  static void ipip6_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p)
>  {
> -	struct net *net = dev_net(t->dev);
> +	struct net *net = t->net;
>  	struct sit_net *sitn = net_generic(net, sit_net_id);
>  
>  	ipip6_tunnel_unlink(sitn, t);
> @@ -1248,7 +1254,6 @@ static void ipip6_tunnel_setup(struct net_device *dev)
>  	dev->priv_flags	       &= ~IFF_XMIT_DST_RELEASE;
>  	dev->iflink		= 0;
>  	dev->addr_len		= 4;
> -	dev->features		|= NETIF_F_NETNS_LOCAL;
>  	dev->features		|= NETIF_F_LLTX;
>  }
>  
> @@ -1257,6 +1262,7 @@ static int ipip6_tunnel_init(struct net_device *dev)
>  	struct ip_tunnel *tunnel = netdev_priv(dev);
>  
>  	tunnel->dev = dev;
> +	tunnel->net = dev_net(dev);
>  
>  	memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4);
>  	memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4);
> @@ -1277,6 +1283,7 @@ static int __net_init ipip6_fb_tunnel_init(struct net_device *dev)
>  	struct sit_net *sitn = net_generic(net, sit_net_id);
>  
>  	tunnel->dev = dev;
> +	tunnel->net = dev_net(dev);
>  	strcpy(tunnel->parms.name, dev->name);
>  
>  	iph->version		= 4;
> @@ -1562,22 +1569,15 @@ static struct xfrm_tunnel ipip_handler __read_mostly = {
>  	.priority	=	2,
>  };
>  
> -static void __net_exit sit_destroy_tunnels(struct sit_net *sitn, struct list_head *head)
> +static void __net_exit sit_destroy_tunnels(struct net *net,
> +					   struct list_head *head)
>  {
> -	int prio;
> +	struct net_device *dev, *aux;
>  
> -	for (prio = 1; prio < 4; prio++) {
> -		int h;
> -		for (h = 0; h < HASH_SIZE; h++) {
> -			struct ip_tunnel *t;
> -
> -			t = rtnl_dereference(sitn->tunnels[prio][h]);
> -			while (t != NULL) {
> -				unregister_netdevice_queue(t->dev, head);
> -				t = rtnl_dereference(t->next);
> -			}
> -		}
> -	}
> +	for_each_netdev_safe(net, dev, aux)
> +		if (dev->rtnl_link_ops &&
> +		    !strcmp(dev->rtnl_link_ops->kind, "sit"))
> +			unregister_netdevice_queue(dev, head);

This entire idiom change is a bit ugly, and it is wrong.

You need to look for two classes of tunnels to take down.  Tunnels that
originate in net and tunnels whose netdevice is in net.

For tunnles that reside in net you should be able to just compare the
rtnl_link_ops pointer, rather than an ascii name.

Tunnels that originate in this network namespace most definitely need to
be taken down as among other things you wisely do not keep a reference
count on the originating network namespace.

>  }
>  
>  static int __net_init sit_init_net(struct net *net)
> @@ -1598,6 +1598,7 @@ static int __net_init sit_init_net(struct net *net)
>  		goto err_alloc_dev;
>  	}
>  	dev_net_set(sitn->fb_tunnel_dev, net);
> +	sitn->fb_tunnel_dev->features |= NETIF_F_NETNS_LOCAL;
>  
>  	err = ipip6_fb_tunnel_init(sitn->fb_tunnel_dev);
>  	if (err)
> @@ -1627,7 +1628,7 @@ static void __net_exit sit_exit_net(struct net *net)
>  	LIST_HEAD(list);
>  
>  	rtnl_lock();
> -	sit_destroy_tunnels(sitn, &list);
> +	sit_destroy_tunnels(net, &list);
>  	unregister_netdevice_queue(sitn->fb_tunnel_dev, &list);
>  	unregister_netdevice_many(&list);
>  	rtnl_unlock();

  reply	other threads:[~2013-06-24 20:42 UTC|newest]

Thread overview: 52+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-10-23 17:49 switching network namespace midway rsa
2012-10-24 21:11 ` Eric W. Biederman
2012-10-24 21:21   ` Benjamin LaHaise
2012-10-25  1:37     ` Eric W. Biederman
2012-10-25 14:38       ` Benjamin LaHaise
2012-10-25 16:21         ` Stephen Hemminger
2012-10-28  5:43           ` Eric W. Biederman
2012-10-29 14:23             ` Stephen Hemminger
2012-10-30  0:21               ` Eric W. Biederman
2012-10-30  8:55                 ` James Chapman
2012-10-25 15:12     ` rsa
2012-10-25 15:29     ` rsa
2012-10-25 15:59       ` Benjamin LaHaise
2012-10-25 16:15         ` Eric W. Biederman
2012-11-02  2:25           ` Benjamin LaHaise
2012-11-02  6:18             ` Eric W. Biederman
2012-11-02 14:03               ` Benjamin LaHaise
2012-11-02 20:45                 ` Eric W. Biederman
2013-06-24 14:13                   ` [RFC PATCH net-next 0/2] sit: allow to switch netns during encap/decap Nicolas Dichtel
2013-06-24 14:13                     ` [RFC PATCH net-next 1/2] dev: introduce dev_cleanup_skb() Nicolas Dichtel
2013-06-24 18:13                       ` Ben Hutchings
2013-06-24 19:05                         ` Eric W. Biederman
2013-06-24 14:13                     ` [RFC PATCH net-next 2/2] sit: add support of x-netns Nicolas Dichtel
2013-06-24 19:28                       ` Eric W. Biederman [this message]
2013-06-24 21:11                         ` Nicolas Dichtel
2013-06-24 22:42                           ` Eric W. Biederman
2013-06-25 14:10                             ` Nicolas Dichtel
2013-06-25 14:24                               ` [PATCH v2 net-next 0/2] sit: allow to switch netns during encap/decap Nicolas Dichtel
2013-06-25 14:24                                 ` [PATCH v2 net-next 1/2] dev: introduce skb_scrub_packet() Nicolas Dichtel
2013-06-25 14:24                                 ` [PATCH v2 net-next 2/2] sit: add support of x-netns Nicolas Dichtel
2013-06-25 23:56                                   ` David Miller
2013-06-26  1:35                                     ` Eric W. Biederman
2013-06-26  5:48                                       ` David Miller
2013-06-26 10:03                                         ` Eric W. Biederman
2013-06-26 10:22                                           ` Eric Dumazet
2013-06-26 12:15                                             ` Nicolas Dichtel
2013-06-26 14:11                                               ` [PATCH v3 net-next 0/2] sit: allow to switch netns during encap/decap Nicolas Dichtel
2013-06-26 14:11                                                 ` [PATCH v3 net-next 1/2] dev: introduce skb_scrub_packet() Nicolas Dichtel
2013-06-26 14:11                                                 ` [PATCH v3 net-next 2/2] sit: add support of x-netns Nicolas Dichtel
2013-06-28  5:36                                                 ` [PATCH v3 net-next 0/2] sit: allow to switch netns during encap/decap David Miller
2013-07-03 15:00                                                   ` [PATCH net-next 0/3] ipip/ip6tnl: " Nicolas Dichtel
2013-07-03 15:00                                                     ` [PATCH net-next 1/3] sit: fix tunnel update via netlink Nicolas Dichtel
2013-07-03 15:00                                                     ` [PATCH net-next 2/3] ipip: add x-netns support Nicolas Dichtel
2013-07-03 15:00                                                     ` [PATCH net-next 3/3] ip6tnl: " Nicolas Dichtel
2013-07-04 21:56                                                     ` [PATCH net-next 0/3] ipip/ip6tnl: allow to switch netns during encap/decap David Miller
2013-08-13 15:51                                                       ` [PATCH net-next v2 0/4] " Nicolas Dichtel
2013-08-13 15:51                                                         ` [PATCH net-next v2 1/4] dev: move skb_scrub_packet() after eth_type_trans() Nicolas Dichtel
2013-08-13 15:51                                                         ` [PATCH net-next v2 2/4] ipv4 tunnels: use net_eq() helper to check netns Nicolas Dichtel
2013-08-13 15:51                                                         ` [PATCH net-next v2 3/4] ipip: add x-netns support Nicolas Dichtel
2013-08-13 15:51                                                         ` [PATCH net-next v2 4/4] ip6tnl: " Nicolas Dichtel
2013-08-15  8:01                                                         ` [PATCH net-next v2 0/4] ipip/ip6tnl: allow to switch netns during encap/decap David Miller
2013-06-26 13:49                                     ` [PATCH v2 net-next 2/2] sit: add support of x-netns Nicolas Dichtel

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=878v1zjokr.fsf@xmission.com \
    --to=ebiederm@xmission.com \
    --cc=bcrl@kvack.org \
    --cc=davem@davemloft.net \
    --cc=netdev@vger.kernel.org \
    --cc=nicolas.dichtel@6wind.com \
    --cc=ravi.mlists@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.