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