1 /* $NetBSD: npf_nbuf_test.c,v 1.5 2013/11/08 00:38:27 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 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(&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 return s; 71 } 72 73 static char * 74 mbuf_getstring(struct mbuf *m) 75 { 76 char *s = kmem_zalloc(MBUF_CHAIN_LEN + 1, KM_SLEEP); 77 u_int tlen = 0; 78 79 while (m) { 80 int len = m->m_len; 81 char *d = m->m_data; 82 while (len--) { 83 s[tlen++] = *d++; 84 } 85 m = m->m_next; 86 } 87 return s; 88 } 89 90 static struct mbuf * 91 mbuf_alloc_with_off(size_t off, int len) 92 { 93 struct mbuf *m; 94 95 KASSERT(off + len < MLEN); 96 m = m_get(M_WAITOK, MT_DATA); 97 m->m_data = (char *)m->m_data + off; 98 m->m_len = len; 99 return m; 100 } 101 102 /* 103 * Create an mbuf chain, each of 1 byte size. 104 */ 105 static struct mbuf * 106 mbuf_bytesize(size_t clen) 107 { 108 struct mbuf *m0 = NULL, *m = NULL; 109 u_int i, n; 110 111 /* Chain of clen (e.g. 128) mbufs, each storing 1 byte of data. */ 112 for (i = 0, n = 0; i < clen; i++) { 113 /* Range of offset: 0 .. 15. */ 114 m0 = mbuf_alloc_with_off(n & 0xf, 1); 115 116 /* Fill data with letters from 'a' to 'z'. */ 117 memset(m0->m_data, 'a' + n, 1); 118 n = ('a' + n) < 'z' ? n + 1 : 0; 119 120 /* Next mbuf.. */ 121 m0->m_next = m; 122 m = m0; 123 } 124 125 m0 = m_gethdr(M_WAITOK, MT_HEADER); 126 m0->m_pkthdr.len = clen; 127 m0->m_len = 0; 128 m0->m_next = m; 129 return m0; 130 } 131 132 /* 133 * Generate random amount of mbufs, with random offsets and lengths. 134 */ 135 static struct mbuf * 136 mbuf_random_len(size_t chain_len) 137 { 138 struct mbuf *m0 = NULL, *m = NULL; 139 u_int tlen = 0, n = 0; 140 141 while (tlen < chain_len) { 142 u_int off, len; 143 char *d; 144 145 /* Random offset and length range: 1 .. 16. */ 146 off = (random() % 16) + 1; 147 len = (random() % 16) + 1; 148 149 /* Do not exceed 128 bytes of total length. */ 150 if (tlen + len > chain_len) { 151 len = chain_len - tlen; 152 } 153 tlen += len; 154 155 /* Consistently fill data with letters from 'a' to 'z'. */ 156 m0 = mbuf_alloc_with_off(off, len); 157 d = m0->m_data; 158 while (len--) { 159 *d++ = ('a' + n); 160 n = ('a' + n) < 'z' ? n + 1 : 0; 161 } 162 163 /* Next mbuf.. */ 164 m0->m_next = m; 165 m = m0; 166 } 167 KASSERT(tlen == chain_len); 168 169 m0 = m_gethdr(M_WAITOK, MT_HEADER); 170 m0->m_pkthdr.len = tlen; 171 m0->m_next = m; 172 m0->m_len = 0; 173 return m0; 174 } 175 176 static bool 177 validate_mbuf_data(bool verbose, char *bufa, char *bufb) 178 { 179 bool ret = (strcmp(bufa, bufb) == 0); 180 181 if (verbose) { 182 printf("Buffer A: %s\nBuffer B: %s\n", bufa, bufb); 183 } 184 kmem_free(bufa, MBUF_CHAIN_LEN + 1); 185 kmem_free(bufb, MBUF_CHAIN_LEN + 1); 186 return ret; 187 } 188 189 bool 190 npf_nbuf_test(bool verbose) 191 { 192 struct mbuf *m1, *m2; 193 char *bufa, *bufb; 194 bool fail = false; 195 196 m1 = mbuf_random_len(MBUF_CHAIN_LEN); 197 bufa = mbuf_getstring(m1); 198 bufb = parse_nbuf_chain(m1); 199 fail |= !validate_mbuf_data(verbose, bufa, bufb); 200 201 m2 = mbuf_bytesize(MBUF_CHAIN_LEN); 202 bufa = mbuf_getstring(m2); 203 bufb = parse_nbuf_chain(m2); 204 fail |= !validate_mbuf_data(verbose, bufa, bufb); 205 206 return !fail; 207 } 208