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