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