npf_nbuf_test.c revision 1.1 1 /* $NetBSD: npf_nbuf_test.c,v 1.1 2012/04/14 21:57:29 rmind Exp $ */
2
3 /*
4 * NPF nbuf interface test.
5 *
6 * Public Domain.
7 */
8
9 #include <sys/types.h>
10 #include <sys/kmem.h>
11
12 #include "npf_impl.h"
13 #include "npf_test.h"
14
15 #define MBUF_CHAIN_LEN 128
16
17 CTASSERT((MBUF_CHAIN_LEN % sizeof(uint32_t)) == 0);
18
19 static char *
20 parse_nbuf_chain(void *nbuf, void *n_ptr)
21 {
22 char *s = kmem_zalloc(MBUF_CHAIN_LEN + 1, KM_SLEEP);
23 int n, error;
24
25 for (n = 0; ; ) {
26 char d[4 + 1];
27
28 error = nbuf_fetch_datum(nbuf, n_ptr, sizeof(uint32_t), d);
29 if (error) {
30 return NULL;
31 }
32 d[sizeof(d) - 1] = '\0';
33 strcat(s, d);
34
35 if (n + sizeof(uint32_t) == MBUF_CHAIN_LEN) {
36 assert(nbuf_advance(&nbuf, n_ptr,
37 sizeof(uint32_t) - 1));
38 break;
39 }
40 n_ptr = nbuf_advance(&nbuf, n_ptr, sizeof(uint32_t));
41 if (n_ptr == NULL) {
42 return NULL;
43 }
44 n += sizeof(uint32_t);
45 }
46 return s;
47 }
48
49 static char *
50 mbuf_getstring(struct mbuf *m)
51 {
52 char *s = kmem_zalloc(MBUF_CHAIN_LEN + 1, KM_SLEEP);
53 u_int tlen = 0;
54
55 while (m) {
56 int len = m->m_len;
57 char *d = m->m_data;
58 while (len--) {
59 s[tlen++] = *d++;
60 }
61 m = m->m_next;
62 }
63 return s;
64 }
65
66 static struct mbuf *
67 mbuf_alloc_with_off(size_t off, int len)
68 {
69 struct mbuf *m;
70
71 m = kmem_zalloc(sizeof(struct mbuf) + off + len, KM_SLEEP);
72 m->m_data = (char *)m + sizeof(struct mbuf) + off;
73 m->m_len = len;
74 return m;
75 }
76
77 /*
78 * Create an mbuf chain, each of 1 byte size.
79 */
80 static struct mbuf *
81 mbuf_bytesize(size_t clen)
82 {
83 struct mbuf *m0 = NULL, *m = NULL;
84 u_int i, n;
85
86 /* Chain of clen (e.g. 128) mbufs, each storing 1 byte of data. */
87 for (i = 0, n = 0; i < clen; i++) {
88 /* Range of offset: 0 .. 15. */
89 m0 = mbuf_alloc_with_off(n & 0xf, 1);
90
91 /* Fill data with letters from 'a' to 'z'. */
92 memset(m0->m_data, 'a' + n, 1);
93 n = ('a' + n) != 'z' ? n + 1 : 0;
94
95 /* Next mbuf.. */
96 m0->m_next = m;
97 m = m0;
98 }
99 return m0;
100 }
101
102 /*
103 * Generate random amount of mbufs, with random offsets and lengths.
104 */
105 static struct mbuf *
106 mbuf_random_len(size_t chain_len)
107 {
108 struct mbuf *m0 = NULL, *m = NULL;
109 u_int tlen = 0, n = 0;
110
111 while (tlen < chain_len) {
112 u_int off, len;
113 char *d;
114
115 /* Random offset and length range: 1 .. 16. */
116 off = (random() % 16) + 1;
117 len = (random() % 16) + 1;
118
119 /* Do not exceed 128 bytes of total length. */
120 if (tlen + len > chain_len) {
121 len = chain_len - tlen;
122 }
123 tlen += len;
124
125 /* Consistently fill data with letters from 'a' to 'z'. */
126 m0 = mbuf_alloc_with_off(off, len);
127 d = m0->m_data;
128 while (len--) {
129 *d++ = ('a' + n);
130 n = ('a' + n) != 'z' ? n + 1 : 0;
131 }
132
133 /* Next mbuf.. */
134 m0->m_next = m;
135 m = m0;
136 }
137 assert(tlen == chain_len);
138 return m0;
139 }
140
141 static bool
142 validate_mbuf_data(struct mbuf *m, bool verbose, char *bufa, char *bufb)
143 {
144 bool ret = (strcmp(bufa, bufb) == 0);
145
146 if (verbose) {
147 printf("Buffer A: %s\nBuffer B: %s\n", bufa, bufb);
148 }
149 /* XXX free m */
150 kmem_free(bufa, MBUF_CHAIN_LEN + 1);
151 kmem_free(bufb, MBUF_CHAIN_LEN + 1);
152 return ret;
153 }
154
155 bool
156 npf_nbuf_test(bool verbose)
157 {
158 struct mbuf *m1, *m2;
159 char *bufa, *bufb;
160
161 m1 = mbuf_random_len(MBUF_CHAIN_LEN);
162 bufa = mbuf_getstring(m1);
163 bufb = parse_nbuf_chain(m1, m1->m_data);
164 if (!validate_mbuf_data(m1, verbose, bufa, bufb)) {
165 return false;
166 }
167
168 m2 = mbuf_bytesize(MBUF_CHAIN_LEN);
169 bufa = mbuf_getstring(m2);
170 bufb = parse_nbuf_chain(m2, m2->m_data);
171 if (!validate_mbuf_data(m2, verbose, bufa, bufb)) {
172 return false;
173 }
174
175 return true;
176 }
177