linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Willy Tarreau <willy@w.ods.org>
To: "David S. Miller" <davem@redhat.com>
Cc: linux-kernel@vger.kernel.org, netdev@oss.sgi.com
Subject: [RFC][2.4 PATCH] source address selection for ARP requests
Date: Wed, 20 Aug 2003 23:34:43 +0200	[thread overview]
Message-ID: <20030820213443.GA23939@alpha.home.local> (raw)
In-Reply-To: <20030820104831.6235f3b9.davem@redhat.com>

Hi David,

On Wed, Aug 20, 2003 at 10:48:31AM -0700, David S. Miller wrote:
> On Wed, 20 Aug 2003 10:44:41 -0700
> Ben Greear <greearb@candelatech.com> wrote:
> 
> > It seems that these reasons would not preclude the addition of a flag
> > that would default to the current behaviour but allow the behaviour that
> > other setups desire easily?
> 
> I would accept a patch that did something like
> the following in arp_solicit().
> 
> 	if (skb && inet_addr_type(skb->nh.iph->saddr) == RTN_LOCAL &&
> 	    (in_dev->conf.shared_media ||
> 	     inet_addr_onlink(dev, skb->nh.iph->saddr, 0)))
> 		saddr = skb->nh.iph->saddr;
> 	else
> 		saddr = inet_select_addr(dev, target, RT_SCOPE_LINE);
> 

I finally found some time to code and test both Alexey's idea and the one I
derived from it the other day.

1) Alexey's solution (above, patch below)

It solves most issues discussed previously, which showed up on somewhat common
setups like this one :

                Server                        Gateway
    eth0=10.0.0.1   eth1=11.0.0.1 --------- IP=11.0.0.2

When server receives a ping to 10.0.0.1 from Gateway or some host behind it, it
will now properly select 11.0.0.1 for the ARP request prior to sending its
echo reply. This behaviour requires the user to explicitly set
eth1/shared_media and all/shared_media to 0 (not too hard).

=> So the patch below fixes most problems.

-8<--------------------------

--- linux-2.4.22-rc2/net/ipv4/arp.c	Wed Jul 30 09:19:06 2003
+++ linux-2.4.22-rc2-arp/net/ipv4/arp.c	Wed Aug 20 21:19:42 2003
@@ -320,13 +320,22 @@
 	u32 saddr;
 	u8  *dst_ha = NULL;
 	struct net_device *dev = neigh->dev;
+	struct in_device *in_dev = in_dev_get(dev);
 	u32 target = *(u32*)neigh->primary_key;
 	int probes = atomic_read(&neigh->probes);
 
-	if (skb && inet_addr_type(skb->nh.iph->saddr) == RTN_LOCAL)
+	if (in_dev == NULL)
+		return;
+
+	if (in_dev->ifa_list == NULL ||
+	    (skb && inet_addr_type(skb->nh.iph->saddr) == RTN_LOCAL &&
+	    (IN_DEV_SHARED_MEDIA(in_dev) ||
+	    inet_addr_onlink(in_dev, skb->nh.iph->saddr, 0))))
 		saddr = skb->nh.iph->saddr;
 	else
 		saddr = inet_select_addr(dev, target, RT_SCOPE_LINK);
+
+	in_dev_put(in_dev);
 
 	if ((probes -= neigh->parms->ucast_probes) < 0) {
 		if (!(neigh->nud_state&NUD_VALID))

-8<--------------------------

However, there still is a case which is not covered : when the source address
is itself on the same interface. Let's take the previous example and add an
alias to eth1 :

                Server                        Gateway
    eth0=10.0.0.1   eth1=11.0.0.1 --------- IP=11.0.0.2
                         12.0.0.1

If gateway pings 12.0.0.1, Server will use this address to send its ARP
requests (because of the 'inet_addr_onlink' above). The workaround would
simply be to move the alias somewhere else...

Second, you were concerned about breaking setups with no IP address on eth1
because inet_addr_onlink() will return 0,  and inet_select_addr() will fail,
in the event they would run with shared_media=0 :

                Server                        Gateway
    eth0=10.0.0.1   eth1=*no IP* ---------- IP=11.0.0.2

In fact, inet_select_addr() is smarter than inet_addr_onlink() in that it can
also return non-loopback addresses set to the loopback interface. Moreover, if
it fails, it returns 0, which is a good test to drop back to the current
behaviour (use skb->nh.iph->saddr). I didn't manage to get my interface to
send ARP requests when I have no IP address on it, because I don't know how
to do, since I cannot add a route to it. I presume I could make it work with
SO_BINDTODEVICE + MSG_DONTROUTE, but I don't have time to try all this.

So please look at this code now :

-8<-------------------------------

diff -urN linux-2.4.22-rc2/net/ipv4/arp.c linux-2.4.22-rc2-arp3/net/ipv4/arp.c
--- linux-2.4.22-rc2/net/ipv4/arp.c	Wed Jul 30 09:19:06 2003
+++ linux-2.4.22-rc2-arp3/net/ipv4/arp.c	Wed Aug 20 23:11:53 2003
@@ -320,13 +320,21 @@
 	u32 saddr;
 	u8  *dst_ha = NULL;
 	struct net_device *dev = neigh->dev;
+	struct in_device *in_dev = in_dev_get(dev);
 	u32 target = *(u32*)neigh->primary_key;
 	int probes = atomic_read(&neigh->probes);
 
-	if (skb && inet_addr_type(skb->nh.iph->saddr) == RTN_LOCAL)
-		saddr = skb->nh.iph->saddr;
+	if (in_dev == NULL)
+		return;
+
+	if (skb && inet_addr_type(skb->nh.iph->saddr) == RTN_LOCAL &&
+	    (IN_DEV_SHARED_MEDIA(in_dev) ||
+	     (saddr = inet_select_addr(dev, target, RT_SCOPE_LINK)) == 0))
+			saddr = skb->nh.iph->saddr;
 	else
 		saddr = inet_select_addr(dev, target, RT_SCOPE_LINK);
+
+	in_dev_put(in_dev);
 
 	if ((probes -= neigh->parms->ucast_probes) < 0) {
 		if (!(neigh->nud_state&NUD_VALID))


-8<-------------------------------

It will correctly pick the most appropriate address when shared_media=0, and
will also drop back to the current behaviour when there's no IP yet on the
device.

It also enhances an interesting point compared to the previous one : it allows
broken setups such as the one below to select the valid source IP depending on
source route :


                Server                        Gateway
    eth0=11.0.0.1   eth1=10.0.0.1 --------- IP=11.0.0.2

    ip addr  add 11.0.0.1/N dev eth0
    ip addr  add 10.0.0.1/M dev eth1 scope host
    ip route add 11.0.0.2 dev eth1 src 11.0.0.1

=> ARP requests sent to 11.0.0.2 "correctly" use 11.0.0.1 as the source IP.

I'm not sure this setup will concern anyone, but I came across it during my
tests of the patch, and thought that for evry setup which people will be able
to configure themselves without patching, there will be less whiners ;-)

I'd sincerely prefer the later patch to be tested and integrated, but Alexey's
first idea was the former, so I don't know which one you'll pick.

Of course, if you're willing to apply one of them, I'll try to port them to
2.6.

Cheers,
Willy


  reply	other threads:[~2003-08-20 21:36 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2003-08-19 12:02 [2.4 PATCH] bugfix: ARP respond on all devices Richard Underwood
2003-08-19 12:35 ` Alan Cox
2003-08-19 18:30   ` Daniel Gryniewicz
2003-08-19 18:29     ` David S. Miller
2003-08-19 19:12       ` Daniel Gryniewicz
2003-08-19 19:10         ` David S. Miller
2003-08-20 16:49         ` Bill Davidsen
2003-08-20 17:00           ` David S. Miller
2003-08-20 17:44             ` Ben Greear
2003-08-20 17:48               ` David S. Miller
2003-08-20 21:34                 ` Willy Tarreau [this message]
2003-08-20 21:47                   ` [RFC][2.4 PATCH] source address selection for ARP requests David S. Miller
2003-08-20 22:27                     ` Willy Tarreau
2003-08-20 22:35                       ` David S. Miller
2003-08-20 22:59                         ` Willy Tarreau
2003-08-20 23:18                 ` [2.4 PATCH] bugfix: ARP respond on all devices Julian Anastasov
2003-08-23 20:50                 ` Bill Davidsen
2003-08-20 19:08             ` Bill Davidsen
2003-08-20 20:07               ` Bas Bloemsaat
2003-08-19 19:17       ` Discussion fucking closed WAS(Re: " jamal
2003-08-19 19:42       ` bill davidsen
2003-08-20  5:31       ` ARP and knowledge of IP addresses [Re: [2.4 PATCH] bugfix: ARP respond on all devices] Pekka Savola
2003-08-19 13:11 ` [2.4 PATCH] bugfix: ARP respond on all devices Bas Bloemsaat
2003-08-19 15:34   ` David S. Miller
2003-08-19 17:39     ` Lars Marowsky-Bree
2003-08-19 17:36       ` David S. Miller
2003-08-19 21:01         ` Harley Stenzel
2003-08-19 16:19   ` Stephan von Krawczynski
2003-08-19 16:54   ` David S. Miller
2003-08-19 17:15     ` Stephan von Krawczynski
2003-08-19 16:56 ` David S. Miller
2003-08-20  5:18   ` host vs interface address ownership [Re: [2.4 PATCH] bugfix: ARP respond on all devices] Pekka Savola
2003-08-20  5:38     ` Valdis.Kletnieks

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=20030820213443.GA23939@alpha.home.local \
    --to=willy@w.ods.org \
    --cc=davem@redhat.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=netdev@oss.sgi.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).