| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Net::BART::Node; |
|
2
|
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
8
|
use strict; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
48
|
|
|
4
|
1
|
|
|
1
|
|
6
|
use warnings; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
68
|
|
|
5
|
1
|
|
|
1
|
|
7
|
use Net::BART::SparseArray256; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
58
|
|
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
our $VERSION = '0.01'; |
|
8
|
|
|
|
|
|
|
|
|
9
|
1
|
|
|
1
|
|
6
|
use Net::BART::Art qw(pfx_to_idx octet_to_idx idx_to_pfx pfx_bits prefix_decompose); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
114
|
|
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
# --- LeafNode: path-compressed leaf storing a full prefix + value --- |
|
12
|
|
|
|
|
|
|
# Structure: bless [$addr, $prefix_len, $value], 'Net::BART::Node::Leaf' |
|
13
|
|
|
|
|
|
|
# Constants for field access: |
|
14
|
1
|
|
|
1
|
|
8
|
use constant { LEAF_ADDR => 0, LEAF_PFXLEN => 1, LEAF_VALUE => 2 }; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
753
|
|
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
package Net::BART::Node::Leaf { |
|
17
|
|
|
|
|
|
|
sub new { |
|
18
|
10
|
|
|
10
|
|
45
|
my ($class, %args) = @_; |
|
19
|
10
|
|
|
|
|
48
|
return bless [$args{addr}, $args{prefix_len}, $args{value}], $class; |
|
20
|
|
|
|
|
|
|
} |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
sub contains_ip { |
|
23
|
5
|
|
|
5
|
|
10
|
my ($self, $ip_bytes) = @_; |
|
24
|
5
|
|
|
|
|
16
|
my $pfx = $self->[0]; # addr |
|
25
|
5
|
|
|
|
|
6
|
my $pfx_len = $self->[1]; |
|
26
|
5
|
|
|
|
|
11
|
my $full_bytes = $pfx_len >> 3; # int($pfx_len / 8) |
|
27
|
5
|
|
|
|
|
11
|
for my $i (0 .. $full_bytes - 1) { |
|
28
|
24
|
100
|
|
|
|
55
|
return 0 if $pfx->[$i] != $ip_bytes->[$i]; |
|
29
|
|
|
|
|
|
|
} |
|
30
|
3
|
|
|
|
|
7
|
my $remaining = $pfx_len & 7; |
|
31
|
3
|
50
|
|
|
|
9
|
if ($remaining) { |
|
32
|
0
|
|
|
|
|
0
|
my $mask = (0xFF << (8 - $remaining)) & 0xFF; |
|
33
|
0
|
0
|
|
|
|
0
|
return 0 if ($pfx->[$full_bytes] & $mask) != ($ip_bytes->[$full_bytes] & $mask); |
|
34
|
|
|
|
|
|
|
} |
|
35
|
3
|
|
|
|
|
12
|
return 1; |
|
36
|
|
|
|
|
|
|
} |
|
37
|
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
sub matches_prefix { |
|
39
|
6
|
|
|
6
|
|
12
|
my ($self, $addr, $prefix_len) = @_; |
|
40
|
6
|
100
|
|
|
|
22
|
return 0 if $self->[1] != $prefix_len; |
|
41
|
3
|
|
|
|
|
6
|
my $pfx = $self->[0]; |
|
42
|
3
|
|
|
|
|
6
|
my $full_bytes = $prefix_len >> 3; |
|
43
|
3
|
|
|
|
|
9
|
for my $i (0 .. $full_bytes - 1) { |
|
44
|
7
|
100
|
|
|
|
22
|
return 0 if $pfx->[$i] != $addr->[$i]; |
|
45
|
|
|
|
|
|
|
} |
|
46
|
1
|
|
|
|
|
2
|
my $remaining = $prefix_len & 7; |
|
47
|
1
|
50
|
|
|
|
4
|
if ($remaining) { |
|
48
|
1
|
|
|
|
|
3
|
my $mask = (0xFF << (8 - $remaining)) & 0xFF; |
|
49
|
1
|
50
|
|
|
|
6
|
return 0 if ($pfx->[$full_bytes] & $mask) != ($addr->[$full_bytes] & $mask); |
|
50
|
|
|
|
|
|
|
} |
|
51
|
0
|
|
|
|
|
0
|
return 1; |
|
52
|
|
|
|
|
|
|
} |
|
53
|
|
|
|
|
|
|
} |
|
54
|
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
# --- FringeNode: stride-aligned prefix, value only --- |
|
56
|
|
|
|
|
|
|
# Structure: bless [$value], 'Net::BART::Node::Fringe' |
|
57
|
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
package Net::BART::Node::Fringe { |
|
59
|
|
|
|
|
|
|
sub new { |
|
60
|
270
|
|
|
270
|
|
926
|
my ($class, %args) = @_; |
|
61
|
270
|
|
|
|
|
1449
|
return bless [$args{value}], $class; |
|
62
|
|
|
|
|
|
|
} |
|
63
|
|
|
|
|
|
|
} |
|
64
|
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
# --- BartNode: internal trie node --- |
|
66
|
|
|
|
|
|
|
# Structure: bless [$prefixes_sparse_array, $children_sparse_array], 'Net::BART::Node::Bart' |
|
67
|
1
|
|
|
1
|
|
9
|
use constant { BART_PFX => 0, BART_CHD => 1 }; |
|
|
1
|
|
|
|
|
12
|
|
|
|
1
|
|
|
|
|
859
|
|
|
68
|
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
package Net::BART::Node::Bart { |
|
70
|
|
|
|
|
|
|
sub new { |
|
71
|
37
|
|
|
37
|
|
133
|
return bless [Net::BART::SparseArray256->new, Net::BART::SparseArray256->new], $_[0]; |
|
72
|
|
|
|
|
|
|
} |
|
73
|
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
# Prefix operations - delegate to sparse array |
|
75
|
8
|
|
|
8
|
|
23
|
sub insert_prefix { return $_[0]->[0]->insert_at($_[1], $_[2]) } |
|
76
|
0
|
|
|
0
|
|
0
|
sub delete_prefix { return $_[0]->[0]->delete_at($_[1]) } |
|
77
|
1
|
|
|
1
|
|
3
|
sub get_prefix { return $_[0]->[0]->get($_[1]) } |
|
78
|
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
# Child operations |
|
80
|
811
|
|
|
811
|
|
2077
|
sub get_child { return $_[0]->[1]->get($_[1]) } |
|
81
|
291
|
|
|
291
|
|
747
|
sub set_child { return $_[0]->[1]->insert_at($_[1], $_[2]) } |
|
82
|
1
|
|
|
1
|
|
4
|
sub delete_child { return $_[0]->[1]->delete_at($_[1]) } |
|
83
|
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
# Longest-prefix-match at this node for the given octet. |
|
85
|
|
|
|
|
|
|
# Returns (value, 1) if found, (undef, 0) if not. |
|
86
|
|
|
|
|
|
|
sub lpm { |
|
87
|
16
|
|
|
16
|
|
24
|
my $self = $_[0]; |
|
88
|
16
|
|
|
|
|
29
|
my $idx = ($_[1] >> 1) + 128; # octet_to_idx inlined |
|
89
|
16
|
|
|
|
|
26
|
my $pfx_bs = $self->[0][0]; # prefixes sparse array -> bitset |
|
90
|
16
|
|
|
|
|
31
|
my $lut = $Net::BART::LPM::LOOKUP_TBL[$idx]; |
|
91
|
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
# intersection_top inlined |
|
93
|
16
|
|
|
|
|
24
|
my $w; |
|
94
|
16
|
50
|
|
|
|
32
|
$w = $pfx_bs->[3] & $lut->[3]; if ($w) { return $self->[0]->get(192 + Net::BART::BitSet256::_bit_len64($w) - 1) } |
|
|
16
|
|
|
|
|
33
|
|
|
|
0
|
|
|
|
|
0
|
|
|
95
|
16
|
50
|
|
|
|
23
|
$w = $pfx_bs->[2] & $lut->[2]; if ($w) { return $self->[0]->get(128 + Net::BART::BitSet256::_bit_len64($w) - 1) } |
|
|
16
|
|
|
|
|
31
|
|
|
|
0
|
|
|
|
|
0
|
|
|
96
|
16
|
50
|
|
|
|
31
|
$w = $pfx_bs->[1] & $lut->[1]; if ($w) { return $self->[0]->get( 64 + Net::BART::BitSet256::_bit_len64($w) - 1) } |
|
|
16
|
|
|
|
|
33
|
|
|
|
0
|
|
|
|
|
0
|
|
|
97
|
16
|
100
|
|
|
|
26
|
$w = $pfx_bs->[0] & $lut->[0]; if ($w) { return $self->[0]->get( Net::BART::BitSet256::_bit_len64($w) - 1) } |
|
|
16
|
|
|
|
|
56
|
|
|
|
8
|
|
|
|
|
30
|
|
|
98
|
8
|
|
|
|
|
23
|
return (undef, 0); |
|
99
|
|
|
|
|
|
|
} |
|
100
|
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
# Check if any prefix at this node matches the given octet. |
|
102
|
|
|
|
|
|
|
sub lpm_test { |
|
103
|
0
|
|
|
0
|
|
0
|
my $pfx_bs = $_[0]->[0][0]; # prefixes -> bitset |
|
104
|
0
|
|
|
|
|
0
|
my $lut = $Net::BART::LPM::LOOKUP_TBL[($_[1] >> 1) + 128]; |
|
105
|
0
|
0
|
|
|
|
0
|
return (($pfx_bs->[0] & $lut->[0]) | |
|
106
|
|
|
|
|
|
|
($pfx_bs->[1] & $lut->[1]) | |
|
107
|
|
|
|
|
|
|
($pfx_bs->[2] & $lut->[2]) | |
|
108
|
|
|
|
|
|
|
($pfx_bs->[3] & $lut->[3])) ? 1 : 0; |
|
109
|
|
|
|
|
|
|
} |
|
110
|
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
sub is_empty { |
|
112
|
1
|
|
33
|
1
|
|
1
|
return !@{$_[0]->[0][1]} && !@{$_[0]->[1][1]}; |
|
113
|
|
|
|
|
|
|
} |
|
114
|
|
|
|
|
|
|
} |
|
115
|
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
1; |