1 /*
2 * Copyright (c) 2009-2020, Peter Haag
3 * Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * * Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 * * Neither the name of the author nor the names of its contributors may be
15 * used to endorse or promote products derived from this software without
16 * specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 *
30 */
31
32 #include "config.h"
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <sys/types.h>
37 #include <string.h>
38 #include <errno.h>
39
40 #ifdef HAVE_STDINT_H
41 #include <stdint.h>
42 #endif
43
44 #include "rbtree.h"
45 #include "filter.h"
46 #include "nfdump.h"
47 #include "nffile.h"
48 #include "ipconv.h"
49 #include "nftree.h"
50
51 // #include "grammar.h"
52
53 /*
54 * netflow filter engine
55 *
56 */
57
58 extern char *CurrentIdent;
59
60 #define MAXBLOCKS 1024
61
62 static FilterBlock_t *FilterTree;
63 static uint32_t memblocks;
64
65 static uint32_t NumBlocks = 1; /* index 0 reserved */
66
67 #define IdentNumBlockSize 32
68 static uint16_t MaxIdents;
69 static uint16_t NumIdents;
70 static char **IdentList;
71
72 static void UpdateList(uint32_t a, uint32_t b);
73
74 /* flow processing functions */
75 static inline void pps_function(uint64_t *record_data, uint64_t *comp_values);
76 static inline void bps_function(uint64_t *record_data, uint64_t *comp_values);
77 static inline void bpp_function(uint64_t *record_data, uint64_t *comp_values);
78 static inline void duration_function(uint64_t *record_data, uint64_t *comp_values);
79 static inline void mpls_eos_function(uint64_t *record_data, uint64_t *comp_values);
80 static inline void mpls_any_function(uint64_t *record_data, uint64_t *comp_values);
81 static inline void pblock_function(uint64_t *record_data, uint64_t *comp_values);
82
83 /*
84 * flow processing function table:
85 * order of entries must correspond with filter functions enum in nftree.h
86 */
87 static struct flow_procs_map_s {
88 char *name;
89 flow_proc_t function;
90 } flow_procs_map[] = {
91 {"none", NULL},
92 {"pps", pps_function},
93 {"bps", bps_function},
94 {"bpp", bpp_function},
95 {"duration", duration_function},
96 {"mpls eos", mpls_eos_function},
97 {"mpls any", mpls_any_function},
98 {"pblock", pblock_function},
99 {NULL, NULL}
100 };
101
102 uint64_t *IPstack = NULL;
103 uint32_t StartNode;
104 uint16_t Extended;
105
106 // 128bit compare for IPv6
IPNodeCMP(struct IPListNode * e1,struct IPListNode * e2)107 static int IPNodeCMP(struct IPListNode *e1, struct IPListNode *e2) {
108 uint64_t ip_e1[2], ip_e2[2];
109
110 ip_e1[0] = e1->ip[0] & e2->mask[0];
111 ip_e1[1] = e1->ip[1] & e2->mask[1];
112
113 ip_e2[0] = e2->ip[0] & e1->mask[0];
114 ip_e2[1] = e2->ip[1] & e1->mask[1];
115
116 if ( ip_e1[0] == ip_e2[0] ) {
117 if ( ip_e1[1] == ip_e2[1] )
118 return 0;
119 else
120 return (ip_e1[1] < ip_e2[1] ? -1 : 1);
121 } else {
122 return (ip_e1[0] < ip_e2[0] ? -1 : 1);
123 }
124
125 } // End of IPNodeCMP
126
127 // 64bit uint64 compare
ULNodeCMP(struct ULongListNode * e1,struct ULongListNode * e2)128 static int ULNodeCMP(struct ULongListNode *e1, struct ULongListNode *e2) {
129 if ( e1->value == e2->value )
130 return 0;
131 else
132 return (e1->value < e2->value ? -1 : 1);
133
134 } // End of ULNodeCMP
135
136 // Insert the IP RB tree code here
137 RB_GENERATE(IPtree, IPListNode, entry, IPNodeCMP);
138
139 // Insert the Ulong RB tree code here
140 RB_GENERATE(ULongtree, ULongListNode, entry, ULNodeCMP);
141
InitTree(void)142 void InitTree(void) {
143 memblocks = 1;
144 FilterTree = (FilterBlock_t *)malloc(MAXBLOCKS * sizeof(FilterBlock_t));
145 if ( !FilterTree ) {
146 fprintf(stderr, "Memory allocation error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
147 exit(255);
148 }
149 ClearFilter();
150 } // End of InitTree
151
152
153 /*
154 * Clear Filter
155 */
ClearFilter(void)156 void ClearFilter(void) {
157
158 NumBlocks = 1;
159 Extended = 0;
160 MaxIdents = 0;
161 NumIdents = 0;
162 IdentList = NULL;
163 memset((void *)FilterTree, 0, MAXBLOCKS * sizeof(FilterBlock_t));
164
165 } /* End of ClearFilter */
166
CompileFilter(char * FilterSyntax)167 FilterEngine_t *CompileFilter(char *FilterSyntax) {
168 FilterEngine_t *engine;
169 int ret;
170
171 if ( !FilterSyntax )
172 return NULL;
173
174 IPstack = (uint64_t *)malloc(16 * MAXHOSTS);
175 if ( !IPstack ) {
176 fprintf(stderr, "Memory allocation error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
177 exit(255);
178 }
179
180 InitTree();
181 lex_init(FilterSyntax);
182 ret = yyparse();
183 if ( ret != 0 ) {
184 return NULL;
185 }
186 lex_cleanup();
187 free(IPstack);
188
189 engine = malloc(sizeof(FilterEngine_t));
190 if ( !engine ) {
191 fprintf(stderr, "Memory allocation error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
192 exit(255);
193 }
194 engine->nfrecord = NULL;
195 engine->StartNode = StartNode;
196 engine->Extended = Extended;
197 engine->IdentList = IdentList;
198 engine->filter = FilterTree;
199 if ( Extended )
200 engine->FilterEngine = RunExtendedFilter;
201 else
202 engine->FilterEngine = RunFilter;
203
204 return (FilterEngine_t *)engine;
205
206 } // End of GetTree
207
208 /*
209 * For testing purpose only
210 */
nblocks(void)211 int nblocks(void) {
212 return NumBlocks - 1;
213 } /* End of nblocks */
214
215 /*
216 * Returns next free slot in blocklist
217 */
NewBlock(uint32_t offset,uint64_t mask,uint64_t value,uint16_t comp,uint32_t function,void * data)218 uint32_t NewBlock(uint32_t offset, uint64_t mask, uint64_t value, uint16_t comp, uint32_t function, void *data) {
219 uint32_t n = NumBlocks;
220
221 if ( n >= ( memblocks * MAXBLOCKS ) ) {
222 memblocks++;
223 FilterTree = realloc(FilterTree, memblocks * MAXBLOCKS * sizeof(FilterBlock_t));
224 if ( !FilterTree ) {
225 fprintf(stderr, "Memory allocation error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
226 exit(255);
227 }
228 }
229
230 FilterTree[n].offset = offset;
231 FilterTree[n].mask = mask;
232 FilterTree[n].value = value;
233 FilterTree[n].invert = 0;
234 FilterTree[n].OnTrue = 0;
235 FilterTree[n].OnFalse = 0;
236 FilterTree[n].comp = comp;
237 FilterTree[n].function = flow_procs_map[function].function;
238 FilterTree[n].fname = flow_procs_map[function].name;
239 FilterTree[n].label = NULL;
240 FilterTree[n].data = data;
241 if ( comp > 0 || function > 0 )
242 Extended = 1;
243
244 FilterTree[n].numblocks = 1;
245 FilterTree[n].blocklist = (uint32_t *)malloc(sizeof(uint32_t));
246 FilterTree[n].superblock = n;
247 FilterTree[n].blocklist[0] = n;
248 NumBlocks++;
249 return n;
250
251 } /* End of NewBlock */
252
253 /*
254 * Connects the two blocks b1 and b2 ( AND ) and returns index of superblock
255 */
Connect_AND(uint32_t b1,uint32_t b2)256 uint32_t Connect_AND(uint32_t b1, uint32_t b2) {
257
258 uint32_t a, b, i, j;
259
260 if ( FilterTree[b1].numblocks <= FilterTree[b2].numblocks ) {
261 a = b1;
262 b = b2;
263 } else {
264 a = b2;
265 b = b1;
266 }
267 /* a points to block with less children and becomes the superblock
268 * connect b to a
269 */
270 for ( i=0; i < FilterTree[a].numblocks; i++ ) {
271 j = FilterTree[a].blocklist[i];
272 if ( FilterTree[j].invert ) {
273 if ( FilterTree[j].OnFalse == 0 ) {
274 FilterTree[j].OnFalse = b;
275 }
276 } else {
277 if ( FilterTree[j].OnTrue == 0 ) {
278 FilterTree[j].OnTrue = b;
279 }
280 }
281 }
282 UpdateList(a,b);
283 return a;
284
285 } /* End of Connect_AND */
286
287 /*
288 * Connects the two blocks b1 and b2 ( OR ) and returns index of superblock
289 */
Connect_OR(uint32_t b1,uint32_t b2)290 uint32_t Connect_OR(uint32_t b1, uint32_t b2) {
291
292 uint32_t a, b, i, j;
293
294 if ( FilterTree[b1].numblocks <= FilterTree[b2].numblocks ) {
295 a = b1;
296 b = b2;
297 } else {
298 a = b2;
299 b = b1;
300 }
301 /* a points to block with less children and becomes the superblock
302 * connect b to a
303 */
304 for ( i=0; i < FilterTree[a].numblocks; i++ ) {
305 j = FilterTree[a].blocklist[i];
306 if ( FilterTree[j].invert ) {
307 if ( FilterTree[j].OnTrue == 0 ) {
308 FilterTree[j].OnTrue = b;
309 }
310 } else {
311 if ( FilterTree[j].OnFalse == 0 ) {
312 FilterTree[j].OnFalse = b;
313 }
314 }
315 }
316 UpdateList(a,b);
317 return a;
318
319 } /* End of Connect_OR */
320
321 /*
322 * Inverts OnTrue and OnFalse
323 */
Invert(uint32_t a)324 uint32_t Invert(uint32_t a) {
325 uint32_t i, j;
326
327 for ( i=0; i< FilterTree[a].numblocks; i++ ) {
328 j = FilterTree[a].blocklist[i];
329 FilterTree[j].invert = FilterTree[j].invert ? 0 : 1 ;
330 }
331 return a;
332
333 } /* End of Invert */
334
335 /*
336 * Update supernode infos:
337 * node 'b' was connected to 'a'. update node 'a' supernode data
338 */
UpdateList(uint32_t a,uint32_t b)339 static void UpdateList(uint32_t a, uint32_t b) {
340 size_t s;
341 uint32_t i,j;
342
343 /* numblocks contains the number of blocks in the superblock */
344 s = FilterTree[a].numblocks + FilterTree[b].numblocks;
345 FilterTree[a].blocklist = (uint32_t *)realloc(FilterTree[a].blocklist, s * sizeof(uint32_t));
346 if ( !FilterTree[a].blocklist ) {
347 fprintf(stderr, "Memory allocation error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
348 exit(250);
349 }
350
351 /* connect list of node 'b' after list of node 'a' */
352 j = FilterTree[a].numblocks;
353 for ( i=0; i< FilterTree[b].numblocks; i++ ) {
354 FilterTree[a].blocklist[j+i] = FilterTree[b].blocklist[i];
355 }
356 FilterTree[a].numblocks = s;
357
358 /* set superblock info of all children to new superblock */
359 for ( i=0; i< FilterTree[a].numblocks; i++ ) {
360 j = FilterTree[a].blocklist[i];
361 FilterTree[j].superblock = a;
362 }
363
364 /* cleanup old node 'b' */
365 FilterTree[b].numblocks = 0;
366 if ( FilterTree[b].blocklist )
367 free(FilterTree[b].blocklist);
368
369 } /* End of UpdateList */
370
371 /*
372 * Dump Filterlist
373 */
DumpEngine(FilterEngine_t * engine)374 void DumpEngine(FilterEngine_t *engine) {
375 uint32_t i, j;
376
377 for (i=1; i<NumBlocks; i++ ) {
378 if ( engine->filter[i].invert )
379 printf("Index: %u, Offset: %u, Mask: %.16llx, Value: %.16llx, Superblock: %u, Numblocks: %u, !OnTrue: %u, !OnFalse: %u Comp: %u Function: %s, Label: %s\n",
380 i, engine->filter[i].offset, (unsigned long long)engine->filter[i].mask,
381 (unsigned long long)engine->filter[i].value, engine->filter[i].superblock,
382 engine->filter[i].numblocks, engine->filter[i].OnTrue, engine->filter[i].OnFalse,
383 engine->filter[i].comp, engine->filter[i].fname, engine->filter[i].label ? engine->filter[i].label : "<none>");
384 else
385 printf("Index: %u, Offset: %u, Mask: %.16llx, Value: %.16llx, Superblock: %u, Numblocks: %u, OnTrue: %u, OnFalse: %u Comp: %u Function: %s, Label: %s\n",
386 i, engine->filter[i].offset, (unsigned long long)engine->filter[i].mask,
387 (unsigned long long)engine->filter[i].value, engine->filter[i].superblock,
388 engine->filter[i].numblocks, engine->filter[i].OnTrue, engine->filter[i].OnFalse,
389 engine->filter[i].comp, engine->filter[i].fname, engine->filter[i].label ? engine->filter[i].label : "<none>");
390 if ( engine->filter[i].OnTrue > (memblocks * MAXBLOCKS) || engine->filter[i].OnFalse > (memblocks * MAXBLOCKS) ) {
391 fprintf(stderr, "Tree pointer out of range for index %u. *** ABORT ***\n", i);
392 exit(255);
393 }
394 if ( engine->filter[i].data ) {
395 if ( engine->filter[i].comp == CMP_IPLIST ) {
396 struct IPListNode *node;
397 RB_FOREACH(node, IPtree, engine->filter[i].data) {
398 printf("value: %.16llx %.16llx mask: %.16llx %.16llx\n",
399 (unsigned long long)node->ip[0], (unsigned long long)node->ip[1],
400 (unsigned long long)node->mask[0], (unsigned long long)node->mask[1]);
401 }
402 } else if ( engine->filter[i].comp == CMP_ULLIST ) {
403 struct ULongListNode *node;
404 RB_FOREACH(node, ULongtree, engine->filter[i].data) {
405 printf("%.16llx \n", (unsigned long long)node->value);
406 }
407 } else
408 printf("Error comp: %i\n", engine->filter[i].comp);
409 }
410 printf("\tBlocks: ");
411 for ( j=0; j<engine->filter[i].numblocks; j++ )
412 printf("%i ", engine->filter[i].blocklist[j]);
413 printf("\n");
414 }
415 printf("NumBlocks: %i\n", NumBlocks - 1);
416 for ( i=0; i<NumIdents; i++ ) {
417 printf("Ident %i: %s\n", i, IdentList[i]);
418 }
419 } /* End of DumpList */
420
421 /* fast filter engine */
RunFilter(FilterEngine_t * engine)422 int RunFilter(FilterEngine_t *engine) {
423 uint32_t index, offset;
424 int evaluate, invert;
425
426 engine->label = NULL;
427 index = engine->StartNode;
428 evaluate = 0;
429 invert = 0;
430 while ( index ) {
431 offset = engine->filter[index].offset;
432 invert = engine->filter[index].invert;
433 evaluate = ( engine->nfrecord[offset] & engine->filter[index].mask ) == engine->filter[index].value;
434 index = evaluate ? engine->filter[index].OnTrue : engine->filter[index].OnFalse;
435 }
436 return invert ? !evaluate : evaluate;
437
438 } /* End of RunFilter */
439
440 /* extended filter engine */
RunExtendedFilter(FilterEngine_t * engine)441 int RunExtendedFilter(FilterEngine_t *engine) {
442 uint32_t index, offset;
443 uint64_t comp_value[2];
444 int evaluate, invert;
445
446 engine->label = NULL;
447 index = engine->StartNode;
448 evaluate = 0;
449 invert = 0;
450 while ( index ) {
451 offset = engine->filter[index].offset;
452 invert = engine->filter[index].invert;
453
454 comp_value[0] = engine->nfrecord[offset] & engine->filter[index].mask;
455 comp_value[1] = engine->filter[index].value;
456
457 if (engine->filter[index].function != NULL)
458 engine->filter[index].function(engine->nfrecord, comp_value);
459
460 switch (engine->filter[index].comp) {
461 case CMP_EQ:
462 evaluate = comp_value[0] == comp_value[1];
463 break;
464 case CMP_GT:
465 evaluate = comp_value[0] > comp_value[1];
466 break;
467 case CMP_LT:
468 evaluate = comp_value[0] < comp_value[1];
469 break;
470 case CMP_IDENT:
471 evaluate = strncmp(CurrentIdent, engine->IdentList[comp_value[1]], IDENTLEN) == 0 ;
472 break;
473 case CMP_FLAGS:
474 if ( invert )
475 evaluate = comp_value[0] > 0;
476 else
477 evaluate = comp_value[0] == comp_value[1];
478 break;
479 case CMP_IPLIST: {
480 struct IPListNode find;
481 find.ip[0] = engine->nfrecord[offset];
482 find.ip[1] = engine->nfrecord[offset+1];
483 find.mask[0] = 0xffffffffffffffffLL;
484 find.mask[1] = 0xffffffffffffffffLL;
485 evaluate = RB_FIND(IPtree, engine->filter[index].data, &find) != NULL; }
486 break;
487 case CMP_ULLIST: {
488 struct ULongListNode find;
489 find.value = comp_value[0];
490 evaluate = RB_FIND(ULongtree, engine->filter[index].data, &find ) != NULL; }
491 break;
492 }
493
494 /*
495 * Label evaluation:
496 * A flow gets labeled, if one filter expression has a label assigned and
497 * that filter expression is in the 'true' path of the tree, resulting
498 * to a final match. If subsequent expressions in the same path evaluate
499 * to false, the label is cleared again.
500 * In case of multiple labels in a true patch, the last seen label wins.
501 */
502 if ( evaluate ) {
503 // if filter expression has a label assigned, copy that
504 if ( engine->filter[index].label ) {
505 engine->label = engine->filter[index].label;
506 }
507 index = engine->filter[index].OnTrue;
508 } else {
509 // filter expression does not match - clear previous label if abailable
510 if ( engine->label )
511 engine->label = NULL;
512 index = engine->filter[index].OnFalse;
513 }
514 // index = evaluate ? engine->filter[index].OnTrue : engine->filter[index].OnFalse;
515 }
516 return invert ? !evaluate : evaluate;
517
518 } /* End of RunExtendedFilter */
519
AddLabel(uint32_t index,char * label)520 void AddLabel(uint32_t index, char *label) {
521
522 FilterTree[index].label = strdup(label);
523 //Evaluation requires extended engine
524 Extended = 1;
525
526 } // End of AddLabel
527
AddIdent(char * Ident)528 uint32_t AddIdent(char *Ident) {
529 uint32_t num;
530
531 if ( MaxIdents == 0 ) {
532 // allocate first array block
533 MaxIdents = IdentNumBlockSize;
534 IdentList = (char **)malloc( MaxIdents * sizeof(char *));
535 if ( !IdentList ) {
536 fprintf(stderr, "Memory allocation error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
537 exit(254);
538 }
539 memset((void *)IdentList, 0, MaxIdents * sizeof(char *));
540 NumIdents = 0;
541 } else if ( NumIdents == MaxIdents ) {
542 // extend array block
543 MaxIdents += IdentNumBlockSize;
544 IdentList = realloc((void *)IdentList, MaxIdents * sizeof(char *));
545 if ( !IdentList ) {
546 fprintf(stderr, "Memory allocation error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
547 exit(254);
548 }
549 }
550
551 num = NumIdents++;
552 IdentList[num] = strdup(Ident);
553 if ( !IdentList[num] ) {
554 fprintf(stderr, "Memory allocation error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
555 exit(254);
556 }
557
558 return num;
559
560 } // End of AddIdent
561
562 /* record processing functions */
563
duration_function(uint64_t * record_data,uint64_t * comp_values)564 static inline void duration_function(uint64_t *record_data, uint64_t *comp_values) {
565 master_record_t *record = (master_record_t *)record_data;
566
567 /* duration in msec */
568 comp_values[0] = 1000*(record->last - record->first) + record->msec_last - record->msec_first;
569
570 } // End of duration_function
571
pps_function(uint64_t * record_data,uint64_t * comp_values)572 static inline void pps_function(uint64_t *record_data, uint64_t *comp_values) {
573 master_record_t *record = (master_record_t *)record_data;
574 uint64_t duration;
575
576 /* duration in msec */
577 duration = 1000*(record->last - record->first) + record->msec_last - record->msec_first;
578 if ( duration == 0 )
579 comp_values[0] = 0;
580 else
581 comp_values[0] = ( 1000LL * record->dPkts ) / duration;
582
583 } // End of pps_function
584
bps_function(uint64_t * record_data,uint64_t * comp_values)585 static inline void bps_function(uint64_t *record_data, uint64_t *comp_values) {
586 master_record_t *record = (master_record_t *)record_data;
587 uint64_t duration;
588
589 /* duration in msec */
590 duration = 1000*(record->last - record->first) + record->msec_last - record->msec_first;
591 if ( duration == 0 )
592 comp_values[0] = 0;
593 else
594 comp_values[0] = ( 8000LL * record->dOctets ) / duration; /* 8 bits per Octet - x 1000 for msec */
595
596 } // End of bps_function
597
bpp_function(uint64_t * record_data,uint64_t * comp_values)598 static inline void bpp_function(uint64_t *record_data, uint64_t *comp_values) {
599 master_record_t *record = (master_record_t *)record_data;
600
601 comp_values[0] = record->dPkts ? record->dOctets / record->dPkts : 0;
602
603 } // End of bpp_function
604
mpls_eos_function(uint64_t * record_data,uint64_t * comp_values)605 static inline void mpls_eos_function(uint64_t *record_data, uint64_t *comp_values) {
606 master_record_t *record = (master_record_t *)record_data;
607 int i;
608
609 // search for end of MPLS stack label
610 for (i=0; i<10; i++ ) {
611 if ( record->mpls_label[i] & 1 ) {
612 // End of stack found -> mask exp and eos bits
613 comp_values[0] = record->mpls_label[i] & 0x00FFFFF0;
614 return;
615 }
616 }
617
618 // trick filter to fail with an invalid mpls label value
619 comp_values[0] = 0xFF000000;
620
621 } // End of mpls_eos_function
622
mpls_any_function(uint64_t * record_data,uint64_t * comp_values)623 static inline void mpls_any_function(uint64_t *record_data, uint64_t *comp_values) {
624 master_record_t *record = (master_record_t *)record_data;
625 int i;
626
627 // search for end of MPLS stack label
628 for (i=0; i<10; i++ ) {
629 if ( (record->mpls_label[i] & 1) == 1 ) {
630 // End of stack found -> mask exp and eos bits
631 comp_values[0] = record->mpls_label[i] & 0x00FFFFF0;
632 return;
633 }
634 }
635
636 // trick filter to fail with an invalid mpls label value
637 comp_values[0] = 0xFF000000;
638
639 } // End of mpls_eos_function
640
pblock_function(uint64_t * record_data,uint64_t * comp_values)641 static inline void pblock_function(uint64_t *record_data, uint64_t *comp_values) {
642 #ifdef NSEL
643 master_record_t *record = (master_record_t *)record_data;
644 comp_values[0] = comp_values[0] >> comp_values[1];
645 if ( (comp_values[0] >= record->block_start) && (comp_values[0] <= record->block_end) ) {
646 comp_values[1] = comp_values[0];
647 } else {
648 // force "not equal"
649 comp_values[1] = comp_values[0] + 1;
650 }
651 #else
652 comp_values[1] = 0;
653 #endif
654
655 } // End of pblock_function
656
657