netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Flavio Leitner <fbl@redhat.com>
To: Eric Dumazet <eric.dumazet@gmail.com>
Cc: David Miller <davem@davemloft.net>,
	Ivan Zahariev <famzah@icdsoft.com>,
	netdev@vger.kernel.org, Vasiliy Kulikov <segoon@openwall.com>
Subject: Re: Unable to flush ICMP redirect routes in kernel 3.0+
Date: Fri, 18 Nov 2011 14:30:16 -0200	[thread overview]
Message-ID: <20111118143016.01e24b37@asterix.rh> (raw)
In-Reply-To: <1321632128.3277.29.camel@edumazet-HP-Compaq-6005-Pro-SFF-PC>

On Fri, 18 Nov 2011 17:02:08 +0100
Eric Dumazet <eric.dumazet@gmail.com> wrote:

> 
> 
> David, unless I missed something, we should revert commit f39925dbde77
> ipv4: Cache learned redirect information in inetpeer.)
> 
> With following patch, redirects now work for me.
> 
> Thanks !
> 
> 
> 
> [PATCH net-next] ipv4: fix redirect handling
> 
> commit f39925dbde77 (ipv4: Cache learned redirect information in
> inetpeer.) introduced a regression in ICMP redirect handling.
> 
> It assumed ipv4_dst_check() would be called because all possible
> routes were attached to the inetpeer we modify in ip_rt_redirect(),
> but thats not true.
> 
> commit 7cc9150ebe (route: fix ICMP redirect validation) tried to fix
> this but solution was not complete. (It fixed only one route)
> 
> So we must lookup existing routes (including different TOS values) and
> call check_peer_redir() on them.
> 
> Reported-by: Ivan Zahariev <famzah@icdsoft.com>
> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
> CC: Flavio Leitner <fbl@redhat.com>
> ---
>  net/ipv4/route.c |  110 ++++++++++++++++++++++++---------------------
>  1 file changed, 59 insertions(+), 51 deletions(-)
> 
> diff --git a/net/ipv4/route.c b/net/ipv4/route.c
> index 511f4a7..0c74da8 100644
> --- a/net/ipv4/route.c
> +++ b/net/ipv4/route.c
> @@ -1304,16 +1304,42 @@ static void rt_del(unsigned hash, struct
> rtable *rt) spin_unlock_bh(rt_hash_lock_addr(hash));
>  }
>  
> +static int check_peer_redir(struct dst_entry *dst, struct inet_peer
> *peer) +{
> +	struct rtable *rt = (struct rtable *) dst;
> +	__be32 orig_gw = rt->rt_gateway;
> +	struct neighbour *n, *old_n;
> +
> +	dst_confirm(&rt->dst);
> +
> +	rt->rt_gateway = peer->redirect_learned.a4;
> +
> +	n = ipv4_neigh_lookup(&rt->dst, &rt->rt_gateway);
> +	if (IS_ERR(n))
> +		return PTR_ERR(n);
> +	old_n = xchg(&rt->dst._neighbour, n);
> +	if (old_n)
> +		neigh_release(old_n);
> +	if (!n || !(n->nud_state & NUD_VALID)) {
> +		if (n)
> +			neigh_event_send(n, NULL);
> +		rt->rt_gateway = orig_gw;
> +		return -EAGAIN;
> +	} else {
> +		rt->rt_flags |= RTCF_REDIRECTED;
> +		call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, n);
> +	}
> +	return 0;
> +}
> +
>  /* called in rcu_read_lock() section */
>  void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
>  		    __be32 saddr, struct net_device *dev)
>  {
>  	int s, i;
>  	struct in_device *in_dev = __in_dev_get_rcu(dev);
> -	struct rtable *rt;
>  	__be32 skeys[2] = { saddr, 0 };
>  	int    ikeys[2] = { dev->ifindex, 0 };
> -	struct flowi4 fl4;
>  	struct inet_peer *peer;
>  	struct net *net;
>  
> @@ -1336,33 +1362,42 @@ void ip_rt_redirect(__be32 old_gw, __be32
> daddr, __be32 new_gw, goto reject_redirect;
>  	}
>  
> -	memset(&fl4, 0, sizeof(fl4));
> -	fl4.daddr = daddr;
>  	for (s = 0; s < 2; s++) {
>  		for (i = 0; i < 2; i++) {
> -			fl4.flowi4_oif = ikeys[i];
> -			fl4.saddr = skeys[s];
> -			rt = __ip_route_output_key(net, &fl4);
> -			if (IS_ERR(rt))
> -				continue;
> -
> -			if (rt->dst.error || rt->dst.dev != dev ||
> -			    rt->rt_gateway != old_gw) {
> -				ip_rt_put(rt);
> -				continue;
> -			}
> +			unsigned int hash;
> +			struct rtable __rcu **rthp;
> +			struct rtable *rt;
> +
> +			hash = rt_hash(daddr, skeys[s], ikeys[i],
> rt_genid(net)); +
> +			rthp = &rt_hash_table[hash].chain;
> +
> +			while ((rt = rcu_dereference(*rthp)) !=
> NULL) {
> +				rthp = &rt->dst.rt_next;
> +
> +				if (rt->rt_key_dst != daddr ||
> +				    rt->rt_key_src != skeys[s] ||
> +				    rt->rt_oif != ikeys[i] ||
> +				    rt_is_input_route(rt) ||
> +				    rt_is_expired(rt) ||
> +				    !net_eq(dev_net(rt->dst.dev),
> net) ||
> +				    rt->dst.error ||
> +				    rt->dst.dev != dev ||
> +				    rt->rt_gateway != old_gw)
> +					continue;
>  

I know we are reverting to get it fixed, but this adds the routing
cache back, so what is the plan? Revert to get it working and then
think on new approach to remove the route cache again later?

I had one previous patch using the routing cache posted to the list,
but it won't fix the route flush problem.

thanks,
fbl

  reply	other threads:[~2011-11-18 16:30 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-11-15 20:23 Unable to flush ICMP redirect routes in kernel 3.0+ Ivan Zahariev
2011-11-15 21:09 ` Eric Dumazet
2011-11-16 22:32   ` Ivan Zahariev
2011-11-17  0:33     ` Flavio Leitner
2011-11-17  8:10       ` Ivan Zahariev
2011-11-17 13:11         ` Flavio Leitner
2011-11-17 13:15           ` Eric Dumazet
2011-11-17 14:40             ` Eric Dumazet
2011-11-17 15:37               ` Flavio Leitner
2011-11-17 16:31                 ` Eric Dumazet
2011-11-17 16:40                   ` Flavio Leitner
2011-11-17 16:45                     ` Eric Dumazet
2011-11-17 16:57                       ` Eric Dumazet
2011-11-17 17:01                       ` Flavio Leitner
2011-11-17 17:18                         ` Eric Dumazet
2011-11-17 17:33                           ` Flavio Leitner
2011-11-17 17:38                           ` Eric Dumazet
2011-11-18 16:02                             ` Eric Dumazet
2011-11-18 16:30                               ` Flavio Leitner [this message]
2011-11-18 16:34                                 ` Eric Dumazet
2011-11-18 17:05                                   ` Flavio Leitner
2011-11-18 17:07                                     ` Eric Dumazet
2011-11-18 17:21                                       ` Flavio Leitner
2011-11-18 18:04                                         ` David Miller
2011-11-18 20:26                               ` David Miller
2011-11-17 16:52               ` Vasiliy Kulikov

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=20111118143016.01e24b37@asterix.rh \
    --to=fbl@redhat.com \
    --cc=davem@davemloft.net \
    --cc=eric.dumazet@gmail.com \
    --cc=famzah@icdsoft.com \
    --cc=netdev@vger.kernel.org \
    --cc=segoon@openwall.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).