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