xref: /freebsd/tools/regression/netinet/arphold/arphold.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
1e162ea60SGeorge V. Neville-Neil /*
2*179fa75eSJohn Baldwin  * Copyright (c) 2010 Hudson River Trading LLC
3e162ea60SGeorge V. Neville-Neil  * Written by George Neville-Neil gnn@freebsd.org
4e162ea60SGeorge V. Neville-Neil  * All rights reserved.
5e162ea60SGeorge V. Neville-Neil  *
6e162ea60SGeorge V. Neville-Neil  * Redistribution and use in source and binary forms, with or without
7e162ea60SGeorge V. Neville-Neil  * modification, are permitted provided that the following conditions
8e162ea60SGeorge V. Neville-Neil  * are met:
9e162ea60SGeorge V. Neville-Neil  * 1. Redistributions of source code must retain the above copyright
10e162ea60SGeorge V. Neville-Neil  *    notice, this list of conditions and the following disclaimer.
11e162ea60SGeorge V. Neville-Neil  * 2. Redistributions in binary form must reproduce the above copyright
12e162ea60SGeorge V. Neville-Neil  *    notice, this list of conditions and the following disclaimer in the
13e162ea60SGeorge V. Neville-Neil  *    documentation and/or other materials provided with the distribution.
14e162ea60SGeorge V. Neville-Neil  *
15e162ea60SGeorge V. Neville-Neil  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16e162ea60SGeorge V. Neville-Neil  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17e162ea60SGeorge V. Neville-Neil  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18e162ea60SGeorge V. Neville-Neil  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19e162ea60SGeorge V. Neville-Neil  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20e162ea60SGeorge V. Neville-Neil  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21e162ea60SGeorge V. Neville-Neil  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22e162ea60SGeorge V. Neville-Neil  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23e162ea60SGeorge V. Neville-Neil  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24e162ea60SGeorge V. Neville-Neil  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25e162ea60SGeorge V. Neville-Neil  * SUCH DAMAGE.
26e162ea60SGeorge V. Neville-Neil  *
27e162ea60SGeorge V. Neville-Neil  * Description: The following is a test of the arp entry packet queues
28e162ea60SGeorge V. Neville-Neil  * which replaced the single packet hold entry that existed in the BSDs
29e162ea60SGeorge V. Neville-Neil  * since time immemorial.  The test process is:
30e162ea60SGeorge V. Neville-Neil  *
31e162ea60SGeorge V. Neville-Neil  * 1) Find out the current system limit (maxhold)
32e162ea60SGeorge V. Neville-Neil  * 2) Using an IP address for which we do not yet have an entry
33e162ea60SGeorge V. Neville-Neil  *    load up an ARP entry packet queue with exactly that many packets.
34e162ea60SGeorge V. Neville-Neil  * 3) Check the arp dropped stat to make sure that we have not dropped
35e162ea60SGeorge V. Neville-Neil  *    any packets as yet.
36e162ea60SGeorge V. Neville-Neil  * 4) Add one more packet to the queue.
37e162ea60SGeorge V. Neville-Neil  * 5) Make sure that only one packet was dropped.
38e162ea60SGeorge V. Neville-Neil  *
39e162ea60SGeorge V. Neville-Neil  * CAVEAT: The ARP timer will flush the queue after 1 second so it is
40e162ea60SGeorge V. Neville-Neil  * important not to run this code in a fast loop or the test will
41e162ea60SGeorge V. Neville-Neil  * fail.
42e162ea60SGeorge V. Neville-Neil  */
43e162ea60SGeorge V. Neville-Neil 
44e162ea60SGeorge V. Neville-Neil #include <unistd.h>
45e162ea60SGeorge V. Neville-Neil #include <stdio.h>
46e162ea60SGeorge V. Neville-Neil #include <stdlib.h>
47e162ea60SGeorge V. Neville-Neil #include <string.h>
48e162ea60SGeorge V. Neville-Neil #include <sys/types.h>
49e162ea60SGeorge V. Neville-Neil #include <sys/sysctl.h>
50e162ea60SGeorge V. Neville-Neil #include <sys/socket.h>
51e162ea60SGeorge V. Neville-Neil #include <netinet/in.h>
52e162ea60SGeorge V. Neville-Neil #include <arpa/inet.h>
53e162ea60SGeorge V. Neville-Neil #include <net/if_arp.h>
54e162ea60SGeorge V. Neville-Neil 
55e162ea60SGeorge V. Neville-Neil #define MSG_SIZE 1024
56e162ea60SGeorge V. Neville-Neil #define PORT 6969
57e162ea60SGeorge V. Neville-Neil 
58e162ea60SGeorge V. Neville-Neil int
main(int argc,char ** argv)59e162ea60SGeorge V. Neville-Neil main(int argc, char **argv)
60e162ea60SGeorge V. Neville-Neil {
61e162ea60SGeorge V. Neville-Neil 
62e162ea60SGeorge V. Neville-Neil 	int sock;
63e162ea60SGeorge V. Neville-Neil 	int maxhold;
64e162ea60SGeorge V. Neville-Neil 	size_t size = sizeof(maxhold);
65e162ea60SGeorge V. Neville-Neil 	struct sockaddr_in dest;
66e162ea60SGeorge V. Neville-Neil 	char message[MSG_SIZE];
67e162ea60SGeorge V. Neville-Neil 	struct arpstat arpstat;
68e162ea60SGeorge V. Neville-Neil 	size_t len = sizeof(arpstat);
69e162ea60SGeorge V. Neville-Neil 	unsigned long dropped = 0;
70e162ea60SGeorge V. Neville-Neil 
71e162ea60SGeorge V. Neville-Neil 	memset(&message, 1, sizeof(message));
72e162ea60SGeorge V. Neville-Neil 
73e162ea60SGeorge V. Neville-Neil 	if (sysctlbyname("net.link.ether.inet.maxhold", &maxhold, &size,
74e162ea60SGeorge V. Neville-Neil 			 NULL, 0) < 0) {
75e162ea60SGeorge V. Neville-Neil 		perror("not ok 1 - sysctlbyname failed");
76e162ea60SGeorge V. Neville-Neil 		exit(1);
77e162ea60SGeorge V. Neville-Neil 	}
78e162ea60SGeorge V. Neville-Neil 
79e162ea60SGeorge V. Neville-Neil #ifdef DEBUG
80e162ea60SGeorge V. Neville-Neil 	printf("maxhold is %d\n", maxhold);
81e162ea60SGeorge V. Neville-Neil #endif /* DEBUG */
82e162ea60SGeorge V. Neville-Neil 
83e162ea60SGeorge V. Neville-Neil 	if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
84e162ea60SGeorge V. Neville-Neil 		perror("not ok 1 - could not open socket");
85e162ea60SGeorge V. Neville-Neil 		exit(1);
86e162ea60SGeorge V. Neville-Neil 	}
87e162ea60SGeorge V. Neville-Neil 
88e162ea60SGeorge V. Neville-Neil 	bzero(&dest, sizeof(dest));
89e162ea60SGeorge V. Neville-Neil 	if (inet_pton(AF_INET, argv[1], &dest.sin_addr.s_addr) != 1) {
90e162ea60SGeorge V. Neville-Neil 		perror("not ok 1 - could not parse address");
91e162ea60SGeorge V. Neville-Neil 		exit(1);
92e162ea60SGeorge V. Neville-Neil 	}
93e162ea60SGeorge V. Neville-Neil 	dest.sin_len = sizeof(dest);
94e162ea60SGeorge V. Neville-Neil 	dest.sin_family = AF_INET;
95e162ea60SGeorge V. Neville-Neil 	dest.sin_port = htons(PORT);
96e162ea60SGeorge V. Neville-Neil 
97e162ea60SGeorge V. Neville-Neil 	if (sysctlbyname("net.link.ether.arp.stats", &arpstat, &len,
98e162ea60SGeorge V. Neville-Neil 			 NULL, 0) < 0) {
99e162ea60SGeorge V. Neville-Neil 		perror("not ok 1 - could not get initial arp stats");
100e162ea60SGeorge V. Neville-Neil 		exit(1);
101e162ea60SGeorge V. Neville-Neil 	}
102e162ea60SGeorge V. Neville-Neil 
103e162ea60SGeorge V. Neville-Neil 	dropped = arpstat.dropped;
104e162ea60SGeorge V. Neville-Neil #ifdef DEBUG
105e162ea60SGeorge V. Neville-Neil 	printf("dropped before %ld\n", dropped);
106e162ea60SGeorge V. Neville-Neil #endif /* DEBUG */
107e162ea60SGeorge V. Neville-Neil 
108e162ea60SGeorge V. Neville-Neil 	/*
109e162ea60SGeorge V. Neville-Neil 	 * Load up the queue in the ARP entry to the maximum.
110e162ea60SGeorge V. Neville-Neil 	 * We should not drop any packets at this point.
111e162ea60SGeorge V. Neville-Neil 	 */
112e162ea60SGeorge V. Neville-Neil 
113e162ea60SGeorge V. Neville-Neil 	while (maxhold > 0) {
114e162ea60SGeorge V. Neville-Neil 		if (sendto(sock, message, sizeof(message), 0,
115e162ea60SGeorge V. Neville-Neil 			   (struct sockaddr *)&dest, sizeof(dest)) < 0) {
116e162ea60SGeorge V. Neville-Neil 			perror("not ok 1 - could not send packet");
117e162ea60SGeorge V. Neville-Neil 			exit(1);
118e162ea60SGeorge V. Neville-Neil 		}
119e162ea60SGeorge V. Neville-Neil 		maxhold--;
120e162ea60SGeorge V. Neville-Neil 	}
121e162ea60SGeorge V. Neville-Neil 
122e162ea60SGeorge V. Neville-Neil 	if (sysctlbyname("net.link.ether.arp.stats", &arpstat, &len,
123e162ea60SGeorge V. Neville-Neil 			 NULL, 0) < 0) {
124e162ea60SGeorge V. Neville-Neil 		perror("not ok 1 - could not get new arp stats");
125e162ea60SGeorge V. Neville-Neil 		exit(1);
126e162ea60SGeorge V. Neville-Neil 	}
127e162ea60SGeorge V. Neville-Neil 
128e162ea60SGeorge V. Neville-Neil #ifdef DEBUG
129e162ea60SGeorge V. Neville-Neil 	printf("dropped after %ld\n", arpstat.dropped);
130e162ea60SGeorge V. Neville-Neil #endif /* DEBUG */
131e162ea60SGeorge V. Neville-Neil 
132e162ea60SGeorge V. Neville-Neil 	if (arpstat.dropped != dropped) {
133e162ea60SGeorge V. Neville-Neil 		printf("not ok 1 - Failed, drops changed:"
134e162ea60SGeorge V. Neville-Neil 		       "before %ld after %ld\n", dropped, arpstat.dropped);
135e162ea60SGeorge V. Neville-Neil 		exit(1);
136e162ea60SGeorge V. Neville-Neil 	}
137e162ea60SGeorge V. Neville-Neil 
138e162ea60SGeorge V. Neville-Neil 	dropped = arpstat.dropped;
139e162ea60SGeorge V. Neville-Neil 
140e162ea60SGeorge V. Neville-Neil 	/* Now add one extra and make sure it is dropped. */
141e162ea60SGeorge V. Neville-Neil 	if (sendto(sock, message, sizeof(message), 0,
142e162ea60SGeorge V. Neville-Neil 		   (struct sockaddr *)&dest, sizeof(dest)) < 0) {
143e162ea60SGeorge V. Neville-Neil 		perror("not ok 1 - could not send packet");
144e162ea60SGeorge V. Neville-Neil 		exit(1);
145e162ea60SGeorge V. Neville-Neil 	}
146e162ea60SGeorge V. Neville-Neil 
147e162ea60SGeorge V. Neville-Neil 	if (sysctlbyname("net.link.ether.arp.stats", &arpstat, &len,
148e162ea60SGeorge V. Neville-Neil 			 NULL, 0) < 0) {
149e162ea60SGeorge V. Neville-Neil 		perror("not ok 1 - could not get new arp stats");
150e162ea60SGeorge V. Neville-Neil 		exit(1);
151e162ea60SGeorge V. Neville-Neil 	}
152e162ea60SGeorge V. Neville-Neil 
153e162ea60SGeorge V. Neville-Neil 	if (arpstat.dropped != (dropped + 1)) {
154e162ea60SGeorge V. Neville-Neil 		printf("not ok 1 - Failed to drop one packet: before"
155e162ea60SGeorge V. Neville-Neil 		       " %ld after %ld\n", dropped, arpstat.dropped);
156e162ea60SGeorge V. Neville-Neil 		exit(1);
157e162ea60SGeorge V. Neville-Neil 	}
158e162ea60SGeorge V. Neville-Neil 
159e162ea60SGeorge V. Neville-Neil 	printf("ok\n");
160e162ea60SGeorge V. Neville-Neil 	return (0);
161e162ea60SGeorge V. Neville-Neil }
162