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