blob: 3c51c904a526fb0b257b6ebc32cc9eee8e145b2c [file] [log] [blame]
Jonathan Hart382623d2014-04-03 09:48:11 -07001package net.onrc.onos.apps.bgproute;
pingping-lina2cbfad2013-03-07 08:39:21 +08002
Jonathan Hart66dffed2013-07-16 11:36:00 +12003/*
4 * TODO This Ptree needs to be refactored if we're going to use it permenantly.
5 *
6 * The biggest problem is it leaks PTreeNode references - these need to stay within
7 * the Ptree as they contain data fundamental to the structure of the tree.
8 * You should put RIB entries in and get RIB entries out.
9 * Also we need to get rid of the referencing scheme to determine when to delete nodes.
Ray Milkey5d406012014-04-08 14:44:41 -070010 * Deletes should be explicit, and there's no need to keep track of references if
Jonathan Hart66dffed2013-07-16 11:36:00 +120011 * we don't leak them out the the Ptree.
12 */
pingping-lina2cbfad2013-03-07 08:39:21 +080013public class Ptree {
Ray Milkey269ffb92014-04-03 14:43:30 -070014 private int maxKeyBits;
15 private int maxKeyOctets;
16 //private int refCount;
17 private PtreeNode top;
Ray Milkey45614c52014-04-07 16:30:54 -070018 private byte[] maskBits = {(byte) 0x00, (byte) 0x80, (byte) 0xc0, (byte) 0xe0, (byte) 0xf0, (byte) 0xf8, (byte) 0xfc, (byte) 0xfe, (byte) 0xff};
pingping-lina2cbfad2013-03-07 08:39:21 +080019
Ray Milkey9526d6f2014-04-10 14:54:15 -070020 public Ptree(int maxKeyBits) {
21 this.maxKeyBits = maxKeyBits;
22 maxKeyOctets = bit_to_octet(maxKeyBits);
Ray Milkey269ffb92014-04-03 14:43:30 -070023 //refCount = 0;
24 }
pingping-lina2cbfad2013-03-07 08:39:21 +080025
Ray Milkey269ffb92014-04-03 14:43:30 -070026 public synchronized PtreeNode acquire(byte[] key) {
27 return acquire(key, maxKeyBits);
28 }
pingping-lina2cbfad2013-03-07 08:39:21 +080029
Ray Milkey9526d6f2014-04-10 14:54:15 -070030 public synchronized PtreeNode acquire(byte[] key, int keyBits) {
31 if (keyBits > maxKeyBits) {
Ray Milkey269ffb92014-04-03 14:43:30 -070032 return null;
33 }
pingping-lina2cbfad2013-03-07 08:39:21 +080034
Ray Milkey269ffb92014-04-03 14:43:30 -070035 PtreeNode node = top;
36 PtreeNode match = null;
pingping-lina2cbfad2013-03-07 08:39:21 +080037
Ray Milkey269ffb92014-04-03 14:43:30 -070038 while (node != null
Ray Milkey9526d6f2014-04-10 14:54:15 -070039 && node.keyBits <= keyBits
Ray Milkey6c4f2fe2014-04-11 09:47:23 -070040 && key_match(node.key, node.keyBits, key, keyBits)) {
Ray Milkey9526d6f2014-04-10 14:54:15 -070041 if (node.keyBits == keyBits) {
Ray Milkey269ffb92014-04-03 14:43:30 -070042 return addReference(node);
43 }
pingping-lina2cbfad2013-03-07 08:39:21 +080044
Ray Milkey269ffb92014-04-03 14:43:30 -070045 match = node;
pingping-lina2cbfad2013-03-07 08:39:21 +080046
Ray Milkey6c4f2fe2014-04-11 09:47:23 -070047 if (bit_check(key, node.keyBits)) {
Ray Milkey269ffb92014-04-03 14:43:30 -070048 node = node.right;
49 } else {
50 node = node.left;
51 }
52 }
pingping-lina2cbfad2013-03-07 08:39:21 +080053
Ray Milkey269ffb92014-04-03 14:43:30 -070054 PtreeNode add = null;
pingping-lina2cbfad2013-03-07 08:39:21 +080055
Ray Milkey269ffb92014-04-03 14:43:30 -070056 if (node == null) {
Ray Milkey9526d6f2014-04-10 14:54:15 -070057 add = new PtreeNode(key, keyBits, maxKeyOctets);
pingping-lina2cbfad2013-03-07 08:39:21 +080058
Ray Milkey269ffb92014-04-03 14:43:30 -070059 if (match != null) {
60 node_link(match, add);
61 } else {
62 top = add;
63 }
64 } else {
Ray Milkey9526d6f2014-04-10 14:54:15 -070065 add = node_common(node, key, keyBits);
pingping-lina2cbfad2013-03-07 08:39:21 +080066
Ray Milkey269ffb92014-04-03 14:43:30 -070067 if (match != null) {
68 node_link(match, add);
69 } else {
70 top = add;
71 }
72 node_link(add, node);
pingping-lina2cbfad2013-03-07 08:39:21 +080073
Ray Milkey9526d6f2014-04-10 14:54:15 -070074 if (add.keyBits != keyBits) {
Ray Milkey269ffb92014-04-03 14:43:30 -070075 match = add;
76
Ray Milkey9526d6f2014-04-10 14:54:15 -070077 add = new PtreeNode(key, keyBits, maxKeyOctets);
Ray Milkey269ffb92014-04-03 14:43:30 -070078 node_link(match, add);
79 }
80 }
81
82 return addReference(add);
83 }
84
Ray Milkey9526d6f2014-04-10 14:54:15 -070085 public synchronized PtreeNode lookup(byte[] key, int keyBits) {
86 if (keyBits > maxKeyBits) {
Ray Milkey269ffb92014-04-03 14:43:30 -070087 return null;
88 }
89
90 PtreeNode node = top;
91
92 while (node != null
Ray Milkey9526d6f2014-04-10 14:54:15 -070093 && node.keyBits <= keyBits
Ray Milkey6c4f2fe2014-04-11 09:47:23 -070094 && key_match(node.key, node.keyBits, key, keyBits)) {
Ray Milkey9526d6f2014-04-10 14:54:15 -070095 if (node.keyBits == keyBits) {
Ray Milkey269ffb92014-04-03 14:43:30 -070096 return addReference(node);
97 }
98
Ray Milkey6c4f2fe2014-04-11 09:47:23 -070099 if (bit_check(key, node.keyBits)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700100 node = node.right;
101 } else {
102 node = node.left;
103 }
104 }
105 return null;
106 }
107
Ray Milkey9526d6f2014-04-10 14:54:15 -0700108 public synchronized PtreeNode match(byte[] key, int keyBits) {
109 if (keyBits > maxKeyBits) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700110 return null;
111 }
112 PtreeNode node = top;
113 PtreeNode matched = null;
114
Ray Milkeyb29e6262014-04-09 16:02:14 -0700115 if (node != null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700116
117 while (node != null
Ray Milkey9526d6f2014-04-10 14:54:15 -0700118 && node.keyBits <= keyBits
Ray Milkey6c4f2fe2014-04-11 09:47:23 -0700119 && key_match(node.key, node.keyBits, key, keyBits)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700120 matched = node;
121
Ray Milkey6c4f2fe2014-04-11 09:47:23 -0700122 if (bit_check(key, node.keyBits)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700123 node = node.right;
124 } else {
125 node = node.left;
126 }
127 }
Ray Milkeyb29e6262014-04-09 16:02:14 -0700128 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700129
130 if (matched != null) {
131 return addReference(matched);
132 }
133
134 return null;
135 }
136
137 public synchronized PtreeNode begin() {
138 if (top == null) {
139 return null;
140 }
141 return addReference(top);
142 }
143
144 public synchronized PtreeNode next(PtreeNode node) {
145 PtreeNode next;
146
147 if (node.left != null) {
148 next = node.left;
149 addReference(next);
150 delReference(node);
151 return next;
152 }
153 if (node.right != null) {
154 next = node.right;
155 addReference(next);
156 delReference(node);
157 return next;
158 }
159
160 PtreeNode start = node;
161 while (node.parent != null) {
162 if (node.parent.left == node && node.parent.right != null) {
163 next = node.parent.right;
164 addReference(next);
165 delReference(start);
166 return next;
167 }
168 node = node.parent;
169 }
170
171 delReference(start);
172
173 return null;
174 }
175
Ray Milkey9526d6f2014-04-10 14:54:15 -0700176 public static int bit_to_octet(int keyBits) {
177 return Math.max((keyBits + 7) / 8, 1);
Ray Milkey269ffb92014-04-03 14:43:30 -0700178 }
179
180 private PtreeNode addReference(PtreeNode node) {
181 node.refCount++;
182 return node;
183 }
184
185 public synchronized void delReference(PtreeNode node) {
186 if (node.refCount > 0) {
187 node.refCount--;
188 }
189 if (node.refCount == 0) {
190 node_remove(node);
191 }
192 }
193
Ray Milkey9526d6f2014-04-10 14:54:15 -0700194 private boolean key_match(byte[] key1, int key1Len, byte[] key2, int key2Len) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700195 int offset;
196 int shift;
197
Ray Milkey9526d6f2014-04-10 14:54:15 -0700198 if (key1Len > key2Len) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700199 return false;
200 }
201
Ray Milkey9526d6f2014-04-10 14:54:15 -0700202 offset = (Math.min(key1Len, key2Len)) / 8;
203 shift = (Math.min(key1Len, key2Len)) % 8;
Ray Milkey269ffb92014-04-03 14:43:30 -0700204
205 if (shift != 0) {
206 if ((maskBits[shift] & (key1[offset] ^ key2[offset])) != 0) {
207 return false;
208 }
209 }
210
211 while (offset != 0) {
212 offset--;
213 if (key1[offset] != key2[offset]) {
214 return false;
215 }
216 }
217 return true;
218 }
219
Ray Milkey9526d6f2014-04-10 14:54:15 -0700220 private boolean bit_check(byte[] key, int keyBits) {
221 int offset = keyBits / 8;
222 int shift = 7 - (keyBits % 8);
Ray Milkey269ffb92014-04-03 14:43:30 -0700223 int bit = key[offset] & 0xff;
224
225 bit >>= shift;
226
Ray Milkey4985f212014-04-10 16:57:05 -0700227 return ((bit & 1) == 1);
Ray Milkey269ffb92014-04-03 14:43:30 -0700228 }
229
230 private void node_link(PtreeNode node, PtreeNode add) {
231 boolean bit = bit_check(add.key, node.keyBits);
232
Ray Milkey6c4f2fe2014-04-11 09:47:23 -0700233 if (bit) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700234 node.right = add;
235 } else {
236 node.left = add;
237 }
238 add.parent = node;
239 }
240
Ray Milkey9526d6f2014-04-10 14:54:15 -0700241 private PtreeNode node_common(PtreeNode node, byte[] key, int keyBits) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700242 int i;
Ray Milkey9526d6f2014-04-10 14:54:15 -0700243 int limit = Math.min(node.keyBits, keyBits) / 8;
Ray Milkey269ffb92014-04-03 14:43:30 -0700244
245 for (i = 0; i < limit; i++) {
246 if (node.key[i] != key[i]) {
247 break;
248 }
249 }
250
Ray Milkey2476cac2014-04-08 11:03:21 -0700251 int commonLen = i * 8;
Ray Milkey269ffb92014-04-03 14:43:30 -0700252 int boundary = 0;
253
Ray Milkey9526d6f2014-04-10 14:54:15 -0700254 if (commonLen != keyBits) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700255 byte diff = (byte) (node.key[i] ^ key[i]);
256 byte mask = (byte) 0x80;
Ray Milkey2476cac2014-04-08 11:03:21 -0700257 int shiftMask = 0;
Ray Milkey269ffb92014-04-03 14:43:30 -0700258
Ray Milkey9526d6f2014-04-10 14:54:15 -0700259 while (commonLen < keyBits && ((mask & diff) == 0)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700260 boundary = 1;
261
Ray Milkey2476cac2014-04-08 11:03:21 -0700262 shiftMask = (mask & 0xff);
263 shiftMask >>= 1;
264 mask = (byte) shiftMask;
Ray Milkey269ffb92014-04-03 14:43:30 -0700265
Ray Milkey2476cac2014-04-08 11:03:21 -0700266 commonLen++;
Ray Milkey269ffb92014-04-03 14:43:30 -0700267 }
268 }
269
Ray Milkey2476cac2014-04-08 11:03:21 -0700270 PtreeNode add = new PtreeNode(null, commonLen, maxKeyOctets);
Ray Milkey269ffb92014-04-03 14:43:30 -0700271
272 int j;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700273 for (j = 0; j < i; j++) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700274 add.key[j] = node.key[j];
Ray Milkeyb29e6262014-04-09 16:02:14 -0700275 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700276
Ray Milkeyb29e6262014-04-09 16:02:14 -0700277 if (boundary != 0) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700278 add.key[j] = (byte) (node.key[j] & maskBits[add.keyBits % 8]);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700279 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700280
281 return add;
282 }
283
284 private void node_remove(PtreeNode node) {
285 PtreeNode child;
286 PtreeNode parent;
287
288 if (node.left != null && node.right != null) {
289 return;
290 }
291
292 if (node.left != null) {
293 child = node.left;
294 } else {
295 child = node.right;
296 }
297
298 parent = node.parent;
299
300 if (child != null) {
301 child.parent = parent;
302 }
303
304 if (parent != null) {
305 if (parent.left == node) {
306 parent.left = child;
307 } else {
308 parent.right = child;
309 }
310 } else {
311 top = child;
312 }
313
314 if (parent != null && parent.refCount == 0) {
315 node_remove(parent);
316 }
317 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800318}