Hello,
On Fri, 13 Feb 2004, David S. Miller wrote:
> > http://www.ssi.bg/~ja/arp_announce-2.6.2-4.diff
>
> Ok, I eat this, please make a 2.4.x version against Marcelo's current tree.
Attached, against rc2 which looks enough.
> The 2.6.x variant will go into 2.6.4-pre1 and the 2.4.x will go into 2.4.26-pre1
very good
Regards
--
Julian Anastasov <ja@ssi.bg>
diff -ur v2.4.25-rc2/linux/Documentation/networking/ip-sysctl.txt linux/Documentation/networking/ip-sysctl.txt
--- v2.4.25-rc2/linux/Documentation/networking/ip-sysctl.txt 2003-06-14 08:41:59.000000000 +0300
+++ linux/Documentation/networking/ip-sysctl.txt 2004-02-14 11:00:31.528798088 +0200
@@ -481,6 +481,37 @@
conf/{all,interface}/arp_filter is set to TRUE,
it will be disabled otherwise
+arp_announce - INTEGER
+ Define different restriction levels for announcing the local
+ source IP address from IP packets in ARP requests sent on
+ interface:
+ 0 - (default) Use any local address, configured on any interface
+ 1 - Try to avoid local addresses that are not in the target's
+ subnet for this interface. This mode is useful when target
+ hosts reachable via this interface require the source IP
+ address in ARP requests to be part of their logical network
+ configured on the receiving interface. When we generate the
+ request we will check all our subnets that include the
+ target IP and will preserve the source address if it is from
+ such subnet. If there is no such subnet we select source
+ address according to the rules for level 2.
+ 2 - Always use the best local address for this target.
+ In this mode we ignore the source address in the IP packet
+ and try to select local address that we prefer for talks with
+ the target host. Such local address is selected by looking
+ for primary IP addresses on all our subnets on the outgoing
+ interface that include the target IP address. If no suitable
+ local address is found we select the first local address
+ we have on the outgoing interface or on all other interfaces,
+ with the hope we will receive reply for our request and
+ even sometimes no matter the source IP address we announce.
+
+ The max value from conf/{all,interface}/arp_announce is used.
+
+ Increasing the restriction level gives more chance for
+ receiving answer from the resolved target while decreasing
+ the level announces more valid sender's information.
+
tag - INTEGER
Allows you to write a number, which can be used as required.
Default value is 0.
diff -ur v2.4.25-rc2/linux/include/linux/inetdevice.h linux/include/linux/inetdevice.h
--- v2.4.25-rc2/linux/include/linux/inetdevice.h 2004-02-14 10:37:06.000000000 +0200
+++ linux/include/linux/inetdevice.h 2004-02-14 11:00:31.549794896 +0200
@@ -18,6 +18,7 @@
int mc_forwarding;
int tag;
int arp_filter;
+ int arp_announce;
int medium_id;
int force_igmp_version;
void *sysctl;
@@ -69,6 +70,7 @@
(ipv4_devconf.accept_redirects || (in_dev)->cnf.accept_redirects)))
#define IN_DEV_ARPFILTER(in_dev) (ipv4_devconf.arp_filter || (in_dev)->cnf.arp_filter)
+#define IN_DEV_ARP_ANNOUNCE(in_dev) (max(ipv4_devconf.arp_announce, (in_dev)->cnf.arp_announce))
struct in_ifaddr
{
diff -ur v2.4.25-rc2/linux/include/linux/sysctl.h linux/include/linux/sysctl.h
--- v2.4.25-rc2/linux/include/linux/sysctl.h 2004-02-14 10:37:06.000000000 +0200
+++ linux/include/linux/sysctl.h 2004-02-14 11:00:31.550794744 +0200
@@ -360,6 +360,7 @@
NET_IPV4_CONF_ARPFILTER=13,
NET_IPV4_CONF_MEDIUM_ID=14,
NET_IPV4_CONF_FORCE_IGMP_VERSION=17,
+ NET_IPV4_CONF_ARP_ANNOUNCE=18,
};
/* /proc/sys/net/ipv4/netfilter */
diff -ur v2.4.25-rc2/linux/net/ipv4/arp.c linux/net/ipv4/arp.c
--- v2.4.25-rc2/linux/net/ipv4/arp.c 2003-11-28 22:04:14.000000000 +0200
+++ linux/net/ipv4/arp.c 2004-02-14 11:00:31.551794592 +0200
@@ -317,15 +317,40 @@
static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
{
- u32 saddr;
+ u32 saddr = 0;
u8 *dst_ha = NULL;
struct net_device *dev = neigh->dev;
u32 target = *(u32*)neigh->primary_key;
int probes = atomic_read(&neigh->probes);
+ struct in_device *in_dev = in_dev_get(dev);
+
+ if (!in_dev)
+ return;
- if (skb && inet_addr_type(skb->nh.iph->saddr) == RTN_LOCAL)
+ switch (IN_DEV_ARP_ANNOUNCE(in_dev)) {
+ default:
+ case 0: /* By default announce any local IP */
+ if (skb && inet_addr_type(skb->nh.iph->saddr) == RTN_LOCAL)
+ saddr = skb->nh.iph->saddr;
+ break;
+ case 1: /* Restrict announcements of saddr in same subnet */
+ if (!skb)
+ break;
saddr = skb->nh.iph->saddr;
- else
+ if (inet_addr_type(saddr) == RTN_LOCAL) {
+ /* saddr should be known to target */
+ if (inet_addr_onlink(in_dev, target, saddr))
+ break;
+ }
+ saddr = 0;
+ break;
+ case 2: /* Avoid secondary IPs, get a primary/preferred one */
+ break;
+ }
+
+ if (in_dev)
+ in_dev_put(in_dev);
+ if (!saddr)
saddr = inet_select_addr(dev, target, RT_SCOPE_LINK);
if ((probes -= neigh->parms->ucast_probes) < 0) {
diff -ur v2.4.25-rc2/linux/net/ipv4/devinet.c linux/net/ipv4/devinet.c
--- v2.4.25-rc2/linux/net/ipv4/devinet.c 2004-02-14 10:37:06.000000000 +0200
+++ linux/net/ipv4/devinet.c 2004-02-14 11:01:37.845716384 +0200
@@ -1057,7 +1057,7 @@
static struct devinet_sysctl_table
{
struct ctl_table_header *sysctl_header;
- ctl_table devinet_vars[18];
+ ctl_table devinet_vars[19];
ctl_table devinet_dev[2];
ctl_table devinet_conf_dir[2];
ctl_table devinet_proto_dir[2];
@@ -1106,6 +1106,9 @@
{NET_IPV4_CONF_ARPFILTER, "arp_filter",
&ipv4_devconf.arp_filter, sizeof(int), 0644, NULL,
&proc_dointvec},
+ {NET_IPV4_CONF_ARP_ANNOUNCE, "arp_announce",
+ &ipv4_devconf.arp_announce, sizeof(int), 0644, NULL,
+ &proc_dointvec},
{NET_IPV4_CONF_FORCE_IGMP_VERSION, "force_igmp_version",
&ipv4_devconf.force_igmp_version, sizeof(int), 0644, NULL,
&proc_dointvec},