[openib-general] [IPoIB][RFC] neighbour/arp table manipulation
James Lentini
jlentini at netapp.com
Mon Mar 13 11:49:21 PST 2006
Both ip(8) and arp(8), the Linux system commands for managing the
neighbour/arp table, have bugs dealing with IPoIB MAC addresses.
Specifically they do not correctly handle the addition of new entries.
For example, these commands will fail:
ip neigh add 192.168.0.138 lladdr 00:00:04:04:fe:80:00:00:00:00:00:00:00:01:73:00:00:00:8a:91 nud permanent dev ib0
arp -n -H infiniband -i ib0 -s 192.168.0.138 00:00:04:04:fe:80:00:00:00:00:00:00:00:01:73:00:00:00:8a:91
To the best of my knowledge this hasn't documented before.
In the case of the ip(8) command, the problem is simple. The command
line parsing code requires the link layer address to be a maximum of
16-bytes. Addresses over 16-bytes are truncated. This patch fixes the
problem:
============================================
--- iproute2-2.6.15-060110/ip/ipneigh.c.orig 2006-03-10 16:08:37.361756000 -0500
+++ iproute2-2.6.15-060110/ip/ipneigh.c 2006-03-10 17:07:10.594429000 -0500
@@ -165,7 +165,7 @@ static int ipneigh_modify(int cmd, int f
addattr_l(&req.n, sizeof(req), NDA_DST, &dst.data, dst.bytelen);
if (lla && strcmp(lla, "null")) {
- char llabuf[16];
+ char llabuf[20];
int l;
l = ll_addr_a2n(llabuf, sizeof(llabuf), lla);
============================================
I'm planning on sending this as a patch to netdev and the iproute2
maintainer. Please let me know if you have any suggestions for
improving the patch.
In the case of the arp(8) command, the situation is a bit more
complicated. The arp command uses a SIOCSARP ioctl which takes a
struct arpreq argument:
struct arpreq {
struct sockaddr arp_pa; /* protocol address */
struct sockaddr arp_ha; /* hardware address */
int arp_flags; /* flags */
struct sockaddr arp_netmask; /* netmask (only for proxy arps) */
char arp_dev[16];
};
where
struct sockaddr {
sa_family_t sa_family; /* address family, AF_xxx */
char sa_data[14]; /* 14 bytes of protocol address */
};
The size of the IB HW address is 20 bytes (6 bytes greater than the
space available in the struct sockaddr). The arp command doesn't check
that the size of the user-specified hardware address will fit into a
sockaddr. As a result, the IB HW address ends up spilling over into
the arp_flags and, on 32-bit platforms, into the arp_netmask.
Between the arp command and the kernel's arp_req_set() function, the
arp_flags field is set to ATF_PERM | ATF_COM = 0x6. This results in
the 15th byte of the IB HW address always being set to 0x6.
To fix the problem, the arpreq structure needs to be updated and thus
the userspace arp command and kernel ioctl code need to change.
I believe that the SIOCSARP ioctl is supported for backward
compatibility and the arp command is deprecated. Therefore I don't
believe this problem should be fixed (because it would break backward
compatibility).
More information about the general
mailing list