BPF question

Ivo Vachkov ivo.vachkov at gmail.com
Thu Nov 6 09:54:15 PST 2008


I use following code:

/* Send Announce Packet */
int zc_freebsd_sendannounce(int fd, unsigned char *mac, int zc_addr) {
	unsigned char *announce = NULL;

	int i = 0;
	unsigned int packet_len = 0;
	
	struct ether_header *eth_hdr = NULL;
	struct ether_arp *eth_arp = NULL;

	if (mac == NULL || zc_addr == 0 || zc_addr == -1)
		return -1;

	packet_len = sizeof(struct ether_header) + (sizeof(struct ether_arp)
>= ETHER_PAYLOAD ?
										sizeof(struct ether_arp) : ETHER_PAYLOAD);
	
	/* Allocate announce packet */
	if ((announce = malloc(packet_len)) == NULL)
		return -1;

	memset(announce, 0, packet_len);

	/* Populate Announce Packet
	 *
	 * eth_hdr
	 * saddr - iface mac
	 * daddr - ff:ff:ff:ff:ff:ff
	 * type = ETHERTYPE_ARP
	 *
	 * eth_arp - ARP REQUEST
	 * sender hw addr - iface mac
	 * sender ip addr - zc_addr
	 * target hw addr - 00:00:00:00:00:00
	 * target ip addr - zc_addr
	 */

	eth_hdr = (struct ether_header *)announce;
	eth_arp = (struct ether_arp *)((char *)eth_hdr + sizeof(struct ether_header));

	memcpy(eth_hdr->ether_dhost, eth_bcast_addr, ETHER_ADDR_LEN);
	memcpy(eth_hdr->ether_shost, mac, ETHER_ADDR_LEN);
	eth_hdr->ether_type = htons(ETHERTYPE_ARP);

	eth_arp->arp_hrd = htons(ARPHRD_ETHER);
	eth_arp->arp_pro = htons(ETHERTYPE_IP);
	eth_arp->arp_hln = ETHER_ADDR_LEN;
	eth_arp->arp_pln = IP_ADDR_LEN;
	eth_arp->arp_op = htons(ARPOP_REQUEST);
	
	memcpy(eth_arp->arp_sha, mac, ETHER_ADDR_LEN);
	memcpy(eth_arp->arp_spa, &zc_addr, IP_ADDR_LEN);
	memcpy(eth_arp->arp_tha, eth_null_addr, ETHER_ADDR_LEN);
	memcpy(eth_arp->arp_tpa, &zc_addr, IP_ADDR_LEN);

	/* Send packet over the wire */
	if ((i = write(fd, announce, packet_len)) < 0) {
		free(announce);
		return -1;
	}

	free(announce);
	return 0;
}

and later in my code i call this function in a loop:

			for (i = 0; i < ANNOUNCE_NUM; i++) {
				printf("ANNOUNCE ...\n"); fflush(stdout);

				/* Get initial time */
				if (clock_gettime(CLOCK_REALTIME, &ts0) < 0) {
					perror("clock_gettime");
					return -1;
				}

				/* Send Announce Packet */
				if (zc_freebsd_sendannounce(bpf_fd, mac, zc_addr) < 0) {
					printf("zc_freebsd_sendannounce(): error\n");
					return -1;
				}

				/* Possibly check for conflicts here */

				/* Get time after select() */
				if (clock_gettime(CLOCK_REALTIME, &ts1) < 0) {
					perror("clock_gettime");
					return -1;
				}

				printf("ts0.sec |%ld|, ts0.nsec |%ld|\n", ts0.tv_sec,
ts0.tv_nsec); fflush(stdout);
				printf("ts1.sec |%ld|, ts1.nsec |%ld|\n", ts1.tv_sec,
ts1.tv_nsec); fflush(stdout);

				/* wait ANNOUNCE_INTERVAL or the rest of it */
				ts0.tv_sec = ANNOUNCE_INTERVAL - (ts1.tv_sec - ts0.tv_sec) >= 0 ?
					ANNOUNCE_INTERVAL - (ts1.tv_sec - ts0.tv_sec) : 0;
				ts0.tv_nsec = ((ANNOUNCE_INTERVAL - ts0.tv_sec) * 1000000000) -
(ts1.tv_nsec - ts0.tv_nsec) >= 0 ?
					((ANNOUNCE_INTERVAL - ts0.tv_sec) * 1000000000) - (ts1.tv_nsec -
ts0.tv_nsec) : 0;
				nanosleep(&ts0, NULL);
			} /* ANNOUNCE_NUM for() */

>From the two printf()'s above i see the nanosleep() is effective.
However, when I check the packet flow with Wireshark (on the same host
where this code is running) I see the announce packets timed only
miliseconds away from one another. Could this be an issue with
Wireshark ?! Right now I have only one computer to work on, but i'll
test the timing from another computer asap.

P.S. I'm implementing part of RFC3927 (ZeroConf) as part of a bigger project


On Thu, Nov 6, 2008 at 7:06 PM, Robert Watson <rwatson at freebsd.org> wrote:
>
> On Thu, 6 Nov 2008, Ivo Vachkov wrote:
>
>> I am using simple write() calls to send packets over BPF file descriptor.
>> The BPF file descriptor is in buffered read mode (I assume this is the
>> default and I do not set it explicitly). From what I see my write() calls
>> are somewhat buffered. Since timing is relatively important for my project
>> I'd like to ask if there is a way "flush" the write buffer. Setting O_DIRECT
>> flag on the file descriptor doesn't seem to have any effect.
>
> The write(2) system call does no buffering in userspace (unlike, say,
> fwrite(3)), and when you write to a BPF device it essentially goes straight
> into the network interface output queue, so there should be no need for a
> flush mechanism.  Could you describe the buffering effect you're seeing a
> bit more?
>
> Robert N M Watson
> Computer Laboratory
> University of Cambridge
>


More information about the freebsd-net mailing list