cidrmergerb 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/README.md +23 -0
- data/Rakefile +16 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/cidrmergerb.gemspec +26 -0
- data/ffi/Makefile +28 -0
- data/ffi/cidrmerge.h +153 -0
- data/ffi/libcidrmerge.c +529 -0
- data/ffi/optimized-sort.h +292 -0
- data/lib/cidrmergerb/ext.rb +29 -0
- data/lib/cidrmergerb/version.rb +3 -0
- data/lib/cidrmergerb.rb +61 -0
- metadata +120 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: fa2864f0fa01c1ad5efb023dd31341ae702e5bd0
|
4
|
+
data.tar.gz: 025f66ca2d5806b2b06897c6647781e81814d4cc
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 568ae27b383f662a0445f398a95b973fcf8a121896a0b0cdc1b42f60060c9879ddce7182eed7d34fd2c8708b29bd07207ced35d6dbd939156bcd13abbd0ea005
|
7
|
+
data.tar.gz: c5428103188e353dc4d164c89f25f2daa7ae45d6d5325f3b9de3f7d49464ace3ad9cad5571cfbd60bc445dd9d3167b1043026e3ff0c7a2d53e13c4c09d0bb9bd
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# Cidrmergerb
|
2
|
+
|
3
|
+
CIDR Optimize toolkit -- wrapping for Daniele's cidr optimization awesome library
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'cidrmergerb'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install cidrmergerb
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
Cidrmergerb.optimize(cidrs) #=> optimized cidrs
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rake/testtask"
|
3
|
+
|
4
|
+
Rake::TestTask.new(:test) do |t|
|
5
|
+
t.libs << "test"
|
6
|
+
t.libs << "lib"
|
7
|
+
t.test_files = FileList['test/**/*_test.rb']
|
8
|
+
end
|
9
|
+
|
10
|
+
desc "clean shared library"
|
11
|
+
task :clean_library do
|
12
|
+
FileUtils.cd(File.join(File.dirname(__FILE__), 'ext/cidrmergerb'))
|
13
|
+
%x{make clean}
|
14
|
+
end
|
15
|
+
|
16
|
+
task :default => [:clean_library, :spec]
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "cidrmergerb"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/cidrmergerb.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'cidrmergerb/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "cidrmergerb"
|
8
|
+
spec.version = Cidrmergerb::VERSION
|
9
|
+
spec.authors = ["Newell Zhu"]
|
10
|
+
spec.email = ["newell.zhu@kingaxis.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{CIDR Merge toolkit -- Wrapping for Daniele's CIDR Optimization library.}
|
13
|
+
spec.description = %q{CIDR Merge toolkit -- Wrapping for Daniele's CIDR Optimization library.}
|
14
|
+
spec.homepage = "https://github.com/kingaxis/cidrmergerb"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
spec.bindir = "exe"
|
18
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_runtime_dependency "ffi", '~> 1.9', '>= 1.9.10'
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.11"
|
24
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
25
|
+
spec.add_development_dependency "minitest", "~> 5.0"
|
26
|
+
end
|
data/ffi/Makefile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
#Compiler command
|
2
|
+
UNAME_S := $(shell uname -s)
|
3
|
+
ifeq ($(UNAME_S),Linux)
|
4
|
+
CC=gcc
|
5
|
+
LIBRARY_FLAGS=-shared -lc -ldl -Wl,-soname,liboptimize.so.1
|
6
|
+
endif
|
7
|
+
ifeq ($(UNAME_S),Darwin)
|
8
|
+
CC=g++
|
9
|
+
LIBRARY_FLAGS=-shared
|
10
|
+
endif
|
11
|
+
|
12
|
+
CC_FLAGS=-O3 -fPIC -g -c -Wall -W
|
13
|
+
CC_FLAGS+= -ansi -pedantic
|
14
|
+
STD_DEFINES=-D OPTIMIZED_SORT -D INLINE -D CHAR_PREFIX
|
15
|
+
|
16
|
+
all: libcidrmerge.so.1.5.3
|
17
|
+
|
18
|
+
libcidrmerge.o : libcidrmerge.c cidrmerge.h
|
19
|
+
gcc ${STD_DEFINES} ${DEBUG_DEFINES} ${CC_FLAGS} -c libcidrmerge.c
|
20
|
+
|
21
|
+
libcidrmerge.so.1.5.3 : libcidrmerge.o
|
22
|
+
${CC} ${LIBRARY_FLAGS} -o libcidrmerge.so libcidrmerge.o
|
23
|
+
|
24
|
+
clean :
|
25
|
+
rm -f *.o core
|
26
|
+
rm -f libcidrmerge.so
|
27
|
+
rm -f timestamp.out gmon.out
|
28
|
+
|
data/ffi/cidrmerge.h
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
/*
|
2
|
+
Copyright 2004-2008 Daniele Depetrini
|
3
|
+
Author: Daniele Depetrini (depetrini@libero.it)
|
4
|
+
Version: 1.5.3
|
5
|
+
Date: 07/07/08
|
6
|
+
|
7
|
+
This file is part of cidrmerge.
|
8
|
+
|
9
|
+
CIDRMerge is free software; you can redistribute it and/or modify
|
10
|
+
it under the terms of the GNU General Public License as published by
|
11
|
+
the Free Software Foundation; either version 2 of the License, or
|
12
|
+
(at your option) any later version.
|
13
|
+
|
14
|
+
CIDRMerge is distributed in the hope that it will be useful,
|
15
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
17
|
+
GNU General Public License for more details.
|
18
|
+
|
19
|
+
You should have received a copy of the GNU General Public License
|
20
|
+
along with cidrmerge; if not, write to the Free Software
|
21
|
+
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
22
|
+
|
23
|
+
*/
|
24
|
+
|
25
|
+
#ifndef CIDRMERGE
|
26
|
+
#define CIDRMERGE
|
27
|
+
|
28
|
+
#include <stdio.h>
|
29
|
+
|
30
|
+
#ifdef UNIX_IO
|
31
|
+
#include <unistd.h>
|
32
|
+
#include <sys/types.h>
|
33
|
+
#include <sys/stat.h>
|
34
|
+
#include <fcntl.h>
|
35
|
+
|
36
|
+
#define STREAM int
|
37
|
+
#define STDIN 0
|
38
|
+
#define STDOUT 1
|
39
|
+
#define STDERR 2
|
40
|
+
|
41
|
+
#define READ(f,b,n) read(f,b,n)
|
42
|
+
#define WRITE(f,b,n) write(f,b,n)
|
43
|
+
#define OPEN(name) open(name,O_RDONLY)
|
44
|
+
#define CLOSE(f) close(f)
|
45
|
+
#define N_EOF(f,ret) (ret==0)
|
46
|
+
|
47
|
+
#else
|
48
|
+
|
49
|
+
#define STREAM FILE *
|
50
|
+
#define STDIN (stdin)
|
51
|
+
#define STDOUT (stdout)
|
52
|
+
#define STDERR (stderr)
|
53
|
+
|
54
|
+
#define READ(f,b,n) fread(b,1,n,f)
|
55
|
+
#define WRITE(f,b,n) fwrite(b,1,n,f)
|
56
|
+
#define OPEN(name) fopen(name,"r")
|
57
|
+
#define CLOSE(f) fclose(f)
|
58
|
+
#define N_EOF(f,ret) feof(f)
|
59
|
+
|
60
|
+
#endif
|
61
|
+
|
62
|
+
#ifdef TIMESTAMP
|
63
|
+
#include <sys/time.h>
|
64
|
+
#include <time.h>
|
65
|
+
#endif
|
66
|
+
|
67
|
+
#include <stdlib.h>
|
68
|
+
#include <string.h>
|
69
|
+
#include <stdint.h>
|
70
|
+
|
71
|
+
#define MAXLINE 1023
|
72
|
+
#define BUFFER 8192*8
|
73
|
+
|
74
|
+
/* Allocate BUCKET array entries per time */
|
75
|
+
#define BUCKET 100000
|
76
|
+
#define MAXCIDR 23
|
77
|
+
|
78
|
+
/*Special prefix values.
|
79
|
+
Important: INVALID_PREFIX must be < EXPANDED_PREFIX.
|
80
|
+
EXPANDED_PREFIX + 32 must be < 255
|
81
|
+
*/
|
82
|
+
#define INVALID_PREFIX 200
|
83
|
+
#define EXPANDED_PREFIX 220
|
84
|
+
|
85
|
+
#define MASK1 0xff000000
|
86
|
+
#define MASK2 0xff0000
|
87
|
+
#define MASK3 0xff00
|
88
|
+
#define MASK4 0xff
|
89
|
+
|
90
|
+
#ifndef MAXINT
|
91
|
+
#define MAXINT 0xffffffff
|
92
|
+
#endif
|
93
|
+
|
94
|
+
/* timestamping precision definitions */
|
95
|
+
#define PRECISION (1000)
|
96
|
+
#define PRECISION_INV (1000000/PRECISION)
|
97
|
+
#define PRECISION_STRING "milliseconds"
|
98
|
+
|
99
|
+
struct entry
|
100
|
+
{
|
101
|
+
uint32_t network;
|
102
|
+
#ifdef CHAR_PREFIX
|
103
|
+
unsigned char prefix;
|
104
|
+
#else
|
105
|
+
uint32_t prefix;
|
106
|
+
#endif
|
107
|
+
};
|
108
|
+
|
109
|
+
static uint32_t prefix_table[]= {
|
110
|
+
0x0,0x80000000,0xc0000000,0xe0000000,0xf0000000,0xf8000000,0xfc000000,0xfe000000,0xff000000,0xff800000,
|
111
|
+
0xffc00000,0xffe00000,0xfff00000,0xfff80000,0xfffc0000,0xfffe0000,0xffff0000,0xffff8000,0xffffc000,
|
112
|
+
0xffffe000,0xfffff000,0xfffff800,0xfffffc00,0xfffffe00,0xffffff00,0xffffff80,0xffffffc0,0xffffffe0,
|
113
|
+
0xfffffff0,0xfffffff8,0xfffffffc,0xfffffffe,0xffffffff
|
114
|
+
};
|
115
|
+
|
116
|
+
/*#define TONETMASK(PREFIX) (((PREFIX)==0)?(0):(MAXINT<<(32-(PREFIX))))*/
|
117
|
+
#define TONETMASK(PREFIX) prefix_table[PREFIX]
|
118
|
+
|
119
|
+
/*
|
120
|
+
Function execute the reduction of entry array addr.It returns the number of entries in the final array.
|
121
|
+
PARAM: addr array: contains entries to be optimized
|
122
|
+
PARAM: len: number of entries into addr array.
|
123
|
+
PARAM: do_sort: if 0, sort will NOT be perfomed. Be carefull: optimizing a non-sorted input will produce unpredictable results
|
124
|
+
NOTE3: resulting array may contains entries with prefix bigger than EXPANDED_PREFIX. Those are logical pointers: expanded_list[entry.network] (array returned by apply_whitelist function) is the starting position and the leght is entry.prefix- EXPANDED_PREFIX
|
125
|
+
*/
|
126
|
+
unsigned int optimize(struct entry *addr,unsigned int len,int do_sort);
|
127
|
+
|
128
|
+
/*
|
129
|
+
Remove from array *entry_list occurence of array white.
|
130
|
+
Returns number of element into output array expanded_list (that can be reassigned to allow array extension).
|
131
|
+
Function allocate more memory if needed. It does NOT deallocate any if the result is smaller.
|
132
|
+
PARAM: *entry_list: pointer to input/output param entry list.
|
133
|
+
PARAM: **expanded_list: pointer to output param entry list, used to store expanded networks.
|
134
|
+
PARAM: *white: white list entry array
|
135
|
+
PARAM: len1: number of entry into entry_list in input
|
136
|
+
PARAM: len2: number of entry into white_list in input
|
137
|
+
PARAM: size_expanded: return paramether that contains memory size of the output expanded_list array
|
138
|
+
PARAM: do_sort: if 0, sort will NOT be perfomed on both entry_list and white. Be carefull: optimizing a non-sorted input will produce unpredictable results
|
139
|
+
NOTE1: both arrays entry_list and white have to be sorted with sort_entries() function BEFORE calling this.function OR paramether do_sort needs to be set to non zero. Unpredictable results if not
|
140
|
+
NOTE2: resulting array may contains entries with INVALID_PREFIX value prefix. This means entry is invalid and it doesn't have to be taken into account.
|
141
|
+
NOTE3: resulting array may contains entries with prefix bigger than EXPANDED_PREFIX. Those are logical pointers: expanded_list[entry.network] is the starting position and the leght is entry.prefix- EXPANDED_PREFIX
|
142
|
+
NOTE4: resulning array is ordered apart from invalid entries (the ones with INVALID_PREFIX value in prefix)
|
143
|
+
*/
|
144
|
+
unsigned int apply_whitelist(struct entry *addr,struct entry **expanded_list,struct entry *white,unsigned int len1,unsigned int len2,unsigned int *size_expanded,int do_sort);
|
145
|
+
|
146
|
+
/*
|
147
|
+
Execute entries sorting using quicksort.
|
148
|
+
PARAM: addr array: contains entries to be sorted
|
149
|
+
PARAM: len: number of entries into addr array.
|
150
|
+
*/
|
151
|
+
void sort_entries(struct entry *addr,unsigned int len);
|
152
|
+
|
153
|
+
#endif
|
data/ffi/libcidrmerge.c
ADDED
@@ -0,0 +1,529 @@
|
|
1
|
+
/*
|
2
|
+
Copyright 2004-2008 Daniele Depetrini
|
3
|
+
Author: Daniele Depetrini (depetrini@libero.it)
|
4
|
+
Version: 1.5.3
|
5
|
+
Date: 06/07/08
|
6
|
+
|
7
|
+
This file is part of CIDRMerge.
|
8
|
+
|
9
|
+
CIDRMerge is free software; you can redistribute it and/or modify
|
10
|
+
it under the terms of the GNU General Public License as published by
|
11
|
+
the Free Software Foundation; either version 2 of the License, or
|
12
|
+
(at your option) any later version.
|
13
|
+
|
14
|
+
CIDRMerge is distributed in the hope that it will be useful,
|
15
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
17
|
+
GNU General Public License for more details.
|
18
|
+
|
19
|
+
You should have received a copy of the GNU General Public License
|
20
|
+
along with CIDRMerge; if not, write to the Free Software
|
21
|
+
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
22
|
+
|
23
|
+
*/
|
24
|
+
|
25
|
+
#include "cidrmerge.h"
|
26
|
+
|
27
|
+
#ifdef LIBRARY_DEBUG
|
28
|
+
#include <stdarg.h>
|
29
|
+
|
30
|
+
/* Using those functions from cidrmerge.c for debugging purposes only */
|
31
|
+
void print_address(STREAM file,uint32_t net, unsigned char pref);
|
32
|
+
void print_addresses(STREAM f,struct entry *addr,int size,struct entry *expanded,int level);
|
33
|
+
|
34
|
+
void print_debug(STREAM f,char *buf,char *fmt,...)
|
35
|
+
{
|
36
|
+
va_list ap;
|
37
|
+
va_start(ap, fmt);
|
38
|
+
sprintf(buf,fmt,ap);
|
39
|
+
WRITE(f,buf,strlen(buf));
|
40
|
+
va_end(ap);
|
41
|
+
}
|
42
|
+
|
43
|
+
#endif
|
44
|
+
/*
|
45
|
+
Exectute one entry comparation. a1 is bigger than a2 if:
|
46
|
+
- a1.network is bigger than a2.network
|
47
|
+
- a1.network is equal to a2.network but a1.prefix is bigger than a2.prefix
|
48
|
+
PARAM: a1 first entry
|
49
|
+
PARAM: a2 second entry
|
50
|
+
RETURN VALUE: it returns -1 if a1<a2, 0 if a1=a2 and 1 if a1>a2
|
51
|
+
*/
|
52
|
+
#ifndef OPTIMIZED_SORT
|
53
|
+
typedef int(*cmp_type)(const void *,const void*);
|
54
|
+
|
55
|
+
static int cmp_entry(struct entry *a1, struct entry *a2)
|
56
|
+
{
|
57
|
+
if ((*a1).network<(*a2).network)
|
58
|
+
{
|
59
|
+
return -1;
|
60
|
+
}
|
61
|
+
if ((*a1).network>(*a2).network)
|
62
|
+
{
|
63
|
+
return 1;
|
64
|
+
}
|
65
|
+
/* Network are ==, so we compare netmasks*/
|
66
|
+
if ((*a1).prefix<(*a2).prefix)
|
67
|
+
{
|
68
|
+
return -1;
|
69
|
+
}
|
70
|
+
if ((*a1).prefix>(*a2).prefix)
|
71
|
+
{
|
72
|
+
return 1;
|
73
|
+
}
|
74
|
+
|
75
|
+
return 0;
|
76
|
+
}
|
77
|
+
#endif
|
78
|
+
|
79
|
+
/*
|
80
|
+
Please see cidrmerge.h
|
81
|
+
*/
|
82
|
+
void sort_entries(struct entry *addr,unsigned int len)
|
83
|
+
{
|
84
|
+
#ifndef OPTIMIZED_SORT
|
85
|
+
/*standard C quicksort*/
|
86
|
+
qsort(addr,len,sizeof(struct entry),(cmp_type)cmp_entry);
|
87
|
+
#else
|
88
|
+
/*Optimized quicksort. Thanks to Michael Tokarev*/
|
89
|
+
#include "optimized-sort.h"
|
90
|
+
#define cmp_entry(a1,a2) (((a1)->network<(a2)->network) || (((a1)->network==(a2)->network) && ((a1)->prefix<(a2)->prefix)))
|
91
|
+
|
92
|
+
if (len>1)
|
93
|
+
{
|
94
|
+
/*sprintf(debug_buf,"SORT: addr[0] %d len %d\n",addr[0].network,len);*/
|
95
|
+
QSORT(struct entry,addr,len,cmp_entry);
|
96
|
+
}
|
97
|
+
#endif
|
98
|
+
}
|
99
|
+
|
100
|
+
#ifdef INLINE
|
101
|
+
__inline
|
102
|
+
#endif
|
103
|
+
static void expand(struct entry **expanded_list,struct entry to_expand,struct entry *white,unsigned int len_white,unsigned int n,unsigned int *current_position,unsigned int *size_expanded)
|
104
|
+
{
|
105
|
+
int first=*current_position,last=*current_position+n-1;
|
106
|
+
unsigned int first_conflict,last_conflict,i;
|
107
|
+
struct entry tmp_small,tmp_big;
|
108
|
+
struct entry *result=*expanded_list;
|
109
|
+
#ifdef LIBRARY_DEBUG
|
110
|
+
char debug_buf[MAXLINE];
|
111
|
+
#endif
|
112
|
+
|
113
|
+
*current_position+=n;
|
114
|
+
|
115
|
+
if (*current_position>*size_expanded)
|
116
|
+
{
|
117
|
+
/* we need to increase expanded_list array size */
|
118
|
+
#ifdef LIBRARY_DEBUG
|
119
|
+
print_debug(STDOUT,debug_buf,"BEFORE realloc: size_expanded: %u, MEM: %u\n", *size_expanded,(*size_expanded)*sizeof(struct entry));
|
120
|
+
#endif
|
121
|
+
|
122
|
+
*size_expanded+=BUCKET;
|
123
|
+
#ifdef LIBRARY_DEBUG
|
124
|
+
print_debug(STDOUT,debug_buf,"AFTER realloc size_expanded: %u,MEM: %u\n", *size_expanded,(*size_expanded)*sizeof(struct entry));
|
125
|
+
#endif
|
126
|
+
|
127
|
+
result=*expanded_list=realloc(*expanded_list,(*size_expanded)*sizeof(struct entry));
|
128
|
+
if (result==NULL)
|
129
|
+
{
|
130
|
+
fprintf(stderr,"Error reallocating %lu bytes\n",(unsigned long)(*size_expanded)*sizeof(struct entry));
|
131
|
+
exit(1);
|
132
|
+
}
|
133
|
+
}
|
134
|
+
|
135
|
+
#ifdef LIBRARY_DEBUG
|
136
|
+
print_debug(STDOUT,debug_buf,"\nTO EXPAND n %u:\n",n);
|
137
|
+
print_address(STDOUT,to_expand.network,to_expand.prefix);
|
138
|
+
|
139
|
+
print_debug(STDOUT,debug_buf,"START WHITE len_white %u:\n",len_white);
|
140
|
+
print_addresses(STDOUT,white,len_white,NULL,0);
|
141
|
+
print_debug(STDOUT,debug_buf,"END WHITE\n");
|
142
|
+
#endif
|
143
|
+
|
144
|
+
while (first<=last)
|
145
|
+
{
|
146
|
+
tmp_small.prefix=tmp_big.prefix=to_expand.prefix+1;
|
147
|
+
tmp_small.network=to_expand.network; /*last network bit set to 0 */
|
148
|
+
tmp_big.network=to_expand.network+(0x1<<(32-tmp_small.prefix)); /*last network bit set to 1 */
|
149
|
+
|
150
|
+
if ( (white[0].network & TONETMASK(tmp_small.prefix) ) == tmp_small.network )
|
151
|
+
{
|
152
|
+
/* conflicting whith tmp_small. */
|
153
|
+
i=1;
|
154
|
+
/* search for first conflicting position with tmp_big (it cant be the first) */
|
155
|
+
while((i<len_white) && !( (white[i].network & TONETMASK(tmp_big.prefix) ) == tmp_big.network ))
|
156
|
+
{
|
157
|
+
i++;
|
158
|
+
}
|
159
|
+
first_conflict=i;
|
160
|
+
/* search for last conflicting position with tmp_big*/
|
161
|
+
while((i<len_white) && ( (white[i].network & TONETMASK(tmp_big.prefix) ) == tmp_big.network ))
|
162
|
+
{
|
163
|
+
i++;
|
164
|
+
}
|
165
|
+
last_conflict=i;
|
166
|
+
/* check if there is at least one conflicting with tmp_big network into whitelist */
|
167
|
+
if (first_conflict!=len_white)
|
168
|
+
{
|
169
|
+
if (white[first_conflict].prefix!=tmp_big.prefix)
|
170
|
+
{
|
171
|
+
|
172
|
+
#ifdef LIBRARY_DEBUG
|
173
|
+
print_debug(STDOUT,debug_buf,"RE-CONFLICT BIG first %u last %u\n",first_conflict,last_conflict);
|
174
|
+
print_address(STDOUT,tmp_big.network,tmp_big.prefix);
|
175
|
+
#endif
|
176
|
+
|
177
|
+
result[last].network=*current_position;
|
178
|
+
result[last].prefix=EXPANDED_PREFIX+white[first_conflict].prefix-tmp_big.prefix;
|
179
|
+
|
180
|
+
expand(expanded_list,tmp_big,&white[first_conflict],last_conflict-first_conflict,white[first_conflict].prefix-tmp_big.prefix,current_position,size_expanded);
|
181
|
+
}
|
182
|
+
else
|
183
|
+
{
|
184
|
+
#ifdef LIBRARY_DEBUG
|
185
|
+
print_debug(STDOUT,debug_buf,"INVALIDATING BIG POSITION %u\n",last);
|
186
|
+
#endif
|
187
|
+
result[last].prefix=INVALID_PREFIX;
|
188
|
+
}
|
189
|
+
}
|
190
|
+
else
|
191
|
+
{
|
192
|
+
#ifdef LIBRARY_DEBUG
|
193
|
+
print_debug(STDOUT,debug_buf,"VALID BIG position %u:\n",last);
|
194
|
+
print_address(STDOUT,tmp_big.network,tmp_big.prefix);
|
195
|
+
#endif
|
196
|
+
result[last].network=tmp_big.network;
|
197
|
+
result[last].prefix=tmp_big.prefix;
|
198
|
+
}
|
199
|
+
to_expand.network=tmp_small.network;
|
200
|
+
to_expand.prefix=tmp_small.prefix;
|
201
|
+
last--;
|
202
|
+
}
|
203
|
+
else
|
204
|
+
{
|
205
|
+
/* conflicting with tmp_big */
|
206
|
+
i=1;
|
207
|
+
/* search for first conflicting position with tmp_small (it cant be the first)*/
|
208
|
+
while((i<len_white) && !( (white[i].network & TONETMASK(tmp_small.prefix) ) == tmp_small.network ))
|
209
|
+
{
|
210
|
+
i++;
|
211
|
+
}
|
212
|
+
first_conflict=i;
|
213
|
+
/* search for last conflicting position with tmp_small*/
|
214
|
+
while((i<len_white) && ( (white[i].network & TONETMASK(tmp_small.prefix) ) == tmp_small.network ))
|
215
|
+
{
|
216
|
+
i++;
|
217
|
+
}
|
218
|
+
last_conflict=i;
|
219
|
+
|
220
|
+
/* check if there is at least one conflicting with tmp_small network into whitelist */
|
221
|
+
if (first_conflict!=len_white)
|
222
|
+
{
|
223
|
+
if (white[first_conflict].prefix!=tmp_small.prefix)
|
224
|
+
{
|
225
|
+
#ifdef LIBRARY_DEBUG
|
226
|
+
print_debug(STDOUT,debug_buf,"RE-CONFLICT LOW first %u last %u\n",first_conflict,last_conflict);
|
227
|
+
print_address(STDOUT,tmp_small.network,tmp_small.prefix);
|
228
|
+
#endif
|
229
|
+
|
230
|
+
result[first].network=*current_position;
|
231
|
+
result[first].prefix=EXPANDED_PREFIX+white[first_conflict].prefix-tmp_small.prefix;
|
232
|
+
|
233
|
+
expand(expanded_list,tmp_small,&white[first_conflict],last_conflict-first_conflict,white[first_conflict].prefix-tmp_small.prefix,current_position,size_expanded);
|
234
|
+
}
|
235
|
+
else
|
236
|
+
{
|
237
|
+
#ifdef LIBRARY_DEBUG
|
238
|
+
print_debug(STDOUT,debug_buf,"INVALIDATING LOW POSITION %u\n",first);
|
239
|
+
#endif
|
240
|
+
result[first].prefix=INVALID_PREFIX;
|
241
|
+
}
|
242
|
+
}
|
243
|
+
else
|
244
|
+
{
|
245
|
+
#ifdef LIBRARY_DEBUG
|
246
|
+
print_debug(STDOUT,debug_buf,"VALID LOW position %u:\n",first);
|
247
|
+
print_address(STDOUT,tmp_small.network,tmp_small.prefix);
|
248
|
+
#endif
|
249
|
+
|
250
|
+
result[first].network=tmp_small.network;
|
251
|
+
result[first].prefix=tmp_small.prefix;
|
252
|
+
}
|
253
|
+
to_expand.network=tmp_big.network;
|
254
|
+
to_expand.prefix=tmp_big.prefix;
|
255
|
+
first++;
|
256
|
+
}
|
257
|
+
|
258
|
+
#ifdef LIBRARY_DEBUG
|
259
|
+
print_debug(STDOUT,debug_buf,"first %d last %d\n",first,last);
|
260
|
+
#endif
|
261
|
+
}
|
262
|
+
|
263
|
+
#ifdef LIBRARY_DEBUG
|
264
|
+
print_debug(STDOUT,debug_buf,"EXPAND END. Local position %d, current position %u:\n",n,*current_position);
|
265
|
+
print_debug(STDOUT,debug_buf,"\n");
|
266
|
+
#endif
|
267
|
+
}
|
268
|
+
|
269
|
+
/*
|
270
|
+
Please see cidrmerge.h
|
271
|
+
*/
|
272
|
+
unsigned int apply_whitelist(struct entry *addr,struct entry **expanded_list,struct entry *white,unsigned int len1,unsigned int len2,unsigned int *size_expanded,int do_sort)
|
273
|
+
{
|
274
|
+
unsigned int i1,i2,invalid,tmp,expanded_index=0;
|
275
|
+
uint32_t supermask;
|
276
|
+
struct entry tmp_entry;
|
277
|
+
#ifdef LIBRARY_DEBUG
|
278
|
+
char debug_buf[MAXLINE];
|
279
|
+
unsigned int step=0;
|
280
|
+
print_debug(STDOUT,debug_buf,"START apply_whitelist\n");
|
281
|
+
#endif
|
282
|
+
|
283
|
+
|
284
|
+
if (do_sort)
|
285
|
+
{
|
286
|
+
#ifdef LIBRARY_DEBUG
|
287
|
+
print_debug(STDOUT,debug_buf,"Sorting entries\n");
|
288
|
+
#endif
|
289
|
+
sort_entries(addr,len1);
|
290
|
+
sort_entries(white,len2);
|
291
|
+
}
|
292
|
+
|
293
|
+
i1=i2=0;
|
294
|
+
while ((i1<len1)&&(i2<len2))
|
295
|
+
{
|
296
|
+
#ifdef LIBRARY_DEBUG
|
297
|
+
print_debug(STDOUT,debug_buf,"STEP=%u I1=%d I2=%d\n",step++,i1,i2);
|
298
|
+
#endif
|
299
|
+
#ifdef LIBRARY_DEBUG_FULL
|
300
|
+
print_addresses(STDOUT,addr,len1,NULL,0);
|
301
|
+
#endif
|
302
|
+
|
303
|
+
supermask=TONETMASK(addr[i1].prefix)&TONETMASK(white[i2].prefix);
|
304
|
+
|
305
|
+
if ((addr[i1].prefix<=32)&&(addr[i1].network&supermask)==(white[i2].network&supermask))
|
306
|
+
{
|
307
|
+
#ifdef LIBRARY_DEBUG
|
308
|
+
print_debug(STDOUT,debug_buf,"CONFLICT\n");
|
309
|
+
print_address(STDOUT,addr[i1].network,addr[i1].prefix);
|
310
|
+
print_address(STDOUT,white[i2].network,white[i2].prefix);
|
311
|
+
#endif
|
312
|
+
if (addr[i1].prefix<white[i2].prefix)
|
313
|
+
{
|
314
|
+
/*we have to expand the network*/
|
315
|
+
|
316
|
+
/*invalidate all addr[i1] subnetworks */
|
317
|
+
invalid=i1+1;
|
318
|
+
while ((invalid<len1)&&(addr[invalid].network&supermask)==(white[i2].network&supermask))
|
319
|
+
{
|
320
|
+
/*address is already present in the expanded network, just drop it*/
|
321
|
+
#ifdef LIBRARY_DEBUG
|
322
|
+
print_debug(STDOUT,debug_buf,"INVALIDATING ");
|
323
|
+
print_address(STDOUT,addr[invalid].network,addr[invalid].prefix);
|
324
|
+
#endif
|
325
|
+
addr[invalid].prefix=INVALID_PREFIX;
|
326
|
+
|
327
|
+
invalid++;
|
328
|
+
}
|
329
|
+
|
330
|
+
invalid-=i1+1; /*invalid represents the number of invalidated positions*/
|
331
|
+
|
332
|
+
#ifdef LIBRARY_DEBUG
|
333
|
+
print_debug(STDOUT,debug_buf,"INVALID %u LEN1 %u\n",invalid,len1);
|
334
|
+
#endif
|
335
|
+
|
336
|
+
tmp=i2;
|
337
|
+
i2+=1;
|
338
|
+
while ( (i2<len2) && ((addr[i1].network&supermask)==(white[i2].network&supermask)) )
|
339
|
+
{
|
340
|
+
i2++;
|
341
|
+
}
|
342
|
+
|
343
|
+
#ifdef LIBRARY_DEBUG
|
344
|
+
print_debug(STDOUT,debug_buf,"EXPAND expanded_index %u whitelist elements: %u num expand %d\n",expanded_index,i2-tmp,white[tmp].prefix-addr[i1].prefix);
|
345
|
+
#endif
|
346
|
+
|
347
|
+
tmp_entry.network=addr[i1].network;
|
348
|
+
tmp_entry.prefix=addr[i1].prefix;
|
349
|
+
|
350
|
+
addr[i1].prefix=EXPANDED_PREFIX+white[tmp].prefix-addr[i1].prefix;
|
351
|
+
addr[i1].network=expanded_index;
|
352
|
+
/* expanded positions are clean and optimized */
|
353
|
+
expand(expanded_list,tmp_entry,&(white[tmp]),i2-tmp,white[tmp].prefix-tmp_entry.prefix,&expanded_index,size_expanded);
|
354
|
+
|
355
|
+
i1+=invalid+1;
|
356
|
+
|
357
|
+
#ifdef LIBRARY_DEBUG
|
358
|
+
print_debug(STDOUT,debug_buf,"END MAIN EXPAND expanded_index %u i1: %u i2: %u\n",expanded_index,i1,i2);
|
359
|
+
#endif
|
360
|
+
|
361
|
+
}
|
362
|
+
else
|
363
|
+
{
|
364
|
+
/*just invalidating entry i1*/
|
365
|
+
#ifdef LIBRARY_DEBUG
|
366
|
+
printf ("INVALIDATING ");
|
367
|
+
print_address(STDOUT,addr[i1].network,addr[i1].prefix);
|
368
|
+
#endif
|
369
|
+
addr[i1].prefix=INVALID_PREFIX;
|
370
|
+
i1++;
|
371
|
+
}
|
372
|
+
|
373
|
+
}
|
374
|
+
else if ((addr[i1].prefix==INVALID_PREFIX)||(addr[i1].network&supermask)<=(white[i2].network&supermask))
|
375
|
+
{
|
376
|
+
i1++;
|
377
|
+
}
|
378
|
+
else
|
379
|
+
{
|
380
|
+
i2++;
|
381
|
+
}
|
382
|
+
}
|
383
|
+
#ifdef LIBRARY_DEBUG
|
384
|
+
print_debug(STDOUT,debug_buf,"END apply_whitelist\n");
|
385
|
+
#endif
|
386
|
+
return expanded_index;
|
387
|
+
}
|
388
|
+
|
389
|
+
/*
|
390
|
+
Please see cidrmerge.h
|
391
|
+
*/
|
392
|
+
unsigned int optimize(struct entry *addr,unsigned int len,int do_sort)
|
393
|
+
{
|
394
|
+
unsigned int i,cur;
|
395
|
+
unsigned int tmp_net;
|
396
|
+
#ifdef LIBRARY_DEBUG
|
397
|
+
char debug_buf[MAXLINE];
|
398
|
+
unsigned int step=0;
|
399
|
+
|
400
|
+
print_debug(STDOUT,debug_buf,"START optimize\n");
|
401
|
+
#endif
|
402
|
+
|
403
|
+
i=0; /*pointer to last valid position*/
|
404
|
+
cur=1; /*pointer to next addr to analize*/
|
405
|
+
|
406
|
+
if (len <= 1)
|
407
|
+
{
|
408
|
+
/* empty or sigle element array is optimized by definition.*/
|
409
|
+
return len;
|
410
|
+
}
|
411
|
+
|
412
|
+
if (do_sort)
|
413
|
+
{
|
414
|
+
sort_entries(addr,len);
|
415
|
+
}
|
416
|
+
|
417
|
+
/*Find first valid address and move it to first position*/
|
418
|
+
while ((addr[0].prefix==INVALID_PREFIX) && (cur<len))
|
419
|
+
{
|
420
|
+
#ifdef LIBRARY_DEBUG
|
421
|
+
printf ("SEARCH FIRST I: %d CUR: %d\n",i,cur);
|
422
|
+
#endif
|
423
|
+
if (addr[cur].prefix!=INVALID_PREFIX)
|
424
|
+
{
|
425
|
+
addr[0].network=addr[cur].network;
|
426
|
+
addr[0].prefix=addr[cur].prefix;
|
427
|
+
addr[cur].prefix=INVALID_PREFIX;
|
428
|
+
}
|
429
|
+
cur++;
|
430
|
+
}
|
431
|
+
|
432
|
+
while (cur<len)
|
433
|
+
{
|
434
|
+
#ifdef LIBRARY_DEBUG
|
435
|
+
printf ("STEP: %u I: %d CUR: %d\n",step++,i,cur);
|
436
|
+
#endif
|
437
|
+
#ifdef LIBRARY_DEBUG_FULL
|
438
|
+
print_addresses(STDOUT,addr,len,NULL,0);
|
439
|
+
#endif
|
440
|
+
|
441
|
+
/*check for expanded networks, they can never conflicts*/
|
442
|
+
if (addr[cur].prefix>=EXPANDED_PREFIX)
|
443
|
+
{
|
444
|
+
#ifdef LIBRARY_DEBUG
|
445
|
+
printf ("COPY EXPANDED I: %d CUR: %d\n",i,cur);
|
446
|
+
#endif
|
447
|
+
i++;
|
448
|
+
addr[i].network=addr[cur].network;
|
449
|
+
addr[i].prefix=addr[cur].prefix;
|
450
|
+
cur++;
|
451
|
+
while ((addr[i].prefix>=EXPANDED_PREFIX) && (cur<len))
|
452
|
+
{
|
453
|
+
#ifdef LIBRARY_DEBUG
|
454
|
+
printf ("COPY ADDR[CUR] FOR EXPANDED I: %d CUR: %d\n",i,cur);
|
455
|
+
#endif
|
456
|
+
if (addr[cur].prefix!=INVALID_PREFIX)
|
457
|
+
{
|
458
|
+
i++;
|
459
|
+
if (cur != i)
|
460
|
+
{
|
461
|
+
addr[i].network=addr[cur].network;
|
462
|
+
addr[i].prefix=addr[cur].prefix;
|
463
|
+
addr[cur].prefix=INVALID_PREFIX;
|
464
|
+
}
|
465
|
+
}
|
466
|
+
cur++;
|
467
|
+
}
|
468
|
+
}
|
469
|
+
else
|
470
|
+
{
|
471
|
+
/*If this test will fail we just skip addr[cur]*/
|
472
|
+
if ((addr[cur].prefix<=32)&&((addr[cur].network&TONETMASK(addr[i].prefix))!=addr[i].network))
|
473
|
+
{
|
474
|
+
tmp_net=TONETMASK(addr[i].prefix-1);
|
475
|
+
|
476
|
+
if ( (addr[i].prefix==addr[cur].prefix) && ( (addr[i].network&tmp_net) == (addr[cur].network&tmp_net) ) )
|
477
|
+
{
|
478
|
+
#ifdef LIBRARY_DEBUG
|
479
|
+
printf ("COLLAPSE I: %d CUR: %d\n",i,cur);
|
480
|
+
#endif
|
481
|
+
|
482
|
+
if (i>0)
|
483
|
+
{
|
484
|
+
addr[cur].prefix=addr[i].prefix-1;
|
485
|
+
addr[cur].network&=tmp_net;
|
486
|
+
i--;
|
487
|
+
}
|
488
|
+
else
|
489
|
+
{
|
490
|
+
addr[i].prefix=addr[i].prefix-1;
|
491
|
+
addr[i].network&=tmp_net;
|
492
|
+
cur++;
|
493
|
+
}
|
494
|
+
}
|
495
|
+
else
|
496
|
+
{
|
497
|
+
i++;
|
498
|
+
|
499
|
+
addr[i].network=addr[cur].network;
|
500
|
+
addr[i].prefix=addr[cur].prefix;
|
501
|
+
|
502
|
+
cur++;
|
503
|
+
}
|
504
|
+
}
|
505
|
+
else
|
506
|
+
{
|
507
|
+
#ifdef LIBRARY_DEBUG
|
508
|
+
printf ("SKIP CUR: %d\n",cur);
|
509
|
+
#endif
|
510
|
+
|
511
|
+
cur++;
|
512
|
+
}
|
513
|
+
}
|
514
|
+
}
|
515
|
+
|
516
|
+
#ifdef LIBRARY_DEBUG
|
517
|
+
print_debug(STDOUT,debug_buf,"END optimize\n");
|
518
|
+
#endif
|
519
|
+
|
520
|
+
if (addr[i].prefix!=INVALID_PREFIX)
|
521
|
+
{
|
522
|
+
return i+1;
|
523
|
+
}
|
524
|
+
else
|
525
|
+
{
|
526
|
+
return i;
|
527
|
+
}
|
528
|
+
}
|
529
|
+
|
@@ -0,0 +1,292 @@
|
|
1
|
+
/* $Id: optimized-sort.h,v 1.1 2008/06/07 22:30:24 depetrini Exp $
|
2
|
+
* Adopted from GNU glibc by Mjt.
|
3
|
+
* See stdlib/qsort.c in glibc */
|
4
|
+
|
5
|
+
/* Copyright (C) 1991, 1992, 1996, 1997, 1999 Free Software Foundation, Inc.
|
6
|
+
This file is part of the GNU C Library.
|
7
|
+
Written by Douglas C. Schmidt (schmidt@ics.uci.edu).
|
8
|
+
|
9
|
+
The GNU C Library is free software; you can redistribute it and/or
|
10
|
+
modify it under the terms of the GNU Lesser General Public
|
11
|
+
License as published by the Free Software Foundation; either
|
12
|
+
version 2.1 of the License, or (at your option) any later version.
|
13
|
+
|
14
|
+
The GNU C Library is distributed in the hope that it will be useful,
|
15
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
17
|
+
Lesser General Public License for more details.
|
18
|
+
|
19
|
+
You should have received a copy of the GNU Lesser General Public
|
20
|
+
License along with the GNU C Library; if not, write to the Free
|
21
|
+
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
22
|
+
02111-1307 USA. */
|
23
|
+
|
24
|
+
/* in-line qsort implementation. Differs from traditional qsort() routine
|
25
|
+
* in that it is a macro, not a function, and instead of passing an address
|
26
|
+
* of a comparision routine to the function, it is possible to inline
|
27
|
+
* comparision routine, thus speed up sorting alot.
|
28
|
+
*
|
29
|
+
* Usage:
|
30
|
+
* #include "iqsort.h"
|
31
|
+
* #define islt(a,b) (strcmp((*a),(*b))<0)
|
32
|
+
* char *arr[];
|
33
|
+
* int n;
|
34
|
+
* QSORT(char*, arr, n, islt);
|
35
|
+
*
|
36
|
+
* The "prototype" and 4 arguments are:
|
37
|
+
* QSORT(TYPE,BASE,NELT,ISLT)
|
38
|
+
* 1) type of each element, TYPE,
|
39
|
+
* 2) address of the beginning of the array, of type TYPE*,
|
40
|
+
* 3) number of elements in the array, and
|
41
|
+
* 4) comparision routine.
|
42
|
+
* Array pointer and number of elements are referenced only once.
|
43
|
+
* This is similar to a call
|
44
|
+
* qsort(BASE,NELT,sizeof(TYPE),ISLT)
|
45
|
+
* with the difference in last parameter.
|
46
|
+
* Note the islt macro/routine (it receives pointers to two elements):
|
47
|
+
* the only condition of interest is whenever one element is less than
|
48
|
+
* another, no other conditions (greather than, equal to etc) are tested.
|
49
|
+
* So, for example, to define integer sort, use:
|
50
|
+
* #define islt(a,b) ((*a)<(*b))
|
51
|
+
* QSORT(int, arr, n, islt)
|
52
|
+
*
|
53
|
+
* The macro could be used to implement a sorting function (see examples
|
54
|
+
* below), or to implement the sorting algorithm inline. That is, either
|
55
|
+
* create a sorting function and use it whenever you want to sort something,
|
56
|
+
* or use QSORT() macro directly instead a call to such routine. Note that
|
57
|
+
* the macro expands to quite some code (compiled size of int qsort on x86
|
58
|
+
* is about 700..800 bytes).
|
59
|
+
*
|
60
|
+
* Using this macro directly it isn't possible to implement traditional
|
61
|
+
* qsort() routine, because the macro assumes sizeof(element) == sizeof(TYPE),
|
62
|
+
* while qsort() allows element size to be different.
|
63
|
+
*
|
64
|
+
* Several ready-to-use examples:
|
65
|
+
*
|
66
|
+
* Sorting array of integers:
|
67
|
+
* void int_qsort(int *arr, unsigned n) {
|
68
|
+
* #define int_lt(a,b) ((*a)<(*b))
|
69
|
+
* QSORT(int, arr, n, int_lt);
|
70
|
+
* }
|
71
|
+
*
|
72
|
+
* Sorting array of string pointers:
|
73
|
+
* void str_qsort(char *arr[], unsigned n) {
|
74
|
+
* #define str_lt(a,b) (strcmp((*a),(*b)) < 0)
|
75
|
+
* QSORT(char*, arr, n, str_lt);
|
76
|
+
* }
|
77
|
+
*
|
78
|
+
* Sorting array of structures:
|
79
|
+
*
|
80
|
+
* struct elt {
|
81
|
+
* int key;
|
82
|
+
* ...
|
83
|
+
* };
|
84
|
+
* void elt_qsort(struct elt *arr, unsigned n) {
|
85
|
+
* #define elt_lt(a,b) ((a)->key < (b)->key)
|
86
|
+
* QSORT(struct elt, arr, n, elt_lt);
|
87
|
+
* }
|
88
|
+
*
|
89
|
+
* And so on.
|
90
|
+
*/
|
91
|
+
|
92
|
+
/* Swap two items pointed to by A and B using temporary buffer t. */
|
93
|
+
#define _QSORT_SWAP(a, b, t) ((void)((t = *a), (*a = *b), (*b = t)))
|
94
|
+
|
95
|
+
/* Discontinue quicksort algorithm when partition gets below this size.
|
96
|
+
This particular magic number was chosen to work best on a Sun 4/260. */
|
97
|
+
#define _QSORT_MAX_THRESH 4
|
98
|
+
|
99
|
+
/* Stack node declarations used to store unfulfilled partition obligations
|
100
|
+
* (inlined in QSORT).
|
101
|
+
typedef struct {
|
102
|
+
QSORT_TYPE *_lo, *_hi;
|
103
|
+
} qsort_stack_node;
|
104
|
+
*/
|
105
|
+
|
106
|
+
/* The next 4 #defines implement a very fast in-line stack abstraction. */
|
107
|
+
/* The stack needs log (total_elements) entries (we could even subtract
|
108
|
+
log(MAX_THRESH)). Since total_elements has type unsigned, we get as
|
109
|
+
upper bound for log (total_elements):
|
110
|
+
bits per byte (CHAR_BIT) * sizeof(unsigned). */
|
111
|
+
#define _QSORT_STACK_SIZE (8 * sizeof(unsigned))
|
112
|
+
#define _QSORT_PUSH(top, low, high) \
|
113
|
+
(((top->_lo = (low)), (top->_hi = (high)), ++top))
|
114
|
+
#define _QSORT_POP(low, high, top) \
|
115
|
+
((--top, (low = top->_lo), (high = top->_hi)))
|
116
|
+
#define _QSORT_STACK_NOT_EMPTY (_stack < _top)
|
117
|
+
|
118
|
+
|
119
|
+
/* Order size using quicksort. This implementation incorporates
|
120
|
+
four optimizations discussed in Sedgewick:
|
121
|
+
|
122
|
+
1. Non-recursive, using an explicit stack of pointer that store the
|
123
|
+
next array partition to sort. To save time, this maximum amount
|
124
|
+
of space required to store an array of SIZE_MAX is allocated on the
|
125
|
+
stack. Assuming a 32-bit (64 bit) integer for size_t, this needs
|
126
|
+
only 32 * sizeof(stack_node) == 256 bytes (for 64 bit: 1024 bytes).
|
127
|
+
Pretty cheap, actually.
|
128
|
+
|
129
|
+
2. Chose the pivot element using a median-of-three decision tree.
|
130
|
+
This reduces the probability of selecting a bad pivot value and
|
131
|
+
eliminates certain extraneous comparisons.
|
132
|
+
|
133
|
+
3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving
|
134
|
+
insertion sort to order the MAX_THRESH items within each partition.
|
135
|
+
This is a big win, since insertion sort is faster for small, mostly
|
136
|
+
sorted array segments.
|
137
|
+
|
138
|
+
4. The larger of the two sub-partitions is always pushed onto the
|
139
|
+
stack first, with the algorithm then concentrating on the
|
140
|
+
smaller partition. This *guarantees* no more than log (total_elems)
|
141
|
+
stack size is needed (actually O(1) in this case)! */
|
142
|
+
|
143
|
+
/* The main code starts here... */
|
144
|
+
#define QSORT(QSORT_TYPE,QSORT_BASE,QSORT_NELT,QSORT_LT) \
|
145
|
+
{ \
|
146
|
+
QSORT_TYPE *const _base = (QSORT_BASE); \
|
147
|
+
const unsigned _elems = (QSORT_NELT); \
|
148
|
+
QSORT_TYPE _hold; \
|
149
|
+
\
|
150
|
+
/* Don't declare two variables of type QSORT_TYPE in a single \
|
151
|
+
* statement: eg `TYPE a, b;', in case if TYPE is a pointer, \
|
152
|
+
* expands to `type* a, b;' wich isn't what we want. \
|
153
|
+
*/ \
|
154
|
+
\
|
155
|
+
if (_elems > _QSORT_MAX_THRESH) { \
|
156
|
+
QSORT_TYPE *_lo = _base; \
|
157
|
+
QSORT_TYPE *_hi = _lo + _elems - 1; \
|
158
|
+
struct { \
|
159
|
+
QSORT_TYPE *_hi; QSORT_TYPE *_lo; \
|
160
|
+
} _stack[_QSORT_STACK_SIZE], *_top = _stack + 1; \
|
161
|
+
\
|
162
|
+
while (_QSORT_STACK_NOT_EMPTY) { \
|
163
|
+
QSORT_TYPE *_left_ptr; QSORT_TYPE *_right_ptr; \
|
164
|
+
\
|
165
|
+
/* Select median value from among LO, MID, and HI. Rearrange \
|
166
|
+
LO and HI so the three values are sorted. This lowers the \
|
167
|
+
probability of picking a pathological pivot value and \
|
168
|
+
skips a comparison for both the LEFT_PTR and RIGHT_PTR in \
|
169
|
+
the while loops. */ \
|
170
|
+
\
|
171
|
+
QSORT_TYPE *_mid = _lo + ((_hi - _lo) >> 1); \
|
172
|
+
\
|
173
|
+
if (QSORT_LT (_mid, _lo)) \
|
174
|
+
_QSORT_SWAP (_mid, _lo, _hold); \
|
175
|
+
if (QSORT_LT (_hi, _mid)) \
|
176
|
+
_QSORT_SWAP (_mid, _hi, _hold); \
|
177
|
+
else \
|
178
|
+
goto _jump_over; \
|
179
|
+
if (QSORT_LT (_mid, _lo)) \
|
180
|
+
_QSORT_SWAP (_mid, _lo, _hold); \
|
181
|
+
_jump_over:; \
|
182
|
+
\
|
183
|
+
_left_ptr = _lo + 1; \
|
184
|
+
_right_ptr = _hi - 1; \
|
185
|
+
\
|
186
|
+
/* Here's the famous ``collapse the walls'' section of quicksort. \
|
187
|
+
Gotta like those tight inner loops! They are the main reason \
|
188
|
+
that this algorithm runs much faster than others. */ \
|
189
|
+
do { \
|
190
|
+
while (QSORT_LT (_left_ptr, _mid)) \
|
191
|
+
++_left_ptr; \
|
192
|
+
\
|
193
|
+
while (QSORT_LT (_mid, _right_ptr)) \
|
194
|
+
--_right_ptr; \
|
195
|
+
\
|
196
|
+
if (_left_ptr < _right_ptr) { \
|
197
|
+
_QSORT_SWAP (_left_ptr, _right_ptr, _hold); \
|
198
|
+
if (_mid == _left_ptr) \
|
199
|
+
_mid = _right_ptr; \
|
200
|
+
else if (_mid == _right_ptr) \
|
201
|
+
_mid = _left_ptr; \
|
202
|
+
++_left_ptr; \
|
203
|
+
--_right_ptr; \
|
204
|
+
} \
|
205
|
+
else if (_left_ptr == _right_ptr) { \
|
206
|
+
++_left_ptr; \
|
207
|
+
--_right_ptr; \
|
208
|
+
break; \
|
209
|
+
} \
|
210
|
+
} while (_left_ptr <= _right_ptr); \
|
211
|
+
\
|
212
|
+
/* Set up pointers for next iteration. First determine whether \
|
213
|
+
left and right partitions are below the threshold size. If so, \
|
214
|
+
ignore one or both. Otherwise, push the larger partition's \
|
215
|
+
bounds on the stack and continue sorting the smaller one. */ \
|
216
|
+
\
|
217
|
+
if (_right_ptr - _lo <= _QSORT_MAX_THRESH) { \
|
218
|
+
if (_hi - _left_ptr <= _QSORT_MAX_THRESH) \
|
219
|
+
/* Ignore both small partitions. */ \
|
220
|
+
_QSORT_POP (_lo, _hi, _top); \
|
221
|
+
else \
|
222
|
+
/* Ignore small left partition. */ \
|
223
|
+
_lo = _left_ptr; \
|
224
|
+
} \
|
225
|
+
else if (_hi - _left_ptr <= _QSORT_MAX_THRESH) \
|
226
|
+
/* Ignore small right partition. */ \
|
227
|
+
_hi = _right_ptr; \
|
228
|
+
else if (_right_ptr - _lo > _hi - _left_ptr) { \
|
229
|
+
/* Push larger left partition indices. */ \
|
230
|
+
_QSORT_PUSH (_top, _lo, _right_ptr); \
|
231
|
+
_lo = _left_ptr; \
|
232
|
+
} \
|
233
|
+
else { \
|
234
|
+
/* Push larger right partition indices. */ \
|
235
|
+
_QSORT_PUSH (_top, _left_ptr, _hi); \
|
236
|
+
_hi = _right_ptr; \
|
237
|
+
} \
|
238
|
+
} \
|
239
|
+
} \
|
240
|
+
\
|
241
|
+
/* Once the BASE array is partially sorted by quicksort the rest \
|
242
|
+
is completely sorted using insertion sort, since this is efficient \
|
243
|
+
for partitions below MAX_THRESH size. BASE points to the \
|
244
|
+
beginning of the array to sort, and END_PTR points at the very \
|
245
|
+
last element in the array (*not* one beyond it!). */ \
|
246
|
+
\
|
247
|
+
{ \
|
248
|
+
QSORT_TYPE *const _end_ptr = _base + _elems - 1; \
|
249
|
+
QSORT_TYPE *_tmp_ptr = _base; \
|
250
|
+
register QSORT_TYPE *_run_ptr; \
|
251
|
+
QSORT_TYPE *_thresh; \
|
252
|
+
\
|
253
|
+
_thresh = _base + _QSORT_MAX_THRESH; \
|
254
|
+
if (_thresh > _end_ptr) \
|
255
|
+
_thresh = _end_ptr; \
|
256
|
+
\
|
257
|
+
/* Find smallest element in first threshold and place it at the \
|
258
|
+
array's beginning. This is the smallest array element, \
|
259
|
+
and the operation speeds up insertion sort's inner loop. */ \
|
260
|
+
\
|
261
|
+
for (_run_ptr = _tmp_ptr + 1; _run_ptr <= _thresh; ++_run_ptr) \
|
262
|
+
if (QSORT_LT (_run_ptr, _tmp_ptr)) \
|
263
|
+
_tmp_ptr = _run_ptr; \
|
264
|
+
\
|
265
|
+
if (_tmp_ptr != _base) \
|
266
|
+
_QSORT_SWAP (_tmp_ptr, _base, _hold); \
|
267
|
+
\
|
268
|
+
/* Insertion sort, running from left-hand-side \
|
269
|
+
* up to right-hand-side. */ \
|
270
|
+
\
|
271
|
+
_run_ptr = _base + 1; \
|
272
|
+
while (++_run_ptr <= _end_ptr) { \
|
273
|
+
_tmp_ptr = _run_ptr - 1; \
|
274
|
+
while (QSORT_LT (_run_ptr, _tmp_ptr)) \
|
275
|
+
--_tmp_ptr; \
|
276
|
+
\
|
277
|
+
++_tmp_ptr; \
|
278
|
+
if (_tmp_ptr != _run_ptr) { \
|
279
|
+
QSORT_TYPE *_trav = _run_ptr + 1; \
|
280
|
+
while (--_trav >= _run_ptr) { \
|
281
|
+
QSORT_TYPE *_hi; QSORT_TYPE *_lo; \
|
282
|
+
_hold = *_trav; \
|
283
|
+
\
|
284
|
+
for (_hi = _lo = _trav; --_lo >= _tmp_ptr; _hi = _lo) \
|
285
|
+
*_hi = *_lo; \
|
286
|
+
*_hi = _hold; \
|
287
|
+
} \
|
288
|
+
} \
|
289
|
+
} \
|
290
|
+
} \
|
291
|
+
\
|
292
|
+
}
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
SHARED_LIBRARY_FOLDER = File.join(File.dirname(__FILE__), '../../ffi')
|
5
|
+
SHARED_LIBRARY_NAME = File.join(SHARED_LIBRARY_FOLDER, 'libcidrmerge.so')
|
6
|
+
|
7
|
+
unless File.exist?(SHARED_LIBRARY_NAME)
|
8
|
+
FileUtils.cd(SHARED_LIBRARY_FOLDER)
|
9
|
+
%x{make}
|
10
|
+
fail "compile shared library fail, try to compile it by manual" if $?.exitstatus < 0
|
11
|
+
end
|
12
|
+
|
13
|
+
module Cidrmergerb
|
14
|
+
class Ext
|
15
|
+
extend FFI::Library
|
16
|
+
ffi_lib SHARED_LIBRARY_NAME
|
17
|
+
|
18
|
+
class Entry < FFI::ManagedStruct
|
19
|
+
layout :network => :uint,
|
20
|
+
:prefix => :uchar
|
21
|
+
|
22
|
+
def self.release(ptr)
|
23
|
+
Cidrmergerb::Ext.free_object(ptr)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
attach_function :optimize, [ :pointer, :uint, :int ], :uint
|
28
|
+
end
|
29
|
+
end
|
data/lib/cidrmergerb.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
require "cidrmergerb/version"
|
2
|
+
require 'cidrmergerb/ext'
|
3
|
+
require 'ipaddr'
|
4
|
+
require 'ffi'
|
5
|
+
|
6
|
+
module Cidrmergerb
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def optimize(cidrs)
|
10
|
+
pointer = build_pointer_to_cidrs(cidrs)
|
11
|
+
optimize_length = Cidrmergerb::Ext.optimize(pointer, cidrs.length, 1)
|
12
|
+
|
13
|
+
structs = wrap_with_struct(pointer, Cidrmergerb::Ext::Entry, optimize_length)
|
14
|
+
structs.map { |struct| strcut_to_cidr(struct) }
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
def build_pointer_to_cidrs(cidrs)
|
19
|
+
cidrs.select! {|cidr| cidr_valid?(cidr) }
|
20
|
+
|
21
|
+
pointer = alloc_memory(Cidrmergerb::Ext::Entry, cidrs.length)
|
22
|
+
entries = wrap_with_struct(pointer, Cidrmergerb::Ext::Entry, cidrs.length)
|
23
|
+
|
24
|
+
cidrs.each_with_index do |cidr, index|
|
25
|
+
ip, netmask = cidr.split('/')
|
26
|
+
entries[index][:network] = IPAddr.new(ip).to_i
|
27
|
+
entries[index][:prefix] = netmask.to_i
|
28
|
+
end
|
29
|
+
|
30
|
+
pointer
|
31
|
+
end
|
32
|
+
|
33
|
+
def cidr_valid?(cidr)
|
34
|
+
ip, netmask = cidr.split('/')
|
35
|
+
ipaddr = IPAddr.new(ip)
|
36
|
+
ipaddr && netmask.to_i.between?(1, 32)
|
37
|
+
rescue IPAddr::InvalidAddressError => e
|
38
|
+
false
|
39
|
+
end
|
40
|
+
|
41
|
+
def remove_invalid(cidrs)
|
42
|
+
cidrs.map do |cidr|
|
43
|
+
ip, netmask = cidr.split('/')
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def alloc_memory(type, size)
|
48
|
+
FFI::MemoryPointer.new type, size, false
|
49
|
+
end
|
50
|
+
|
51
|
+
def wrap_with_struct(pointer, struct_type, length)
|
52
|
+
length.times.collect do |i|
|
53
|
+
struct_type.new(pointer + i * struct_type.size)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def strcut_to_cidr(struct)
|
58
|
+
"#{IPAddr.new(struct[:network], Socket::AF_INET).to_s}/#{struct[:prefix]}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
metadata
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cidrmergerb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Newell Zhu
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-06-01 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: ffi
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.9'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 1.9.10
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.9'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 1.9.10
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: bundler
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '1.11'
|
40
|
+
type: :development
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '1.11'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rake
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '10.0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '10.0'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: minitest
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '5.0'
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '5.0'
|
75
|
+
description: CIDR Merge toolkit -- Wrapping for Daniele's CIDR Optimization library.
|
76
|
+
email:
|
77
|
+
- newell.zhu@kingaxis.com
|
78
|
+
executables: []
|
79
|
+
extensions: []
|
80
|
+
extra_rdoc_files: []
|
81
|
+
files:
|
82
|
+
- ".gitignore"
|
83
|
+
- ".travis.yml"
|
84
|
+
- Gemfile
|
85
|
+
- README.md
|
86
|
+
- Rakefile
|
87
|
+
- bin/console
|
88
|
+
- bin/setup
|
89
|
+
- cidrmergerb.gemspec
|
90
|
+
- ffi/Makefile
|
91
|
+
- ffi/cidrmerge.h
|
92
|
+
- ffi/libcidrmerge.c
|
93
|
+
- ffi/optimized-sort.h
|
94
|
+
- lib/cidrmergerb.rb
|
95
|
+
- lib/cidrmergerb/ext.rb
|
96
|
+
- lib/cidrmergerb/version.rb
|
97
|
+
homepage: https://github.com/kingaxis/cidrmergerb
|
98
|
+
licenses: []
|
99
|
+
metadata: {}
|
100
|
+
post_install_message:
|
101
|
+
rdoc_options: []
|
102
|
+
require_paths:
|
103
|
+
- lib
|
104
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - ">="
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '0'
|
109
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '0'
|
114
|
+
requirements: []
|
115
|
+
rubyforge_project:
|
116
|
+
rubygems_version: 2.5.1
|
117
|
+
signing_key:
|
118
|
+
specification_version: 4
|
119
|
+
summary: CIDR Merge toolkit -- Wrapping for Daniele's CIDR Optimization library.
|
120
|
+
test_files: []
|