xref: /mOS-networking-stack/util/rss.c (revision 76404edc)
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdint.h>
4 //#include <sys/socket.h>
5 #include <netinet/in.h>
6 #include <arpa/inet.h>
7 #include <stdlib.h>
8 #include <unistd.h>
9 
10 //static int num_queue = 4;
11 
12 /*-------------------------------------------------------------*/
13 static void
BuildKeyCache(uint32_t * cache,int cache_len)14 BuildKeyCache(uint32_t *cache, int cache_len)
15 {
16 #define NBBY 8 /* number of bits per byte */
17 
18 	// 16bit test set
19 /*
20 	static const uint8_t key[] = {
21 		 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
22 		 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
23 		 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
24 		 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
25 		 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00
26 	};
27 */
28     /*
29 	static const uint8_t key[] = {
30 		 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a,
31 		 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a,
32 		 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a,
33 		 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a,
34 		 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a
35 	};
36         */
37 
38 	/*
39 	static const uint8_t key[] = {
40 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
41 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
42 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
43 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
44 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
45 	};
46 	*/
47 
48 	// 32bit test set
49 	/*
50 	static const uint8_t key[] = {
51 		 0x6d, 0x5a, 0x56, 0x25, 0x6d, 0x5a, 0x56, 0x25,
52 		 0x6d, 0x5a, 0x56, 0x25, 0x6d, 0x5a, 0x56, 0x25,
53 		 0x6d, 0x5a, 0x56, 0x25, 0x6d, 0x5a, 0x56, 0x25,
54 		 0x6d, 0x5a, 0x56, 0x25, 0x6d, 0x5a, 0x56, 0x25,
55 		 0x6d, 0x5a, 0x56, 0x25, 0x6d, 0x5a, 0x56, 0x25
56 	};
57 	*/
58 	/* ixgbe driver had a different set of keys than that of Microsoft
59 	   RSS keys */
60 /*	static const uint8_t key[] = {
61 		0x3D, 0xD7, 0x91, 0xE2,
62 		0x6C, 0xEC, 0x05, 0x18,
63 		0x0D, 0xB3, 0x94, 0x2A,
64 		0xEC, 0x2B, 0x4F, 0xA5,
65 		0x7C, 0xAF, 0x49, 0xEA,
66 		0x3D, 0xAD, 0x14, 0xE2,
67 		0xBE, 0xAA, 0x55, 0xB8,
68 		0xEA, 0x67, 0x3E, 0x6A,
69 		0x17, 0x4D, 0x36, 0x14,
70 		0x0D, 0x20, 0xED, 0x3B};
71 */
72 
73 #if 0
74 	/* Microsoft RSS keys */
75 	static const uint8_t key[] = {
76 		 0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
77 		 0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
78 		 0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
79 		 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
80 		 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
81 	};
82 #endif
83         /* Keys for system testing */
84 	static const uint8_t key[] = {
85 		 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
86 		 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
87 		 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
88 		 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
89 		 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05
90 	};
91 
92 	uint32_t result = (((uint32_t)key[0]) << 24) | (((uint32_t)key[1]) << 16) | 		              (((uint32_t)key[2]) << 8)  | ((uint32_t)key[3]);
93 	uint32_t idx = 32;
94 	int i;
95 
96 	for (i = 0; i < cache_len; i++, idx++) {
97 		uint8_t shift = (idx % NBBY);
98 		uint32_t bit;
99 
100 		cache[i] = result;
101 		bit = ((key[idx/NBBY] << shift) & 0x80) ? 1 : 0;
102 		result = ((result << 1) | bit);
103 	}
104 
105 }
106 /*-------------------------------------------------------------*/
107 static uint32_t
GetRSSHash(in_addr_t sip,in_addr_t dip,in_port_t sp,in_port_t dp)108 GetRSSHash(in_addr_t sip, in_addr_t dip, in_port_t sp, in_port_t dp)
109 {
110 #define MSB32 0x80000000
111 #define MSB16 0x8000
112 #define KEY_CACHE_LEN 96
113 
114 	uint32_t res = 0;
115 	int i;
116 	static int first = 1;
117 	static uint32_t key_cache[KEY_CACHE_LEN] = {0};
118 
119 	if (first) {
120 		BuildKeyCache(key_cache, KEY_CACHE_LEN);
121 		first = 0;
122 	}
123 
124 	for (i = 0; i < 32; i++) {
125 		if (sip & MSB32)
126 			res ^= key_cache[i];
127 		sip <<= 1;
128 	}
129 	for (i = 0; i < 32; i++) {
130 		if (dip & MSB32)
131 			res ^= key_cache[32+i];
132 		dip <<= 1;
133 	}
134 	for (i = 0; i < 16; i++) {
135 		if (sp & MSB16)
136 			res ^= key_cache[64+i];
137 		sp <<= 1;
138 	}
139 	for (i = 0; i < 16; i++) {
140 		if (dp & MSB16)
141 			res ^= key_cache[80+i];
142 		dp <<= 1;
143 	}
144 	return res;
145 }
146 /*-------------------------------------------------------------------*/
147 /* RSS redirection table is in the little endian byte order (intel)  */
148 /*                                                                   */
149 /* idx: 0 1 2 3 | 4 5 6 7 | 8 9 10 11 | 12 13 14 15 | 16 17 18 19 ...*/
150 /* val: 3 2 1 0 | 7 6 5 4 | 11 10 9 8 | 15 14 13 12 | 19 18 17 16 ...*/
151 /* qid = val % num_queues */
152 /*-------------------------------------------------------------------*/
153 #if 0
154 int
155 GetRSSCPUCore(in_addr_t sip, in_addr_t dip,
156 			  in_port_t sp, in_port_t dp, int num_queues)
157 {
158 	#define RSS_BIT_MASK 0x0000007F
159 
160 	uint32_t masked = GetRSSHash(sip, dip, sp, dp) & RSS_BIT_MASK;
161 
162 #ifndef ENABLE_DPDK
163 	static const uint32_t off[4] = {3, 1, -1, -3};
164 	masked += off[masked & 0x3];
165 #endif
166 	return (masked % num_queues);
167 
168 }
169 #endif
170 #if _TEST_RSS_
171 /*-------------------------------------------------------------*/
172 static void
VerifyRSSHash(void)173 VerifyRSSHash(void)
174 {
175 	 in_addr_t faddr, laddr;
176 	 in_port_t fport, lport;
177 	 char *src[]  = {"66.9.149.187",
178 					 "199.92.111.2",
179 					 "24.19.198.95",
180 					 "38.27.205.30",
181 					 "153.39.163.191"};
182 	 char *dest[] = {"161.142.100.80",
183 					 "65.69.140.83",
184 					 "12.22.207.184",
185 					 "209.142.163.6",
186 					 "202.188.127.2"};
187 	 in_port_t src_port[]  = {2794, 14230, 12898, 48228, 44251};
188 	 in_port_t dest_port[] = {1766, 4739, 38024, 2217, 1303};
189 	 uint32_t correct_hash[] = {0x51ccc178,
190 				    0xc626b0ea,
191 				    0x5c2b394a,
192 				    0xafc7327f,
193 				    0x10e828a2};
194 	 int i;
195 
196 	 /*
197 	  * RSS hash calculation verification example is from
198 	  * http://msdn.microsoft.com/en-us/library/ff571021%28v=vs.85%29.aspx
199 	  */
200 
201 	 for (i = 0; i < 5; i++) {
202 		 struct in_addr addr;
203 
204 		 if (inet_aton(src[i], &addr) == 0) {
205 			 fprintf(stderr, "inet_aton error\n");
206 			 exit(-1);
207 		 }
208 		 faddr = ntohl(addr.s_addr);
209 
210 		 if (inet_aton(dest[i], &addr) == 0) {
211 			 fprintf(stderr, "inet_aton error\n");
212 			 exit(-1);
213 		 }
214 		 laddr = ntohl(addr.s_addr);
215 
216 		 fport = src_port[i];
217 		 lport = dest_port[i];
218 
219 		 printf("(%15s %15s %5d %5d)  0x%08x, correct_hash: 0x%08x\n",
220 				src[i], dest[i], src_port[i], dest_port[i],
221 				GetRSSHash(faddr, laddr, fport, lport), correct_hash[i]);
222 	 }
223 }
224 
225 static unsigned long next = 2192123;
myrand(void)226 unsigned int myrand(void){
227 	next = next * 1103515245 + 12345;
228 	return next/65536;
229 }
230 
231 static void
CheckRSSHash(int cnt,const char * src_ip,const char * dest_ip,int32_t src_port,int32_t dest_port)232 CheckRSSHash(int cnt, const char* src_ip, const char* dest_ip, int32_t src_port, int32_t dest_port)
233 {
234 
235 	 struct in_addr saddr, daddr;
236 	 char saddr_str[15], daddr_str[15];
237 	 in_port_t sport, dport;
238 	 long queue_cnt[num_queue];
239 	 int queue_idx;
240 
241 
242 	 int i;
243 	 for( i = 0; i < num_queue; i++)
244 	 {
245 		 queue_cnt[i] = 0;
246 	 }
247 
248 	 printf("src\tdest\tqueue_idx\n");
249 
250 	 for( i =0; i < cnt; i++){
251 		// Only generate src/dest address when no address specified
252                 if (src_ip == NULL) {
253                     saddr.s_addr = (in_addr_t) myrand();
254                 } else {
255                     if (inet_aton(src_ip, &saddr) == 0) saddr.s_addr = (in_addr_t) myrand();
256                 }
257                 if (dest_ip == NULL) {
258                     daddr.s_addr = (in_addr_t) myrand();
259                 } else {
260                     if (inet_aton(dest_ip, &daddr) == 0) daddr.s_addr = (in_addr_t) myrand();
261                 }
262 
263 		int32_t ports = (int32_t) myrand();
264                 if (src_port > 0) {
265                     sport = htons(src_port);
266                 } else {
267                     sport = ports;
268                 }
269                 if (dest_port > 0) {
270                     dport = htons(dest_port);
271                 } else {
272                     dport = ports >> 16;
273                 }
274 
275 		//get rss hash
276 		queue_idx = GetRSSCPUCore(saddr.s_addr, daddr.s_addr, sport, dport, num_queue);
277 		//create logs
278 		strncpy(saddr_str, inet_ntoa(saddr), 15);
279 		strncpy(daddr_str, inet_ntoa(daddr), 15);
280 		printf("%15s:%5d\t%15s:%5d\t%d\n", saddr_str, ntohs(sport), daddr_str, ntohs(dport), queue_idx);
281 
282 		queue_idx = GetRSSCPUCore(daddr.s_addr, saddr.s_addr, dport, sport, num_queue);
283 		printf("%15s:%5d\t%15s:%5d\t%d\n", daddr_str, ntohs(dport), saddr_str, ntohs(sport), queue_idx);
284 
285 		queue_cnt[queue_idx]++;
286 	 }
287 
288 	 printf("\n-----summary-----\n");
289 	 for( i = 0; i < num_queue; i++)
290 	 {
291 		 printf("%ld\n", queue_cnt[i]);
292 	 }
293 	 printf("\n");
294 
295 }
296 
297 void
print_usage(int argc,char ** argv)298 print_usage(int argc, char** argv){
299 	printf("Usage: %s -c number_of_test_ip [options]\n", argv[0]);
300         printf("Options:\n");
301         printf(" -r seed(long) : Specifiy random seed\n");
302         printf(" -s srcIP : Source IP address\n");
303         printf(" -S srcPort : Source port number\n");
304         printf(" -d destIP : Destination IP address\n");
305         printf(" -D destPort : Destination port number\n");
306         printf("Any of source/destination IP/port could be omitted.\n");
307         printf("If absent, random generated address is used.\n");
308 }
309 
310 /*-------------------------------------------------------------*/
311 int
main(int argc,char ** argv)312 main(int argc, char** argv)
313 {
314         int opt;
315         int cnt = -1;
316         long seed = -1;
317         int32_t sport = -1, dport = -1;
318         char *srcIP = 0, *destIP = 0;
319         while ((opt=getopt(argc, argv, "c:r:sS:dD:")) != -1) {
320             switch (opt) {
321                 case 'c':
322                     cnt = atoi(optarg);
323                     break;
324                 case 'r':
325                     seed = atol(optarg);
326                     break;
327                 case 's':
328                     srcIP = strdup(argv[optind]);
329                     break;
330                 case 'S':
331                     sport = atoi(optarg);
332                     break;
333                 case 'd':
334                     destIP = strdup(argv[optind]);
335                     break;
336                 case 'D':
337                     dport = atoi(optarg);
338                     break;
339             }
340         }
341 
342         if (cnt < 1) {
343 		print_usage(argc, argv);
344 		exit(0);
345 	}
346         if (seed > 0) next = seed;
347 
348         // Test configuration:
349         // 10.10.4.11:X (rock5) -> 10.10.2.10:80 (rock4)
350 	CheckRSSHash(cnt, srcIP, destIP, sport, dport);
351 
352         if (srcIP) free(srcIP);
353         if (destIP) free(destIP);
354 	return 0;
355 }
356 #endif
357