arphold.c revision 215207
1215207Sgnn/*
2215207Sgnn * Copyright (c) 2010 Advanced Computing Technologies LLC
3215207Sgnn * Written by George Neville-Neil gnn@freebsd.org
4215207Sgnn * All rights reserved.
5215207Sgnn *
6215207Sgnn * Redistribution and use in source and binary forms, with or without
7215207Sgnn * modification, are permitted provided that the following conditions
8215207Sgnn * are met:
9215207Sgnn * 1. Redistributions of source code must retain the above copyright
10215207Sgnn *    notice, this list of conditions and the following disclaimer.
11215207Sgnn * 2. Redistributions in binary form must reproduce the above copyright
12215207Sgnn *    notice, this list of conditions and the following disclaimer in the
13215207Sgnn *    documentation and/or other materials provided with the distribution.
14215207Sgnn *
15215207Sgnn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16215207Sgnn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17215207Sgnn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18215207Sgnn * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19215207Sgnn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20215207Sgnn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21215207Sgnn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22215207Sgnn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23215207Sgnn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24215207Sgnn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25215207Sgnn * SUCH DAMAGE.
26215207Sgnn *
27215207Sgnn * Description: The following is a test of the arp entry packet queues
28215207Sgnn * which replaced the single packet hold entry that existed in the BSDs
29215207Sgnn * since time immemorial.  The test process is:
30215207Sgnn *
31215207Sgnn * 1) Find out the current system limit (maxhold)
32215207Sgnn * 2) Using an IP address for which we do not yet have an entry
33215207Sgnn *    load up an ARP entry packet queue with exactly that many packets.
34215207Sgnn * 3) Check the arp dropped stat to make sure that we have not dropped
35215207Sgnn *    any packets as yet.
36215207Sgnn * 4) Add one more packet to the queue.
37215207Sgnn * 5) Make sure that only one packet was dropped.
38215207Sgnn *
39215207Sgnn * CAVEAT: The ARP timer will flush the queue after 1 second so it is
40215207Sgnn * important not to run this code in a fast loop or the test will
41215207Sgnn * fail.
42215207Sgnn *
43215207Sgnn * $FreeBSD: head/tools/regression/netinet/arphold/arphold.c 215207 2010-11-12 22:03:02Z gnn $
44215207Sgnn */
45215207Sgnn
46215207Sgnn#include <unistd.h>
47215207Sgnn#include <stdio.h>
48215207Sgnn#include <stdlib.h>
49215207Sgnn#include <string.h>
50215207Sgnn#include <sys/types.h>
51215207Sgnn#include <sys/sysctl.h>
52215207Sgnn#include <sys/socket.h>
53215207Sgnn#include <netinet/in.h>
54215207Sgnn#include <arpa/inet.h>
55215207Sgnn#include <net/if_arp.h>
56215207Sgnn
57215207Sgnn#define MSG_SIZE 1024
58215207Sgnn#define PORT 6969
59215207Sgnn
60215207Sgnnint
61215207Sgnnmain(int argc, char **argv)
62215207Sgnn{
63215207Sgnn
64215207Sgnn	int sock;
65215207Sgnn	int maxhold;
66215207Sgnn	int wait;
67215207Sgnn	size_t size = sizeof(maxhold);
68215207Sgnn	struct sockaddr_in dest;
69215207Sgnn	char message[MSG_SIZE];
70215207Sgnn	struct arpstat arpstat;
71215207Sgnn	size_t len = sizeof(arpstat);
72215207Sgnn	unsigned long dropped = 0;
73215207Sgnn
74215207Sgnn	memset(&message, 1, sizeof(message));
75215207Sgnn
76215207Sgnn	if (sysctlbyname("net.link.ether.inet.maxhold", &maxhold, &size,
77215207Sgnn			 NULL, 0) < 0) {
78215207Sgnn		perror("not ok 1 - sysctlbyname failed");
79215207Sgnn		exit(1);
80215207Sgnn	}
81215207Sgnn
82215207Sgnn#ifdef DEBUG
83215207Sgnn	printf("maxhold is %d\n", maxhold);
84215207Sgnn#endif /* DEBUG */
85215207Sgnn
86215207Sgnn	if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
87215207Sgnn		perror("not ok 1 - could not open socket");
88215207Sgnn		exit(1);
89215207Sgnn	}
90215207Sgnn
91215207Sgnn	bzero(&dest, sizeof(dest));
92215207Sgnn	if (inet_pton(AF_INET, argv[1], &dest.sin_addr.s_addr) != 1) {
93215207Sgnn		perror("not ok 1 - could not parse address");
94215207Sgnn		exit(1);
95215207Sgnn	}
96215207Sgnn	dest.sin_len = sizeof(dest);
97215207Sgnn	dest.sin_family = AF_INET;
98215207Sgnn	dest.sin_port = htons(PORT);
99215207Sgnn
100215207Sgnn	if (sysctlbyname("net.link.ether.arp.stats", &arpstat, &len,
101215207Sgnn			 NULL, 0) < 0) {
102215207Sgnn		perror("not ok 1 - could not get initial arp stats");
103215207Sgnn		exit(1);
104215207Sgnn	}
105215207Sgnn
106215207Sgnn	dropped = arpstat.dropped;
107215207Sgnn#ifdef DEBUG
108215207Sgnn	printf("dropped before %ld\n", dropped);
109215207Sgnn#endif /* DEBUG */
110215207Sgnn
111215207Sgnn	/*
112215207Sgnn	 * Load up the queue in the ARP entry to the maximum.
113215207Sgnn	 * We should not drop any packets at this point.
114215207Sgnn	 */
115215207Sgnn
116215207Sgnn	while (maxhold > 0) {
117215207Sgnn		if (sendto(sock, message, sizeof(message), 0,
118215207Sgnn			   (struct sockaddr *)&dest, sizeof(dest)) < 0) {
119215207Sgnn			perror("not ok 1 - could not send packet");
120215207Sgnn			exit(1);
121215207Sgnn		}
122215207Sgnn		maxhold--;
123215207Sgnn	}
124215207Sgnn
125215207Sgnn	if (sysctlbyname("net.link.ether.arp.stats", &arpstat, &len,
126215207Sgnn			 NULL, 0) < 0) {
127215207Sgnn		perror("not ok 1 - could not get new arp stats");
128215207Sgnn		exit(1);
129215207Sgnn	}
130215207Sgnn
131215207Sgnn#ifdef DEBUG
132215207Sgnn	printf("dropped after %ld\n", arpstat.dropped);
133215207Sgnn#endif /* DEBUG */
134215207Sgnn
135215207Sgnn	if (arpstat.dropped != dropped) {
136215207Sgnn		printf("not ok 1 - Failed, drops changed:"
137215207Sgnn		       "before %ld after %ld\n", dropped, arpstat.dropped);
138215207Sgnn		exit(1);
139215207Sgnn	}
140215207Sgnn
141215207Sgnn	dropped = arpstat.dropped;
142215207Sgnn
143215207Sgnn	/* Now add one extra and make sure it is dropped. */
144215207Sgnn	if (sendto(sock, message, sizeof(message), 0,
145215207Sgnn		   (struct sockaddr *)&dest, sizeof(dest)) < 0) {
146215207Sgnn		perror("not ok 1 - could not send packet");
147215207Sgnn		exit(1);
148215207Sgnn	}
149215207Sgnn
150215207Sgnn	if (sysctlbyname("net.link.ether.arp.stats", &arpstat, &len,
151215207Sgnn			 NULL, 0) < 0) {
152215207Sgnn		perror("not ok 1 - could not get new arp stats");
153215207Sgnn		exit(1);
154215207Sgnn	}
155215207Sgnn
156215207Sgnn	if (arpstat.dropped != (dropped + 1)) {
157215207Sgnn		printf("not ok 1 - Failed to drop one packet: before"
158215207Sgnn		       " %ld after %ld\n", dropped, arpstat.dropped);
159215207Sgnn		exit(1);
160215207Sgnn	}
161215207Sgnn
162215207Sgnn	printf("ok\n");
163215207Sgnn	return (0);
164215207Sgnn}
165