Home | History | Annotate | Download | only in tests
      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 (at) 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 */
     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 
     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 
     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 
     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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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 
    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