in6_02.c revision 354ebb48db8e66a853a58379a4808d5dcd1ceac3
1/* 2 * 3 * Copyright (c) International Business Machines Corp., 2001 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 13 * the GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20/* 21 * Test Name: in6_02 22 * 23 * Test Description: 24 * Tests for name to index and index to name functions in IPv6 25 * 26 * Usage: <for command-line> 27 * in6_02 [-c n] [-e] [-i n] [-I x] [-P x] [-t] 28 * where, -c n : Run n copies concurrently. 29 * -e : Turn on errno logging. 30 * -i n : Execute test n times. 31 * -I x : Execute test for x seconds. 32 * -P x : Pause for x seconds between iterations. 33 * -t : Turn on syscall timing. 34 * 35 * HISTORY 36 * 05/2004 written by David L Stevens 37 * 38 * RESTRICTIONS: 39 * None. 40 * 41 */ 42 43#include <unistd.h> 44#include <errno.h> 45 46#include <sys/socket.h> 47 48#include <net/if.h> 49 50#include "test.h" 51#include "usctest.h" 52 53char *TCID = "in6_02"; /* Test program identifier. */ 54int testno; 55 56void setup(void), cleanup(void); 57 58struct { 59 char *name; 60 int nonzero; 61} n2i[] = { 62 { 63 "lo", 1}, { 64 "eth0", 1}, { 65 "hoser75", 0}, { 66"6", 0},}; 67 68#define N2I_COUNT (sizeof(n2i)/sizeof(n2i[0])) 69 70#define I2N_RNDCOUNT 10 /* random ints */ 71#define I2N_LOWCOUNT 10 /* sequential from 0 */ 72 73int TST_TOTAL = N2I_COUNT; 74 75void n2itest(void), i2ntest(void), initest(void); 76 77int main(int argc, char *argv[]) 78{ 79 int lc; 80 char *msg; 81 82 /* Parse standard options given to run the test. */ 83 msg = parse_opts(argc, argv, NULL, NULL); 84 if (msg != NULL) { 85 tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); 86 } 87 88 setup(); 89 90 for (lc = 0; TEST_LOOPING(lc); ++lc) { 91 n2itest(); 92 i2ntest(); 93 initest(); 94 } 95 cleanup(); 96 97 return (0); 98} 99 100/* if_nametoindex tests */ 101 102void n2itest() 103{ 104 int i; 105 106 for (i = 0; i < N2I_COUNT; ++i) { 107 char ifname[IF_NAMESIZE], *pifn; 108 int fail; 109 110 TEST(if_nametoindex(n2i[i].name)); 111 fail = !TEST_RETURN != !n2i[i].nonzero; 112 if (fail) { 113 tst_resm(TFAIL, "if_nametoindex(\"%s\") %ld " 114 "[should be %szero]", n2i[i].name, 115 TEST_RETURN, n2i[i].nonzero ? "non" : ""); 116 continue; 117 } 118 if (!TEST_RETURN) { 119 tst_resm(TPASS, "if_nametoindex(\"%s\") %ld", 120 n2i[i].name, TEST_RETURN); 121 continue; 122 } 123 124 pifn = if_indextoname(TEST_RETURN, ifname); 125 if (!pifn || strcmp(n2i[i].name, pifn)) { 126 tst_resm(TFAIL, "if_nametoindex(\"%s\") %ld doesn't " 127 "match if_indextoname(%ld) \"%s\"", 128 n2i[i].name, TEST_RETURN, TEST_RETURN, 129 pifn ? pifn : ""); 130 continue; 131 } 132 tst_resm(TPASS, "if_nametoindex(\"%s\") %ld", n2i[i].name, 133 TEST_RETURN); 134 } 135} 136 137int i2ntest1(unsigned int if_index) 138{ 139 char ifname[IF_NAMESIZE]; 140 unsigned int idx; 141 142 TEST((ifname == if_indextoname(if_index, ifname))); 143 if (!TEST_RETURN) { 144 if (TEST_ERRNO != ENXIO) { 145 tst_resm(TFAIL, "if_indextoname(%d) returns %ld " 146 "but errno %d != ENXIO", if_index, TEST_RETURN, 147 TEST_ERRNO); 148 return 0; 149 } 150 tst_resm(TPASS, "if_indextoname(%d) returns NULL", if_index); 151 return 1; 152 } 153 /* else, a valid interface-- double check name */ 154 idx = if_nametoindex(ifname); 155 if (idx != if_index) { 156 tst_resm(TFAIL, "if_indextoname(%u) returns \"%s\" but " 157 "doesn't if_nametoindex(\"%s\") returns %u", 158 if_index, ifname, ifname, idx); 159 return 0; 160 } 161 tst_resm(TPASS, "if_indextoname(%d) returns \"%s\"", if_index, ifname); 162 return 1; 163} 164 165void i2ntest(void) 166{ 167 unsigned int i; 168 169 /* some low-numbered indexes-- likely to get valid interfaces here */ 170 for (i = 0; i < I2N_LOWCOUNT; ++i) 171 if (!i2ntest1(i)) 172 return; /* skip the rest, if broken */ 173 /* some random ints; should mostly fail */ 174 for (i = 0; i < I2N_RNDCOUNT; ++i) 175 if (!i2ntest1(rand())) 176 return; /* skip the rest, if broken */ 177} 178 179/* 180 * This is an ugly, linux-only solution. getrusage() doesn't support the 181 * current data segment size, so we get it out of /proc 182 */ 183static int getdatasize(void) 184{ 185 char line[128], *p; 186 int dsize = -1; 187 FILE *fp; 188 189 fp = fopen("/proc/self/status", "r"); 190 if (fp == NULL) 191 return -1; 192 while (fgets(line, sizeof(line), fp)) { 193 if (strncmp(line, "VmData:", 7) == 0) { 194 dsize = strtol(line + 7, &p, 0); 195 ++p; /* skip space */ 196 if (!strcmp(p, "kB")) 197 return -1; /* don't know units */ 198 dsize *= 1024; 199 break; 200 } 201 } 202 fclose(fp); 203 return dsize; 204} 205 206void initest(void) 207{ 208 int freenicount; 209 struct if_nameindex *pini; 210 int i, dsize_before, dsize_after; 211 212 pini = if_nameindex(); 213 if (pini == 0) { 214 tst_resm(TFAIL, "if_nameindex() returns NULL, errno %d (%s)", 215 TEST_ERRNO, strerror(TEST_ERRNO)); 216 return; 217 } 218 for (i = 0; pini[i].if_index; ++i) { 219 char buf[IF_NAMESIZE], *p; 220 int idx; 221 222 p = if_indextoname(pini[i].if_index, buf); 223 if (!p || strcmp(p, pini[i].if_name)) { 224 tst_resm(TFAIL, "if_nameindex idx %d name \"%s\" but " 225 "if_indextoname(%d) is \"%s\"", 226 pini[i].if_index, pini[i].if_name, 227 pini[i].if_index, p ? p : ""); 228 continue; 229 } 230 idx = if_nametoindex(pini[i].if_name); 231 if (idx != pini[i].if_index) { 232 tst_resm(TFAIL, "if_nameindex idx %d name \"%s\" but " 233 "if_indextoname(\"%s\") is %d", 234 pini[i].if_index, pini[i].if_name, 235 pini[i].if_name, idx); 236 continue; 237 } 238 tst_resm(TPASS, "if_nameindex idx %d name \"%s\"", 239 pini[i].if_index, pini[i].if_name); 240 } 241 if_freenameindex(pini); 242 243 /* if_freenameindex() has no error conditions; see if we run 244 * out of memory if we do it a lot. 245 */ 246 dsize_before = getdatasize(); 247 if (dsize_before < 0) { 248 tst_resm(TBROK, "getdatasize failed: errno %d (%s)", errno, 249 strerror(errno)); 250 return; 251 } 252 /* we need to leak at least a page to detect a leak; 1 byte per call 253 * will be detected with getpagesize() calls. 254 */ 255 freenicount = getpagesize(); 256 for (i = 0; i < freenicount; ++i) { 257 pini = if_nameindex(); 258 if (!pini) { 259 tst_resm(TFAIL, "if_freenameindex test failed " 260 "if_nameindex() iteration %d", i); 261 break; 262 } 263 if_freenameindex(pini); 264 } 265 dsize_after = getdatasize(); 266 if (dsize_after < 0) { 267 tst_resm(TBROK, "getdatasize failed: errno %d (%s)", errno, 268 strerror(errno)); 269 return; 270 } 271 if (dsize_after > dsize_before + getpagesize()) 272 tst_resm(TFAIL, "if_freenameindex leaking memory " 273 "(%d iterations) dsize before %d dsize after %d", i, 274 dsize_before, dsize_after); 275 else 276 tst_resm(TPASS, "if_freenameindex passed %d iterations", i); 277} 278 279void setup(void) 280{ 281 TEST_PAUSE; /* if -P option specified */ 282} 283 284void cleanup(void) 285{ 286 TEST_CLEANUP; 287 288} 289