1215207Sgnn/* 2281887Sjhb * Copyright (c) 2010 Hudson River Trading 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$ 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 size_t size = sizeof(maxhold); 67215207Sgnn struct sockaddr_in dest; 68215207Sgnn char message[MSG_SIZE]; 69215207Sgnn struct arpstat arpstat; 70215207Sgnn size_t len = sizeof(arpstat); 71215207Sgnn unsigned long dropped = 0; 72215207Sgnn 73215207Sgnn memset(&message, 1, sizeof(message)); 74215207Sgnn 75215207Sgnn if (sysctlbyname("net.link.ether.inet.maxhold", &maxhold, &size, 76215207Sgnn NULL, 0) < 0) { 77215207Sgnn perror("not ok 1 - sysctlbyname failed"); 78215207Sgnn exit(1); 79215207Sgnn } 80215207Sgnn 81215207Sgnn#ifdef DEBUG 82215207Sgnn printf("maxhold is %d\n", maxhold); 83215207Sgnn#endif /* DEBUG */ 84215207Sgnn 85215207Sgnn if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { 86215207Sgnn perror("not ok 1 - could not open socket"); 87215207Sgnn exit(1); 88215207Sgnn } 89215207Sgnn 90215207Sgnn bzero(&dest, sizeof(dest)); 91215207Sgnn if (inet_pton(AF_INET, argv[1], &dest.sin_addr.s_addr) != 1) { 92215207Sgnn perror("not ok 1 - could not parse address"); 93215207Sgnn exit(1); 94215207Sgnn } 95215207Sgnn dest.sin_len = sizeof(dest); 96215207Sgnn dest.sin_family = AF_INET; 97215207Sgnn dest.sin_port = htons(PORT); 98215207Sgnn 99215207Sgnn if (sysctlbyname("net.link.ether.arp.stats", &arpstat, &len, 100215207Sgnn NULL, 0) < 0) { 101215207Sgnn perror("not ok 1 - could not get initial arp stats"); 102215207Sgnn exit(1); 103215207Sgnn } 104215207Sgnn 105215207Sgnn dropped = arpstat.dropped; 106215207Sgnn#ifdef DEBUG 107215207Sgnn printf("dropped before %ld\n", dropped); 108215207Sgnn#endif /* DEBUG */ 109215207Sgnn 110215207Sgnn /* 111215207Sgnn * Load up the queue in the ARP entry to the maximum. 112215207Sgnn * We should not drop any packets at this point. 113215207Sgnn */ 114215207Sgnn 115215207Sgnn while (maxhold > 0) { 116215207Sgnn if (sendto(sock, message, sizeof(message), 0, 117215207Sgnn (struct sockaddr *)&dest, sizeof(dest)) < 0) { 118215207Sgnn perror("not ok 1 - could not send packet"); 119215207Sgnn exit(1); 120215207Sgnn } 121215207Sgnn maxhold--; 122215207Sgnn } 123215207Sgnn 124215207Sgnn if (sysctlbyname("net.link.ether.arp.stats", &arpstat, &len, 125215207Sgnn NULL, 0) < 0) { 126215207Sgnn perror("not ok 1 - could not get new arp stats"); 127215207Sgnn exit(1); 128215207Sgnn } 129215207Sgnn 130215207Sgnn#ifdef DEBUG 131215207Sgnn printf("dropped after %ld\n", arpstat.dropped); 132215207Sgnn#endif /* DEBUG */ 133215207Sgnn 134215207Sgnn if (arpstat.dropped != dropped) { 135215207Sgnn printf("not ok 1 - Failed, drops changed:" 136215207Sgnn "before %ld after %ld\n", dropped, arpstat.dropped); 137215207Sgnn exit(1); 138215207Sgnn } 139215207Sgnn 140215207Sgnn dropped = arpstat.dropped; 141215207Sgnn 142215207Sgnn /* Now add one extra and make sure it is dropped. */ 143215207Sgnn if (sendto(sock, message, sizeof(message), 0, 144215207Sgnn (struct sockaddr *)&dest, sizeof(dest)) < 0) { 145215207Sgnn perror("not ok 1 - could not send packet"); 146215207Sgnn exit(1); 147215207Sgnn } 148215207Sgnn 149215207Sgnn if (sysctlbyname("net.link.ether.arp.stats", &arpstat, &len, 150215207Sgnn NULL, 0) < 0) { 151215207Sgnn perror("not ok 1 - could not get new arp stats"); 152215207Sgnn exit(1); 153215207Sgnn } 154215207Sgnn 155215207Sgnn if (arpstat.dropped != (dropped + 1)) { 156215207Sgnn printf("not ok 1 - Failed to drop one packet: before" 157215207Sgnn " %ld after %ld\n", dropped, arpstat.dropped); 158215207Sgnn exit(1); 159215207Sgnn } 160215207Sgnn 161215207Sgnn printf("ok\n"); 162215207Sgnn return (0); 163215207Sgnn} 164