1 /*
2  * test/test-complex-HTB-with-hash-filters.c     Add HTB qdisc, HTB classes and creates some hash filters
3  *
4  *      This library is free software; you can redistribute it and/or
5  *      modify it under the terms of the GNU Lesser General Public
6  *      License as published by the Free Software Foundation version 2.1
7  *      of the License.
8  *
9  * Copyright (c) 2011 Adrian Ban <adrian.ban@mantech.ro>
10  */
11 
12 #include <netlink/route/link.h>
13 #include <netlink/route/tc.h>
14 #include <netlink/route/qdisc.h>
15 #include <netlink/route/qdisc/htb.h>
16 #include <netlink/route/qdisc/sfq.h>
17 #include <netlink/route/cls/u32.h>
18 #include <netlink/route/classifier.h>
19 #include <netlink/route/class.h>
20 #include <linux/if_ether.h>
21 
22 #include <netlink/attr.h>
23 //#include "include/rtnl_u32.h"
24 
25 #include <stdio.h>
26 #include <string.h>
27 //#include "include/rtnl_u32_addon.h"
28 
29 #define 	TC_HANDLE(maj, min)   (TC_H_MAJ((maj) << 16) | TC_H_MIN(min))
30 
31 /* some functions are copied from iproute-tc tool */
get_u32(__u32 * val,const char * arg,int base)32 int get_u32(__u32 *val, const char *arg, int base)
33 {
34 	unsigned long res;
35 	char *ptr;
36 
37 	if (!arg || !*arg)
38 		return -1;
39 	res = strtoul(arg, &ptr, base);
40 	if (!ptr || ptr == arg || *ptr || res > 0xFFFFFFFFUL)
41 		return -1;
42 	*val = res;
43 	return 0;
44 }
45 
get_u32_handle(__u32 * handle,const char * str)46 int get_u32_handle(__u32 *handle, const char *str)
47 {
48 	__u32 htid=0, hash=0, nodeid=0;
49 	char *tmp = strchr(str, ':');
50 
51 	if (tmp == NULL) {
52 		if (memcmp("0x", str, 2) == 0)
53 			return get_u32(handle, str, 16);
54 		return -1;
55 	}
56 	htid = strtoul(str, &tmp, 16);
57 	if (tmp == str && *str != ':' && *str != 0)
58 		return -1;
59 	if (htid>=0x1000)
60 		return -1;
61 	if (*tmp) {
62 		str = tmp+1;
63 		hash = strtoul(str, &tmp, 16);
64 		if (tmp == str && *str != ':' && *str != 0)
65 			return -1;
66 		if (hash>=0x100)
67 			return -1;
68 		if (*tmp) {
69 			str = tmp+1;
70 			nodeid = strtoul(str, &tmp, 16);
71 			if (tmp == str && *str != 0)
72 				return -1;
73 			if (nodeid>=0x1000)
74 				return -1;
75 		}
76 	}
77 	*handle = (htid<<20)|(hash<<12)|nodeid;
78 	return 0;
79 }
80 
get_u32_parse_handle(const char * cHandle)81 uint32_t get_u32_parse_handle(const char *cHandle)
82 {
83 	uint32_t handle=0;
84 
85 	if(get_u32_handle(&handle, cHandle)) {
86 		printf ("Illegal \"ht\"\n");
87 		return -1;
88 	}
89 
90 	if (handle && TC_U32_NODE(handle)) {
91 		printf("\"link\" must be a hash table.\n");
92 		return -1;
93 	}
94 	return handle;
95 }
96 
get_tc_classid(__u32 * h,const char * str)97 int get_tc_classid(__u32 *h, const char *str)
98 {
99 	__u32 maj, min;
100 	char *p;
101 
102 	maj = TC_H_ROOT;
103 	if (strcmp(str, "root") == 0)
104 		goto ok;
105 	maj = TC_H_UNSPEC;
106 	if (strcmp(str, "none") == 0)
107 		goto ok;
108 	maj = strtoul(str, &p, 16);
109 	if (p == str) {
110 		maj = 0;
111 		if (*p != ':')
112 			return -1;
113 	}
114 	if (*p == ':') {
115 		if (maj >= (1<<16))
116 			return -1;
117 		maj <<= 16;
118 		str = p+1;
119 		min = strtoul(str, &p, 16);
120 		if (*p != 0)
121 			return -1;
122 		if (min >= (1<<16))
123 			return -1;
124 		maj |= min;
125 	} else if (*p != 0)
126 		return -1;
127 
128 ok:
129 	*h = maj;
130 	return 0;
131 }
132 
133 /*
134  * Function that adds a new filter and attach it to a hash table
135  *
136  */
u32_add_filter_on_ht(struct nl_sock * sock,struct rtnl_link * rtnlLink,uint32_t prio,uint32_t keyval,uint32_t keymask,int keyoff,int keyoffmask,uint32_t htid,uint32_t classid)137 int u32_add_filter_on_ht(struct nl_sock *sock, struct rtnl_link *rtnlLink, uint32_t prio,
138 		uint32_t keyval, uint32_t keymask, int keyoff, int keyoffmask,
139 		uint32_t htid, uint32_t classid
140 )
141 {
142     struct rtnl_cls *cls;
143     int err;
144 
145     //printf("Key Val  : 0x%x\n", keyval);
146     //printf("Key Mask : 0x%x\n", keymask);
147 
148     cls=rtnl_cls_alloc();
149     if (!(cls)) {
150         printf("Can not allocate classifier\n");
151         nl_socket_free(sock);
152         exit(1);
153     }
154 
155     rtnl_tc_set_link(TC_CAST(cls), rtnlLink);
156 
157     if ((err = rtnl_tc_set_kind(TC_CAST(cls), "u32"))) {
158         printf("Can not set classifier as u32\n");
159         return 1;
160     }
161 
162     rtnl_cls_set_prio(cls, prio);
163     rtnl_cls_set_protocol(cls, ETH_P_IP);
164 
165     rtnl_tc_set_parent(TC_CAST(cls), TC_HANDLE(1, 0));
166 
167     rtnl_u32_set_hashtable(cls, htid);
168 
169     rtnl_u32_add_key_uint32(cls, keyval, keymask, keyoff, keyoffmask); /* 10.0.0.0/8 */
170 
171     rtnl_u32_set_classid(cls, classid);
172 
173     rtnl_u32_set_cls_terminal(cls);
174 
175     if ((err = rtnl_cls_add(sock, cls, NLM_F_CREATE))) {
176         printf("Can not add classifier: %s\n", nl_geterror(err));
177         return -1;
178     }
179     rtnl_cls_put(cls);
180     return 0;
181 
182 }
183 
184 /*
185  * Function that adds a new filter and attach it to a hash table
186  * and set next hash table link with hash mask
187  *
188  */
u32_add_filter_on_ht_with_hashmask(struct nl_sock * sock,struct rtnl_link * rtnlLink,uint32_t prio,uint32_t keyval,uint32_t keymask,int keyoff,int keyoffmask,uint32_t htid,uint32_t htlink,uint32_t hmask,uint32_t hoffset)189 int u32_add_filter_on_ht_with_hashmask(struct nl_sock *sock, struct rtnl_link *rtnlLink, uint32_t prio,
190 	    uint32_t keyval, uint32_t keymask, int keyoff, int keyoffmask,
191 	    uint32_t htid, uint32_t htlink, uint32_t hmask, uint32_t hoffset
192 )
193 {
194     struct rtnl_cls *cls;
195     int err;
196 
197     //printf("Key Val  : 0x%x\n", keyval);
198     //printf("Key Mask : 0x%x\n", keymask);
199 
200     cls=rtnl_cls_alloc();
201     if (!(cls)) {
202         printf("Can not allocate classifier\n");
203         nl_socket_free(sock);
204         exit(1);
205     }
206 
207     rtnl_tc_set_link(TC_CAST(cls), rtnlLink);
208 
209     if ((err = rtnl_tc_set_kind(TC_CAST(cls), "u32"))) {
210         printf("Can not set classifier as u32\n");
211         return 1;
212     }
213 
214     rtnl_cls_set_prio(cls, prio);
215     rtnl_cls_set_protocol(cls, ETH_P_IP);
216 
217     rtnl_tc_set_parent(TC_CAST(cls), TC_HANDLE(1, 0));
218 
219     if (htid)
220 	rtnl_u32_set_hashtable(cls, htid);
221 
222     rtnl_u32_add_key_uint32(cls, keyval, keymask, keyoff, keyoffmask);
223 
224     rtnl_u32_set_hashmask(cls, hmask, hoffset);
225 
226     rtnl_u32_set_link(cls, htlink);
227 
228 
229     if ((err = rtnl_cls_add(sock, cls, NLM_F_CREATE))) {
230         printf("Can not add classifier: %s\n", nl_geterror(err));
231         return -1;
232     }
233     rtnl_cls_put(cls);
234     return 0;
235 }
236 
237 /*
238  * function that creates a new hash table
239  */
u32_add_ht(struct nl_sock * sock,struct rtnl_link * rtnlLink,uint32_t prio,uint32_t htid,uint32_t divisor)240 int u32_add_ht(struct nl_sock *sock, struct rtnl_link *rtnlLink, uint32_t prio, uint32_t htid, uint32_t divisor)
241 {
242 
243     int err;
244     struct rtnl_cls *cls;
245 
246     cls=rtnl_cls_alloc();
247     if (!(cls)) {
248         printf("Can not allocate classifier\n");
249         nl_socket_free(sock);
250         exit(1);
251     }
252 
253     rtnl_tc_set_link(TC_CAST(cls), rtnlLink);
254 
255     if ((err = rtnl_tc_set_kind(TC_CAST(cls), "u32"))) {
256         printf("Can not set classifier as u32\n");
257         return 1;
258     }
259 
260     rtnl_cls_set_prio(cls, prio);
261     rtnl_cls_set_protocol(cls, ETH_P_IP);
262     rtnl_tc_set_parent(TC_CAST(cls), TC_HANDLE(1, 0));
263 
264     rtnl_u32_set_handle(cls, htid, 0x0, 0x0);
265     //printf("htid: 0x%X\n", htid);
266     rtnl_u32_set_divisor(cls, divisor);
267 
268     if ((err = rtnl_cls_add(sock, cls, NLM_F_CREATE))) {
269         printf("Can not add classifier: %s\n", nl_geterror(err));
270         return -1;
271     }
272     rtnl_cls_put(cls);
273     return 0;
274 }
275 
276 /*
277  * function that adds a new HTB qdisc and set the default class for unclassified traffic
278  */
qdisc_add_HTB(struct nl_sock * sock,struct rtnl_link * rtnlLink,uint32_t defaultClass)279 int qdisc_add_HTB(struct nl_sock *sock, struct rtnl_link *rtnlLink, uint32_t defaultClass)
280 {
281 
282     struct rtnl_qdisc *qdisc;
283     int err;
284 
285     /* Allocation of a qdisc object */
286     if (!(qdisc = rtnl_qdisc_alloc())) {
287         printf("Can not allocate Qdisc\n");
288 	return -1;
289     }
290 
291     //rtnl_tc_set_ifindex(TC_CAST(qdisc), master_index);
292     rtnl_tc_set_link(TC_CAST(qdisc), rtnlLink);
293     rtnl_tc_set_parent(TC_CAST(qdisc), TC_H_ROOT);
294 
295     //delete the qdisc
296     //printf("Delete current qdisc\n");
297     rtnl_qdisc_delete(sock, qdisc);
298     //rtnl_qdisc_put(qdisc);
299 
300     //add a HTB qdisc
301     //printf("Add a new HTB qdisc\n");
302     rtnl_tc_set_handle(TC_CAST(qdisc), TC_HANDLE(1,0));
303 
304     if ((err = rtnl_tc_set_kind(TC_CAST(qdisc), "htb"))) {
305         printf("Can not allocate HTB\n");
306 	return -1;
307     }
308 
309     /* Set default class for unclassified traffic */
310     //printf("Set default class for unclassified traffic\n");
311     rtnl_htb_set_defcls(qdisc, TC_HANDLE(1, defaultClass));
312     rtnl_htb_set_rate2quantum(qdisc, 1);
313 
314     /* Submit request to kernel and wait for response */
315     if ((err = rtnl_qdisc_add(sock, qdisc, NLM_F_CREATE))) {
316         printf("Can not allocate HTB Qdisc\n");
317 	return -1;
318     }
319 
320     /* Return the qdisc object to free memory resources */
321     rtnl_qdisc_put(qdisc);
322 
323     return 0;
324 }
325 
326 /*
327  * function that adds a new HTB class and set its parameters
328  */
class_add_HTB(struct nl_sock * sock,struct rtnl_link * rtnlLink,uint32_t parentMaj,uint32_t parentMin,uint32_t childMaj,uint32_t childMin,uint64_t rate,uint64_t ceil,uint32_t burst,uint32_t cburst,uint32_t prio)329 int class_add_HTB(struct nl_sock *sock, struct rtnl_link *rtnlLink,
330 		    uint32_t parentMaj, uint32_t parentMin,
331 		    uint32_t childMaj,  uint32_t childMin,
332 		    uint64_t rate, uint64_t ceil,
333 		    uint32_t burst, uint32_t cburst,
334 		    uint32_t prio
335 )
336 {
337     int err;
338     struct rtnl_class *class;
339     //struct rtnl_class *class = (struct rtnl_class *) tc;
340 
341     //create a HTB class
342     //class = (struct rtnl_class *)rtnl_class_alloc();
343     if (!(class = rtnl_class_alloc())) {
344         printf("Can not allocate class object\n");
345         return 1;
346     }
347     //
348     rtnl_tc_set_link(TC_CAST(class), rtnlLink);
349     //add a HTB qdisc
350     //printf("Add a new HTB class with 0x%X:0x%X on parent 0x%X:0x%X\n", childMaj, childMin, parentMaj, parentMin);
351     rtnl_tc_set_parent(TC_CAST(class), TC_HANDLE(parentMaj, parentMin));
352     rtnl_tc_set_handle(TC_CAST(class), TC_HANDLE(childMaj, childMin));
353 
354     if ((err = rtnl_tc_set_kind(TC_CAST(class), "htb"))) {
355         printf("Can not set HTB to class\n");
356         return 1;
357     }
358 
359     //printf("set HTB class prio to %u\n", prio);
360     rtnl_htb_set_prio((struct rtnl_class *)class, prio);
361 
362     if (rate) {
363 	//rate=rate/8;
364 	rtnl_htb_set_rate(class, rate);
365     }
366     if (ceil) {
367 	//ceil=ceil/8;
368 	rtnl_htb_set_ceil(class, ceil);
369     }
370 
371     if (burst) {
372 	//printf ("Class HTB: set rate burst: %u\n", burst);
373         rtnl_htb_set_rbuffer(class, burst);
374     }
375     if (cburst) {
376 	//printf ("Class HTB: set rate cburst: %u\n", cburst);
377         rtnl_htb_set_cbuffer(class, cburst);
378     }
379     /* Submit request to kernel and wait for response */
380     if ((err = rtnl_class_add(sock, class, NLM_F_CREATE))) {
381         printf("Can not allocate HTB Qdisc\n");
382         return 1;
383     }
384     rtnl_class_put(class);
385     return 0;
386 }
387 
388 /*
389  * function that adds a HTB root class and set its parameters
390  */
class_add_HTB_root(struct nl_sock * sock,struct rtnl_link * rtnlLink,uint64_t rate,uint64_t ceil,uint32_t burst,uint32_t cburst)391 int class_add_HTB_root(struct nl_sock *sock, struct rtnl_link *rtnlLink,
392 			uint64_t rate, uint64_t ceil,
393 			uint32_t burst, uint32_t cburst
394 )
395 {
396     int err;
397     struct rtnl_class *class;
398 
399     //create a HTB class
400     class = (struct rtnl_class *)rtnl_class_alloc();
401     //class = rtnl_class_alloc();
402     if (!class) {
403         printf("Can not allocate class object\n");
404         return 1;
405     }
406     //
407     rtnl_tc_set_link(TC_CAST(class), rtnlLink);
408     rtnl_tc_set_parent(TC_CAST(class), TC_H_ROOT);
409     //add a HTB class
410     //printf("Add a new HTB ROOT class\n");
411     rtnl_tc_set_handle(TC_CAST(class), 1);
412 
413     if ((err = rtnl_tc_set_kind(TC_CAST(class), "htb"))) {
414         printf("Can not set HTB to class\n");
415         return 1;
416     }
417 
418     if (rate) {
419 	//rate=rate/8;
420 	rtnl_htb_set_rate(class, rate);
421     }
422     if (ceil) {
423 	//ceil=ceil/8;
424 	rtnl_htb_set_ceil(class, ceil);
425     }
426 
427     if (burst) {
428         rtnl_htb_set_rbuffer(class, burst);
429     }
430     if (cburst) {
431         rtnl_htb_set_cbuffer(class, cburst);
432     }
433 
434     /* Submit request to kernel and wait for response */
435     if ((err = rtnl_class_add(sock, class, NLM_F_CREATE))) {
436         printf("Can not allocate HTB Qdisc\n");
437         return 1;
438     }
439     rtnl_class_put(class);
440     return 0;
441 }
442 
443 /*
444  * function that adds a new SFQ qdisc as a leaf for a HTB class
445  */
qdisc_add_SFQ_leaf(struct nl_sock * sock,struct rtnl_link * rtnlLink,uint32_t parentMaj,uint32_t parentMin,int quantum,int limit,int perturb)446 int qdisc_add_SFQ_leaf(struct nl_sock *sock, struct rtnl_link *rtnlLink,
447 			uint32_t parentMaj, uint32_t parentMin,
448 			int quantum, int limit, int perturb
449 )
450 {
451     int err;
452     struct rtnl_qdisc *qdisc;
453 
454     if (!(qdisc = rtnl_qdisc_alloc())) {
455         printf("Can not allocate qdisc object\n");
456         return 1;
457     }
458     rtnl_tc_set_link(TC_CAST(qdisc), rtnlLink);
459     rtnl_tc_set_parent(TC_CAST(qdisc), TC_HANDLE(parentMaj, parentMin));
460 
461     rtnl_tc_set_handle(TC_CAST(qdisc), TC_HANDLE(parentMin,0));
462 
463     if ((err = rtnl_tc_set_kind(TC_CAST(qdisc), "sfq"))) {
464         printf("Can not set SQF class\n");
465         return 1;
466     }
467 
468     if(quantum) {
469         rtnl_sfq_set_quantum(qdisc, quantum);
470     } else {
471         rtnl_sfq_set_quantum(qdisc, 16000); // tc default value
472     }
473     if(limit) {
474         rtnl_sfq_set_limit(qdisc, limit); // default is 127
475     }
476     if(perturb) {
477         rtnl_sfq_set_perturb(qdisc, perturb); // default never perturb the hash
478     }
479 
480     /* Submit request to kernel and wait for response */
481     if ((err = rtnl_qdisc_add(sock, qdisc, NLM_F_CREATE))) {
482         printf("Can not allocate SFQ qdisc\n");
483 	return -1;
484     }
485 
486     /* Return the qdisc object to free memory resources */
487     rtnl_qdisc_put(qdisc);
488     return 0;
489 }
490 
491 
492 
493 
main()494 int main() {
495 
496     struct nl_sock *sock;
497     struct rtnl_link *link;
498 
499     //struct rtnl_qdisc *qdisc;
500     //struct rtnl_class *class;
501     //struct rtnl_cls   *cls;
502 
503     uint32_t ht, htlink, htid, direction, classid;
504     //uint32_t hash, hashmask, nodeid, divisor, handle;
505     //struct rtnl_u32 *f_u32;
506     char chashlink[16]="";
507 
508     //uint64_t drops, qlen;
509 
510     //int master_index;
511     int err;
512 
513     //uint64_t rate=0, ceil=0;
514 
515     struct nl_cache *link_cache;
516 
517     if (!(sock = nl_socket_alloc())) {
518         printf("Unable to allocate netlink socket\n");
519         exit(1);
520     }
521 
522     if ((err = nl_connect(sock, NETLINK_ROUTE)) < 0 ) {
523         printf("Nu s-a putut conecta la NETLINK!\n");
524         nl_socket_free(sock);
525         exit(1);
526     }
527 
528 
529     if ((err = rtnl_link_alloc_cache(sock, AF_UNSPEC, &link_cache)) < 0) {
530         printf("Unable to allocate link cache: %s\n",
531                              nl_geterror(err));
532         nl_socket_free(sock);
533         exit(1);
534     }
535 
536     /* lookup interface index of eth0 */
537     if (!(link = rtnl_link_get_by_name(link_cache, "imq0"))) {
538         /* error */
539         printf("Interface not found\n");
540         nl_socket_free(sock);
541         exit(1);
542     }
543 
544     err=qdisc_add_HTB(sock, link, 0xffff);
545     //drops = rtnl_tc_get_stat(TC_CAST(qdisc), RTNL_TC_DROPS);
546 
547     //printf("Add ROOT HTB class\n");
548     err=class_add_HTB_root(sock, link, 12500000, 12500000, 25000, 25000);
549     err=class_add_HTB(sock, link, 1, 0, 1, 0xffff, 1250000, 12500000, 25000, 25000, 5);
550     err=qdisc_add_SFQ_leaf(sock, link, 1, 0xffff, 16000, 0, 10);
551     err=class_add_HTB(sock, link, 1, 1, 1, 0x5, 2000000, 2000000, 25000, 25000, 5);
552     err=qdisc_add_SFQ_leaf(sock, link, 1, 0x5, 16000, 0, 10);
553     err=class_add_HTB(sock, link, 1, 1, 1, 0x6, 1000000, 1000000, 25000, 25000, 5);
554     err=qdisc_add_SFQ_leaf(sock, link, 1, 0x6, 16000, 0, 10);
555     //err=class_add_HTB(sock, link, 1, 0, 1, 0x7, 1024000, 100000000, 5);
556     //err=class_add_HTB(sock, link, 1, 0, 1, 0x8, 2048000, 100000000, 5);
557     //err=class_add_HTB(sock, link, 1, 0, 1, 0x9, 4096000, 100000000, 5);
558     //err=class_add_HTB(sock, link, 1, 0, 1, 0xa, 8192000, 100000000, 5);
559 
560     //printf("Add main hash table\n");
561 
562     /* create u32 first hash filter table
563      *
564      */
565     /* formula calcul handle:
566     *         uint32_t handle = (htid << 20) | (hash << 12) | nodeid;
567     */
568 
569     /*
570      * Upper limit of number of hash tables: 4096 (0xFFF)
571      * Number of hashes in a table: 256 values (0xFF)
572      *
573      */
574 
575     /* using 256 values for hash table
576      * each entry in hash table match a byte from IP address specified later by a hash key
577      */
578 
579     uint32_t i;
580     for (i = 1; i <= 0xf; i++)
581 	u32_add_ht(sock, link, 1, i, 256);
582 
583     /*
584      * attach a u32 filter to the first hash
585      * that redirects all traffic and make a hash key
586      * from the fist byte of the IP address
587      *
588      */
589 
590     //divisor=0x0;	// unused here
591     //handle = 0x0;	// unused here
592     //hash = 0x0;		// unused here
593     //htid = 0x0;		// unused here
594     //nodeid = 0x0;	// unused here
595 
596     // direction = 12 -> source IP
597     // direction = 16 -> destination IP
598     direction = 16;
599 
600     /*
601      * which hash table will use
602      * in our case is hash table no 1 defined previous
603      *
604      * There are 2 posibilities to set the the hash table:
605      * 1. Using function get_u32_handle and sent a string in
606      *  format 10: where 10 is number of the hash table
607      * 2. Create your own value in format: 0xa00000
608      *
609      */
610     strcpy(chashlink, "1:");
611     //printf("Hash Link: %s\n", chashlink);
612     //chashlink=malloc(sizeof(char) *
613     htlink = 0x0;		// is used by get_u32_handle to return the correct value of hash table (link)
614 
615     if(get_u32_handle(&htlink, chashlink)) {
616         printf ("Illegal \"link\"");
617         nl_socket_free(sock);
618         exit(1);
619     }
620     //printf ("hash link : 0x%X\n", htlink);
621     //printf ("hash link test : %u\n", (htlink && TC_U32_NODE(htlink)));
622 
623     if (htlink && TC_U32_NODE(htlink)) {
624 	printf("\"link\" must be a hash table.\n");
625         nl_socket_free(sock);
626         exit(1);
627     }
628     /* the hash mask will hit the hash table (link) no 1: in our case
629      */
630 
631     /* set the hash key mask */
632     //hashmask = 0xFF000000UL;	// the mask that is used to match the hash in specific table, in our case for example 1:a with mean the first byte which is 10 in hash table 1
633 
634     /* Here we add a hash filter which match the first byte (see the hashmask value)
635      * of the source IP (offset 12 in the packet header)
636      * You can use also offset 16 to match the destination IP
637      */
638 
639     /*
640      * Also we need a filter to match our rule
641      * This mean that we will put a 0.0.0.0/0 filter in our first rule
642      * that match the offset 12 (source IP)
643      * Also you can put offset 16 to match the destination IP
644      */
645 
646     u32_add_filter_on_ht_with_hashmask(sock, link, 1,
647 	    0x0, 0x0, direction, 0,
648 	    0, htlink, 0xff000000, direction);
649 
650     /*
651      * For each first byte that we need to match we will create a new hash table
652      * For example: you have those clases: 10.0.0.0/24 and 172.16.0.0/23
653      * For byte 10 and byte 172 will create a separate hash table that will match the second
654      * byte from each class.
655      *
656      */
657 
658 
659     // Create a new hash table with prio 1, id 2 and 256 entries
660 //    u32_CreateNewHashTable(sock, link, 1, 2, 256);
661     // Create a new hash table with prio 1, id 3 and 256 entries
662 //    u32_CreateNewHashTable(sock, link, 1, 3, 256);
663 //    u32_CreateNewHashTable(sock, link, 1, 4, 256);
664 //    u32_CreateNewHashTable(sock, link, 1, 5, 256);
665 
666     /*
667      * Now we will create other filter under (ATENTION) our first hash table (link) 1:
668      * Previous rule redirects the trafic according the hash mask to hash table (link) no 1:
669      * Here we will match the hash tables from 1:0 to 1:ff. Under each hash table we will attach
670      * other rules that matches next byte from IP source/destination IP and we will repeat the
671      * previous steps.
672      *
673      */
674 
675 
676     // /8 check
677 
678     // 10.0.0.0/8
679     ht=get_u32_parse_handle("1:a:");
680     htid = (ht&0xFFFFF000);
681     htlink=get_u32_parse_handle("2:");
682 
683     u32_add_filter_on_ht_with_hashmask(sock, link, 1,
684 	    0x0a000000, 0xff000000, direction, 0,
685 	    htid, htlink, 0x00ff0000, direction);
686 
687     // 172.0.0.0/8
688     ht=get_u32_parse_handle("1:ac:");
689     htid = (ht&0xFFFFF000);
690     htlink=get_u32_parse_handle("3:");
691 
692     u32_add_filter_on_ht_with_hashmask(sock, link, 1,
693 	    0xac000000, 0xff000000, direction, 0,
694 	    htid, htlink, 0x00ff0000, direction);
695 
696 
697     // /16 check
698     // 10.0.0.0/16
699     ht=get_u32_parse_handle("2:0:");
700     htid = (ht&0xFFFFF000);
701     htlink=get_u32_parse_handle("4:");
702 
703     u32_add_filter_on_ht_with_hashmask(sock, link, 1,
704 	    0x0a000000, 0xffff0000, direction, 0,
705 	    htid, htlink, 0x0000ff00, direction);
706 
707     // 172.17.0.0/16
708     ht=get_u32_parse_handle("3:11:");
709     htid = (ht&0xFFFFF000);
710     htlink=get_u32_parse_handle("5:");
711 
712     u32_add_filter_on_ht_with_hashmask(sock, link, 1,
713 	    0xac110000, 0xffff0000, direction, 0,
714 	    htid, htlink, 0x0000ff00, direction);
715 
716     // /24 check
717     // 10.0.9.0/24
718     ht=get_u32_parse_handle("4:9:");
719     htid = (ht&0xFFFFF000);
720     htlink=get_u32_parse_handle("6:");
721 
722     u32_add_filter_on_ht_with_hashmask(sock, link, 1,
723 	    0x0a000900, 0xffffff00, direction, 0,
724 	    htid, htlink, 0x000000ff, direction);
725 
726     // 172.17.2.0/16
727     ht=get_u32_parse_handle("5:2:");
728     htid = (ht&0xFFFFF000);
729     htlink=get_u32_parse_handle("7:");
730 
731     u32_add_filter_on_ht_with_hashmask(sock, link, 1,
732 	    0xac110200, 0xffffff00, direction, 0,
733 	    htid, htlink, 0x000000ff, direction);
734 
735 
736     // final filters
737     // 10.0.9.20
738     ht=get_u32_parse_handle("6:14:");
739     htid = (ht&0xFFFFF000);
740 
741     err = get_tc_classid(&classid, "1:5");
742 
743     u32_add_filter_on_ht(sock, link, 1,
744 	    0x0a000914, 0xffffffff, direction, 0,
745 	    htid, classid);
746 
747     // 172.17.2.120
748     ht=get_u32_parse_handle("7:78:");
749     htid = (ht&0xFFFFF000);
750 
751     err = get_tc_classid(&classid, "1:6");
752 
753     u32_add_filter_on_ht(sock, link, 1,
754 	    0xac110278, 0xffffffff, direction, 0,
755 	    htid, classid);
756 
757 
758 
759     nl_socket_free(sock);
760     return 0;
761 }
762