zcip, link-local ARP responses

Sebastian Fett db_extern at gmx.de
Wed Aug 12 07:01:59 UTC 2015



Am 04.08.2015 um 14:36 schrieb Denys Vlasenko:
> On Tue, Aug 4, 2015 at 12:00 PM, Sebastian Fett <db_extern at gmx.de> wrote:
>>> On Tue, Jul 21, 2015 at 2:03 PM, dbextern <db_extern at gmx.de> wrote:
>>>> For our link local functionality I'm using udhcpc together with zcip out
>>>> of busybox on a Blackfin BF-537 CPU without MMU.
>>>>
>>>> The base functionality is there.
>>>> But when I connect two networks with stable IP addresses, and both
>>>> networks had the same IP(s) in them, the conflict stays unresolved.
>>>> My setup is one master PC or MAC and several embedded boards.
>>>>
>>>> What I would expect (following RFC3927
>>>> https://tools.ietf.org/html/rfc3927#page-10[https://3c.gmx.net/mail/client/dereferrer?redirectUrl=https%3A%2F%2Ftools.ietf.org%2Fhtml%2Frfc3927%23page-10];
>>>> chapter 2.x and 4) is that after a while the ARP messages will resolve the
>>>> problem because the still running zcip sees ARP responses on it's own IP and
>>>> reacts accordingly.
>>>> What really happens is:
>>>> * Windows only sends broadcast ARP requests as long as it never got an
>>>> answer. After that there is only unicast. And the requested device answers
>>>> with a unicast as well.
>>>> * the MAC always sends broadcasts. And both embedded devices with the
>>>> conflicting IP answer. But with a unicast ARP reply to the MAC.
>>>>
>>>> As I understand the specification (last paragraph in chapter 2.5) then
>>>> all ARP messages between devices with link local addresses should be link
>>>> layer broadcasts.
>>>> Did I get that right? And if yes, why does zcip not follow that rule?
>>>
>>>
>>> zcip does use bcast for all packets it sends:
>>>
>>> # tcpdump -nliwlan0 -s0 -vv -e arp
>>> tcpdump: listening on wlan0, link-type EN10MB (Ethernet), capture size
>>> 65535 bytes
>>>            <zcip runs>
>>> 02:49:51.078369 00:04:e2:64:23:c2 > ff:ff:ff:ff:ff:ff, ethertype ARP
>>> (0x0806), length 42: arp who-has 169.254.194.171 tell 0.0.0.0
>>> 02:49:52.391711 00:04:e2:64:23:c2 > ff:ff:ff:ff:ff:ff, ethertype ARP
>>> (0x0806), length 42: arp who-has 169.254.194.171 tell 0.0.0.0
>>> 02:49:54.254628 00:04:e2:64:23:c2 > ff:ff:ff:ff:ff:ff, ethertype ARP
>>> (0x0806), length 42: arp who-has 169.254.194.171 tell 0.0.0.0
>>> 02:49:55.305731 00:04:e2:64:23:c2 > ff:ff:ff:ff:ff:ff, ethertype ARP
>>> (0x0806), length 42: arp who-has 169.254.194.171 (00:04:e2:64:23:c2)
>>> tell 169.254.194.171
>>> 02:49:57.307788 00:04:e2:64:23:c2 > ff:ff:ff:ff:ff:ff, ethertype ARP
>>> (0x0806), length 42: arp who-has 169.254.194.171 (00:04:e2:64:23:c2)
>>> tell 169.254.194.171
>>> 02:49:59.309844 00:04:e2:64:23:c2 > ff:ff:ff:ff:ff:ff, ethertype ARP
>>> (0x0806), length 42: arp who-has 169.254.194.171 (00:04:e2:64:23:c2)
>>> tell 169.254.194.171
>>
>>
>> Thanks for looking into that.
>>
>> These are the probing and announcement messages from zcip. They need to be
>> and are bcasts.
>> What it does not do is answer normal ARP requests with a broadcast. Which is
>> specified in RCF3927 as the right thing to do.
>
> Looking at the code, it should answer to them:
>
>                  // packets arriving, or link went down
>                  case 1:
> ...
>                  switch (state) {
> ...                      case MONITOR:
>                                  // If a conflict, we try to defend
> with a single ARP probe.
>                                  if (source_ip_conflict) {
>                                          VDBG("monitor conflict -- defending\n");
>                                          state = DEFEND;
>                                          timeout_ms = DEFEND_INTERVAL * 1000;
>                                          arp(/* ARPOP_REQUEST, */
>                                                  /* &eth_addr, */ ip,
>                                                  &eth_addr, ip);
>                                  }
>                                  break;
>
> The call to arp() in the code snippet above should send a broadcast
> ARP probe.
>

That was my first thought, too. But this only resolves the problem when 
another device does it's probing.
What I needed was a bcast answer to a general ARP request.

This is the patch I use. It's not tidy and the comments are in german, 
sorry.
And the result of this ist that the devices answers to an ARP request 
twice. A bcast from zcip and a unicast from the kernel. Not really nice, 
but acceptable in my usecase.



--- a/networking/zcip.c	2015-07-21 15:10:45.047362400 +0200
+++ c/networking/zcip.c	2015-07-22 14:44:13.280779500 +0200
@@ -117,12 +117,12 @@
   * Broadcast an ARP packet.
   */
  static void arp(
-	/* int op, - always ARPOP_REQUEST */
+	 int op, /*- always ARPOP_REQUEST */
  	/* const struct ether_addr *source_eth, - always &eth_addr */
  					struct in_addr source_ip,
  	const struct ether_addr *target_eth, struct in_addr target_ip)
  {
-	enum { op = ARPOP_REQUEST };
+//	enum { op = ARPOP_REQUEST }; //wir uebergeben wieder von aussen
  #define source_eth (&eth_addr)

  	struct arp_packet p;
@@ -348,6 +348,7 @@
  		struct arp_packet p;
  		int source_ip_conflict;
  		int target_ip_conflict;
+		int bcast_arp_response;

  		fds[0].fd = sock_fd;
  		fds[0].events = POLLIN;
@@ -385,7 +386,7 @@
  							nprobes, argv_intf, inet_ntoa(ip));
  					timeout_ms = PROBE_MIN * 1000;
  					timeout_ms += random_delay_ms(PROBE_MAX - PROBE_MIN);
-					arp(/* ARPOP_REQUEST, */
+					arp( ARPOP_REQUEST, /**/
  							/* &eth_addr, */ null_ip,
  							&null_addr, ip);
  				}
@@ -396,7 +397,7 @@
  					VDBG("announce/%u %s@%s\n",
  							nclaims, argv_intf, inet_ntoa(ip));
  					timeout_ms = ANNOUNCE_INTERVAL  * 1000;
-					arp(/* ARPOP_REQUEST, */
+					arp(ARPOP_REQUEST, /* */
  							/* &eth_addr, */ ip,
  							&eth_addr, ip);
  				}
@@ -409,7 +410,7 @@
  				VDBG("announce/%u %s@%s\n",
  						nclaims, argv_intf, inet_ntoa(ip));
  				timeout_ms = ANNOUNCE_INTERVAL * 1000;
-				arp(/* ARPOP_REQUEST, */
+				arp( ARPOP_REQUEST, /**/
  						/* &eth_addr, */ ip,
  						&eth_addr, ip);
  				break;
@@ -421,7 +422,7 @@
  					VDBG("announce/%u %s@%s\n",
  							nclaims, argv_intf, inet_ntoa(ip));
  					timeout_ms = ANNOUNCE_INTERVAL * 1000;
-					arp(/* ARPOP_REQUEST, */
+					arp( ARPOP_REQUEST, /**/
  							/* &eth_addr, */ ip,
  							&eth_addr, ip);
  				}
@@ -519,6 +520,7 @@

  			source_ip_conflict = 0;
  			target_ip_conflict = 0;
+			bcast_arp_response = 0;

  			if (memcmp(&p.arp.arp_sha, &eth_addr, ETH_ALEN) != 0) {
  				if (memcmp(p.arp.arp_spa, &ip.s_addr, sizeof(struct in_addr)) == 0) {
@@ -526,13 +528,20 @@
  					source_ip_conflict = 1;
  				}
  				if (p.arp.arp_op == htons(ARPOP_REQUEST)
-				 && memcmp(p.arp.arp_spa, &null_ip, sizeof(struct in_addr)) == 0
  				 && memcmp(p.arp.arp_tpa, &ip.s_addr, sizeof(struct in_addr)) == 0
  				) {
-					/* A probe with source_ip == 0.0.0.0, target_ip == chosen ip:
-					 * another host trying to claim this ip!
-					 */
-					target_ip_conflict = 1;
+				
+					if ( memcmp(p.arp.arp_spa, &null_ip, sizeof(struct in_addr)) == 0 
) //Probe eines anders LL Geraetes
+					{
+						/* A probe with source_ip == 0.0.0.0, target_ip == chosen ip:
+						* another host trying to claim this ip!
+						*/
+						target_ip_conflict = 1;
+					}
+					else //normaler ARP Request an meine Adresse, wir Antworten mit 
BCast ARP Response
+					{
+						bcast_arp_response = 1;
+					}
  				}
  			}

@@ -564,7 +573,13 @@
  					VDBG("monitor conflict -- defending\n");
  					state = DEFEND;
  					timeout_ms = DEFEND_INTERVAL * 1000;
-					arp(/* ARPOP_REQUEST, */
+					arp( ARPOP_REQUEST, /**/
+						/* &eth_addr, */ ip,
+						&eth_addr, ip);
+				}
+				else if (bcast_arp_response)//no conflict --> send broadcast arp 
response
+				{
+					arp( ARPOP_REPLY, /**/
  						/* &eth_addr, */ ip,
  						&eth_addr, ip);
  				}



More information about the busybox mailing list