1 /* 2 * NPF nbuf interface tests. 3 * 4 * Public Domain. 5 */ 6 7 #ifdef _KERNEL 8 #include <sys/types.h> 9 #include <sys/kmem.h> 10 #endif 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 void 20 mbuf_consistency_check(nbuf_t *nbuf) 21 { 22 struct mbuf *m = nbuf_head_mbuf(nbuf); 23 24 while (m) { 25 assert(m->m_type != MT_FREE); 26 m = m->m_next; 27 } 28 } 29 30 static char * 31 parse_nbuf_chain(struct mbuf *m) 32 { 33 ifnet_t *dummy_ifp = npf_test_addif(IFNAME_TEST, false, false); 34 char *s = kmem_zalloc(MBUF_CHAIN_LEN + 1, KM_SLEEP); 35 nbuf_t nbuf; 36 void *nptr; 37 int n; 38 39 nbuf_init(npf_getkernctx(), &nbuf, m, dummy_ifp); 40 41 nptr = nbuf_advance(&nbuf, (random() % 16) + 1, (random() % 16) + 1); 42 mbuf_consistency_check(&nbuf); 43 assert(nptr != NULL); 44 nbuf_reset(&nbuf); 45 46 for (n = 0; ; ) { 47 char d[4 + 1]; 48 49 nptr = nbuf_ensure_contig(&nbuf, sizeof(uint32_t)); 50 if (nptr == NULL) { 51 break; 52 } 53 mbuf_consistency_check(&nbuf); 54 memcpy(&d, nptr, sizeof(uint32_t)); 55 56 d[sizeof(d) - 1] = '\0'; 57 strcat(s, d); 58 59 if (n + sizeof(uint32_t) == MBUF_CHAIN_LEN) { 60 assert(nbuf_advance(&nbuf, sizeof(uint32_t) - 1, 0)); 61 assert(!nbuf_advance(&nbuf, 1, 0)); 62 break; 63 } 64 if (!nbuf_advance(&nbuf, sizeof(uint32_t), 0)) { 65 break; 66 } 67 n += sizeof(uint32_t); 68 } 69 mbuf_consistency_check(&nbuf); 70 m_freem(nbuf_head_mbuf(&nbuf)); 71 return s; 72 } 73 74 static char * 75 mbuf_getstring(struct mbuf *m) 76 { 77 char *s = kmem_zalloc(MBUF_CHAIN_LEN + 1, KM_SLEEP); 78 unsigned tlen = 0; 79 80 while (m) { 81 int len = m->m_len; 82 char *d = m->m_data; 83 while (len--) { 84 s[tlen++] = *d++; 85 } 86 m = m->m_next; 87 } 88 return s; 89 } 90 91 static struct mbuf * 92 mbuf_alloc_with_off(size_t off, int len) 93 { 94 struct mbuf *m; 95 96 KASSERT(off + len < MLEN); 97 m = m_get(M_WAITOK, MT_DATA); 98 m->m_data = (char *)m->m_data + off; 99 m->m_len = len; 100 return m; 101 } 102 103 /* 104 * Create an mbuf chain, each of 1 byte size. 105 */ 106 static struct mbuf * 107 mbuf_bytesize(size_t clen) 108 { 109 struct mbuf *m0 = NULL, *m = NULL; 110 unsigned i, n; 111 112 /* Chain of clen (e.g. 128) mbufs, each storing 1 byte of data. */ 113 for (i = 0, n = 0; i < clen; i++) { 114 /* Range of offset: 0 .. 15. */ 115 m0 = mbuf_alloc_with_off(n & 0xf, 1); 116 117 /* Fill data with letters from 'a' to 'z'. */ 118 memset(m0->m_data, 'a' + n, 1); 119 n = ('a' + n) < 'z' ? n + 1 : 0; 120 121 /* Next mbuf.. */ 122 m0->m_next = m; 123 m = m0; 124 } 125 126 m0 = m_gethdr(M_WAITOK, MT_HEADER); 127 m0->m_pkthdr.len = clen; 128 m0->m_len = 0; 129 m0->m_next = m; 130 return m0; 131 } 132 133 /* 134 * Generate random number of mbufs, with random offsets and lengths. 135 */ 136 static struct mbuf * 137 mbuf_random_len(size_t chain_len) 138 { 139 struct mbuf *m0 = NULL, *m = NULL; 140 unsigned tlen = 0, n = 0; 141 142 while (tlen < chain_len) { 143 unsigned off, len; 144 char *d; 145 146 /* Random offset and length range: 1 .. 16. */ 147 off = (random() % 16) + 1; 148 len = (random() % 16) + 1; 149 150 /* Do not exceed 128 bytes of total length. */ 151 if (tlen + len > chain_len) { 152 len = chain_len - tlen; 153 } 154 tlen += len; 155 156 /* Consistently fill data with letters from 'a' to 'z'. */ 157 m0 = mbuf_alloc_with_off(off, len); 158 d = m0->m_data; 159 while (len--) { 160 *d++ = ('a' + n); 161 n = ('a' + n) < 'z' ? n + 1 : 0; 162 } 163 164 /* Next mbuf.. */ 165 m0->m_next = m; 166 m = m0; 167 } 168 KASSERT(tlen == chain_len); 169 170 m0 = m_gethdr(M_WAITOK, MT_HEADER); 171 m0->m_pkthdr.len = tlen; 172 m0->m_next = m; 173 m0->m_len = 0; 174 return m0; 175 } 176 177 static bool 178 validate_mbuf_data(char *bufa, char *bufb) 179 { 180 bool ok = strcmp(bufa, bufb) == 0; 181 182 if (!ok) { 183 printf("Buffer A: %s\nBuffer B: %s\n", bufa, bufb); 184 } 185 kmem_free(bufa, MBUF_CHAIN_LEN + 1); 186 kmem_free(bufb, MBUF_CHAIN_LEN + 1); 187 return ok; 188 } 189 190 bool 191 npf_nbuf_test(bool verbose) 192 { 193 struct mbuf *m; 194 char *bufa, *bufb; 195 unsigned n = 10000; 196 bool ok; 197 198 while (n--) { 199 m = mbuf_random_len(MBUF_CHAIN_LEN); 200 bufa = mbuf_getstring(m); 201 bufb = parse_nbuf_chain(m); 202 ok = validate_mbuf_data(bufa, bufb); 203 CHECK_TRUE(ok); 204 } 205 206 m = mbuf_bytesize(MBUF_CHAIN_LEN); 207 bufa = mbuf_getstring(m); 208 bufb = parse_nbuf_chain(m); 209 ok = validate_mbuf_data(bufa, bufb); 210 CHECK_TRUE(ok); 211 212 (void)verbose; 213 return true; 214 } 215