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