1 | /*------------------------------------------------------------------------- |
2 | * |
3 | * network_spgist.c |
4 | * SP-GiST support for network types. |
5 | * |
6 | * We split inet index entries first by address family (IPv4 or IPv6). |
7 | * If the entries below a given inner tuple are all of the same family, |
8 | * we identify their common prefix and split by the next bit of the address, |
9 | * and by whether their masklens exceed the length of the common prefix. |
10 | * |
11 | * An inner tuple that has both IPv4 and IPv6 children has a null prefix |
12 | * and exactly two nodes, the first being for IPv4 and the second for IPv6. |
13 | * |
14 | * Otherwise, the prefix is a CIDR value representing the common prefix, |
15 | * and there are exactly four nodes. Node numbers 0 and 1 are for addresses |
16 | * with the same masklen as the prefix, while node numbers 2 and 3 are for |
17 | * addresses with larger masklen. (We do not allow a tuple to contain |
18 | * entries with masklen smaller than its prefix's.) Node numbers 0 and 1 |
19 | * are distinguished by the next bit of the address after the common prefix, |
20 | * and likewise for node numbers 2 and 3. If there are no more bits in |
21 | * the address family, everything goes into node 0 (which will probably |
22 | * lead to creating an allTheSame tuple). |
23 | * |
24 | * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group |
25 | * Portions Copyright (c) 1994, Regents of the University of California |
26 | * |
27 | * IDENTIFICATION |
28 | * src/backend/utils/adt/network_spgist.c |
29 | * |
30 | *------------------------------------------------------------------------- |
31 | */ |
32 | #include "postgres.h" |
33 | |
34 | #include <sys/socket.h> |
35 | |
36 | #include "access/spgist.h" |
37 | #include "catalog/pg_type.h" |
38 | #include "utils/builtins.h" |
39 | #include "utils/inet.h" |
40 | |
41 | |
42 | static int inet_spg_node_number(const inet *val, int commonbits); |
43 | static int inet_spg_consistent_bitmap(const inet *prefix, int nkeys, |
44 | ScanKey scankeys, bool leaf); |
45 | |
46 | /* |
47 | * The SP-GiST configuration function |
48 | */ |
49 | Datum |
50 | inet_spg_config(PG_FUNCTION_ARGS) |
51 | { |
52 | /* spgConfigIn *cfgin = (spgConfigIn *) PG_GETARG_POINTER(0); */ |
53 | spgConfigOut *cfg = (spgConfigOut *) PG_GETARG_POINTER(1); |
54 | |
55 | cfg->prefixType = CIDROID; |
56 | cfg->labelType = VOIDOID; |
57 | cfg->canReturnData = true; |
58 | cfg->longValuesOK = false; |
59 | |
60 | PG_RETURN_VOID(); |
61 | } |
62 | |
63 | /* |
64 | * The SP-GiST choose function |
65 | */ |
66 | Datum |
67 | inet_spg_choose(PG_FUNCTION_ARGS) |
68 | { |
69 | spgChooseIn *in = (spgChooseIn *) PG_GETARG_POINTER(0); |
70 | spgChooseOut *out = (spgChooseOut *) PG_GETARG_POINTER(1); |
71 | inet *val = DatumGetInetPP(in->datum), |
72 | *prefix; |
73 | int commonbits; |
74 | |
75 | /* |
76 | * If we're looking at a tuple that splits by address family, choose the |
77 | * appropriate subnode. |
78 | */ |
79 | if (!in->hasPrefix) |
80 | { |
81 | /* allTheSame isn't possible for such a tuple */ |
82 | Assert(!in->allTheSame); |
83 | Assert(in->nNodes == 2); |
84 | |
85 | out->resultType = spgMatchNode; |
86 | out->result.matchNode.nodeN = (ip_family(val) == PGSQL_AF_INET) ? 0 : 1; |
87 | out->result.matchNode.restDatum = InetPGetDatum(val); |
88 | |
89 | PG_RETURN_VOID(); |
90 | } |
91 | |
92 | /* Else it must split by prefix */ |
93 | Assert(in->nNodes == 4 || in->allTheSame); |
94 | |
95 | prefix = DatumGetInetPP(in->prefixDatum); |
96 | commonbits = ip_bits(prefix); |
97 | |
98 | /* |
99 | * We cannot put addresses from different families under the same inner |
100 | * node, so we have to split if the new value's family is different. |
101 | */ |
102 | if (ip_family(val) != ip_family(prefix)) |
103 | { |
104 | /* Set up 2-node tuple */ |
105 | out->resultType = spgSplitTuple; |
106 | out->result.splitTuple.prefixHasPrefix = false; |
107 | out->result.splitTuple.prefixNNodes = 2; |
108 | out->result.splitTuple.prefixNodeLabels = NULL; |
109 | |
110 | /* Identify which node the existing data goes into */ |
111 | out->result.splitTuple.childNodeN = |
112 | (ip_family(prefix) == PGSQL_AF_INET) ? 0 : 1; |
113 | |
114 | out->result.splitTuple.postfixHasPrefix = true; |
115 | out->result.splitTuple.postfixPrefixDatum = InetPGetDatum(prefix); |
116 | |
117 | PG_RETURN_VOID(); |
118 | } |
119 | |
120 | /* |
121 | * If the new value does not match the existing prefix, we have to split. |
122 | */ |
123 | if (ip_bits(val) < commonbits || |
124 | bitncmp(ip_addr(prefix), ip_addr(val), commonbits) != 0) |
125 | { |
126 | /* Determine new prefix length for the split tuple */ |
127 | commonbits = bitncommon(ip_addr(prefix), ip_addr(val), |
128 | Min(ip_bits(val), commonbits)); |
129 | |
130 | /* Set up 4-node tuple */ |
131 | out->resultType = spgSplitTuple; |
132 | out->result.splitTuple.prefixHasPrefix = true; |
133 | out->result.splitTuple.prefixPrefixDatum = |
134 | InetPGetDatum(cidr_set_masklen_internal(val, commonbits)); |
135 | out->result.splitTuple.prefixNNodes = 4; |
136 | out->result.splitTuple.prefixNodeLabels = NULL; |
137 | |
138 | /* Identify which node the existing data goes into */ |
139 | out->result.splitTuple.childNodeN = |
140 | inet_spg_node_number(prefix, commonbits); |
141 | |
142 | out->result.splitTuple.postfixHasPrefix = true; |
143 | out->result.splitTuple.postfixPrefixDatum = InetPGetDatum(prefix); |
144 | |
145 | PG_RETURN_VOID(); |
146 | } |
147 | |
148 | /* |
149 | * All OK, choose the node to descend into. (If this tuple is marked |
150 | * allTheSame, the core code will ignore our choice of nodeN; but we need |
151 | * not account for that case explicitly here.) |
152 | */ |
153 | out->resultType = spgMatchNode; |
154 | out->result.matchNode.nodeN = inet_spg_node_number(val, commonbits); |
155 | out->result.matchNode.restDatum = InetPGetDatum(val); |
156 | |
157 | PG_RETURN_VOID(); |
158 | } |
159 | |
160 | /* |
161 | * The GiST PickSplit method |
162 | */ |
163 | Datum |
164 | inet_spg_picksplit(PG_FUNCTION_ARGS) |
165 | { |
166 | spgPickSplitIn *in = (spgPickSplitIn *) PG_GETARG_POINTER(0); |
167 | spgPickSplitOut *out = (spgPickSplitOut *) PG_GETARG_POINTER(1); |
168 | inet *prefix, |
169 | *tmp; |
170 | int i, |
171 | commonbits; |
172 | bool differentFamilies = false; |
173 | |
174 | /* Initialize the prefix with the first item */ |
175 | prefix = DatumGetInetPP(in->datums[0]); |
176 | commonbits = ip_bits(prefix); |
177 | |
178 | /* Examine remaining items to discover minimum common prefix length */ |
179 | for (i = 1; i < in->nTuples; i++) |
180 | { |
181 | tmp = DatumGetInetPP(in->datums[i]); |
182 | |
183 | if (ip_family(tmp) != ip_family(prefix)) |
184 | { |
185 | differentFamilies = true; |
186 | break; |
187 | } |
188 | |
189 | if (ip_bits(tmp) < commonbits) |
190 | commonbits = ip_bits(tmp); |
191 | commonbits = bitncommon(ip_addr(prefix), ip_addr(tmp), commonbits); |
192 | if (commonbits == 0) |
193 | break; |
194 | } |
195 | |
196 | /* Don't need labels; allocate output arrays */ |
197 | out->nodeLabels = NULL; |
198 | out->mapTuplesToNodes = (int *) palloc(sizeof(int) * in->nTuples); |
199 | out->leafTupleDatums = (Datum *) palloc(sizeof(Datum) * in->nTuples); |
200 | |
201 | if (differentFamilies) |
202 | { |
203 | /* Set up 2-node tuple */ |
204 | out->hasPrefix = false; |
205 | out->nNodes = 2; |
206 | |
207 | for (i = 0; i < in->nTuples; i++) |
208 | { |
209 | tmp = DatumGetInetPP(in->datums[i]); |
210 | out->mapTuplesToNodes[i] = |
211 | (ip_family(tmp) == PGSQL_AF_INET) ? 0 : 1; |
212 | out->leafTupleDatums[i] = InetPGetDatum(tmp); |
213 | } |
214 | } |
215 | else |
216 | { |
217 | /* Set up 4-node tuple */ |
218 | out->hasPrefix = true; |
219 | out->prefixDatum = |
220 | InetPGetDatum(cidr_set_masklen_internal(prefix, commonbits)); |
221 | out->nNodes = 4; |
222 | |
223 | for (i = 0; i < in->nTuples; i++) |
224 | { |
225 | tmp = DatumGetInetPP(in->datums[i]); |
226 | out->mapTuplesToNodes[i] = inet_spg_node_number(tmp, commonbits); |
227 | out->leafTupleDatums[i] = InetPGetDatum(tmp); |
228 | } |
229 | } |
230 | |
231 | PG_RETURN_VOID(); |
232 | } |
233 | |
234 | /* |
235 | * The SP-GiST query consistency check for inner tuples |
236 | */ |
237 | Datum |
238 | inet_spg_inner_consistent(PG_FUNCTION_ARGS) |
239 | { |
240 | spgInnerConsistentIn *in = (spgInnerConsistentIn *) PG_GETARG_POINTER(0); |
241 | spgInnerConsistentOut *out = (spgInnerConsistentOut *) PG_GETARG_POINTER(1); |
242 | int i; |
243 | int which; |
244 | |
245 | if (!in->hasPrefix) |
246 | { |
247 | Assert(!in->allTheSame); |
248 | Assert(in->nNodes == 2); |
249 | |
250 | /* Identify which child nodes need to be visited */ |
251 | which = 1 | (1 << 1); |
252 | |
253 | for (i = 0; i < in->nkeys; i++) |
254 | { |
255 | StrategyNumber strategy = in->scankeys[i].sk_strategy; |
256 | inet *argument = DatumGetInetPP(in->scankeys[i].sk_argument); |
257 | |
258 | switch (strategy) |
259 | { |
260 | case RTLessStrategyNumber: |
261 | case RTLessEqualStrategyNumber: |
262 | if (ip_family(argument) == PGSQL_AF_INET) |
263 | which &= 1; |
264 | break; |
265 | |
266 | case RTGreaterEqualStrategyNumber: |
267 | case RTGreaterStrategyNumber: |
268 | if (ip_family(argument) == PGSQL_AF_INET6) |
269 | which &= (1 << 1); |
270 | break; |
271 | |
272 | case RTNotEqualStrategyNumber: |
273 | break; |
274 | |
275 | default: |
276 | /* all other ops can only match addrs of same family */ |
277 | if (ip_family(argument) == PGSQL_AF_INET) |
278 | which &= 1; |
279 | else |
280 | which &= (1 << 1); |
281 | break; |
282 | } |
283 | } |
284 | } |
285 | else if (!in->allTheSame) |
286 | { |
287 | Assert(in->nNodes == 4); |
288 | |
289 | /* Identify which child nodes need to be visited */ |
290 | which = inet_spg_consistent_bitmap(DatumGetInetPP(in->prefixDatum), |
291 | in->nkeys, in->scankeys, false); |
292 | } |
293 | else |
294 | { |
295 | /* Must visit all nodes; we assume there are less than 32 of 'em */ |
296 | which = ~0; |
297 | } |
298 | |
299 | out->nNodes = 0; |
300 | |
301 | if (which) |
302 | { |
303 | out->nodeNumbers = (int *) palloc(sizeof(int) * in->nNodes); |
304 | |
305 | for (i = 0; i < in->nNodes; i++) |
306 | { |
307 | if (which & (1 << i)) |
308 | { |
309 | out->nodeNumbers[out->nNodes] = i; |
310 | out->nNodes++; |
311 | } |
312 | } |
313 | } |
314 | |
315 | PG_RETURN_VOID(); |
316 | } |
317 | |
318 | /* |
319 | * The SP-GiST query consistency check for leaf tuples |
320 | */ |
321 | Datum |
322 | inet_spg_leaf_consistent(PG_FUNCTION_ARGS) |
323 | { |
324 | spgLeafConsistentIn *in = (spgLeafConsistentIn *) PG_GETARG_POINTER(0); |
325 | spgLeafConsistentOut *out = (spgLeafConsistentOut *) PG_GETARG_POINTER(1); |
326 | inet *leaf = DatumGetInetPP(in->leafDatum); |
327 | |
328 | /* All tests are exact. */ |
329 | out->recheck = false; |
330 | |
331 | /* Leaf is what it is... */ |
332 | out->leafValue = InetPGetDatum(leaf); |
333 | |
334 | /* Use common code to apply the tests. */ |
335 | PG_RETURN_BOOL(inet_spg_consistent_bitmap(leaf, in->nkeys, in->scankeys, |
336 | true)); |
337 | } |
338 | |
339 | /* |
340 | * Calculate node number (within a 4-node, single-family inner index tuple) |
341 | * |
342 | * The value must have the same family as the node's prefix, and |
343 | * commonbits is the mask length of the prefix. We use even or odd |
344 | * nodes according to the next address bit after the commonbits, |
345 | * and low or high nodes according to whether the value's mask length |
346 | * is larger than commonbits. |
347 | */ |
348 | static int |
349 | inet_spg_node_number(const inet *val, int commonbits) |
350 | { |
351 | int nodeN = 0; |
352 | |
353 | if (commonbits < ip_maxbits(val) && |
354 | ip_addr(val)[commonbits / 8] & (1 << (7 - commonbits % 8))) |
355 | nodeN |= 1; |
356 | if (commonbits < ip_bits(val)) |
357 | nodeN |= 2; |
358 | |
359 | return nodeN; |
360 | } |
361 | |
362 | /* |
363 | * Calculate bitmap of node numbers that are consistent with the query |
364 | * |
365 | * This can be used either at a 4-way inner tuple, or at a leaf tuple. |
366 | * In the latter case, we should return a boolean result (0 or 1) |
367 | * not a bitmap. |
368 | * |
369 | * This definition is pretty odd, but the inner and leaf consistency checks |
370 | * are mostly common and it seems best to keep them in one function. |
371 | */ |
372 | static int |
373 | inet_spg_consistent_bitmap(const inet *prefix, int nkeys, ScanKey scankeys, |
374 | bool leaf) |
375 | { |
376 | int bitmap; |
377 | int commonbits, |
378 | i; |
379 | |
380 | /* Initialize result to allow visiting all children */ |
381 | if (leaf) |
382 | bitmap = 1; |
383 | else |
384 | bitmap = 1 | (1 << 1) | (1 << 2) | (1 << 3); |
385 | |
386 | commonbits = ip_bits(prefix); |
387 | |
388 | for (i = 0; i < nkeys; i++) |
389 | { |
390 | inet *argument = DatumGetInetPP(scankeys[i].sk_argument); |
391 | StrategyNumber strategy = scankeys[i].sk_strategy; |
392 | int order; |
393 | |
394 | /* |
395 | * Check 0: different families |
396 | * |
397 | * Matching families do not help any of the strategies. |
398 | */ |
399 | if (ip_family(argument) != ip_family(prefix)) |
400 | { |
401 | switch (strategy) |
402 | { |
403 | case RTLessStrategyNumber: |
404 | case RTLessEqualStrategyNumber: |
405 | if (ip_family(argument) < ip_family(prefix)) |
406 | bitmap = 0; |
407 | break; |
408 | |
409 | case RTGreaterEqualStrategyNumber: |
410 | case RTGreaterStrategyNumber: |
411 | if (ip_family(argument) > ip_family(prefix)) |
412 | bitmap = 0; |
413 | break; |
414 | |
415 | case RTNotEqualStrategyNumber: |
416 | break; |
417 | |
418 | default: |
419 | /* For all other cases, we can be sure there is no match */ |
420 | bitmap = 0; |
421 | break; |
422 | } |
423 | |
424 | if (!bitmap) |
425 | break; |
426 | |
427 | /* Other checks make no sense with different families. */ |
428 | continue; |
429 | } |
430 | |
431 | /* |
432 | * Check 1: network bit count |
433 | * |
434 | * Network bit count (ip_bits) helps to check leaves for sub network |
435 | * and sup network operators. At non-leaf nodes, we know every child |
436 | * value has greater ip_bits, so we can avoid descending in some cases |
437 | * too. |
438 | * |
439 | * This check is less expensive than checking the address bits, so we |
440 | * are doing this before, but it has to be done after for the basic |
441 | * comparison strategies, because ip_bits only affect their results |
442 | * when the common network bits are the same. |
443 | */ |
444 | switch (strategy) |
445 | { |
446 | case RTSubStrategyNumber: |
447 | if (commonbits <= ip_bits(argument)) |
448 | bitmap &= (1 << 2) | (1 << 3); |
449 | break; |
450 | |
451 | case RTSubEqualStrategyNumber: |
452 | if (commonbits < ip_bits(argument)) |
453 | bitmap &= (1 << 2) | (1 << 3); |
454 | break; |
455 | |
456 | case RTSuperStrategyNumber: |
457 | if (commonbits == ip_bits(argument) - 1) |
458 | bitmap &= 1 | (1 << 1); |
459 | else if (commonbits >= ip_bits(argument)) |
460 | bitmap = 0; |
461 | break; |
462 | |
463 | case RTSuperEqualStrategyNumber: |
464 | if (commonbits == ip_bits(argument)) |
465 | bitmap &= 1 | (1 << 1); |
466 | else if (commonbits > ip_bits(argument)) |
467 | bitmap = 0; |
468 | break; |
469 | |
470 | case RTEqualStrategyNumber: |
471 | if (commonbits < ip_bits(argument)) |
472 | bitmap &= (1 << 2) | (1 << 3); |
473 | else if (commonbits == ip_bits(argument)) |
474 | bitmap &= 1 | (1 << 1); |
475 | else |
476 | bitmap = 0; |
477 | break; |
478 | } |
479 | |
480 | if (!bitmap) |
481 | break; |
482 | |
483 | /* |
484 | * Check 2: common network bits |
485 | * |
486 | * Compare available common prefix bits to the query, but not beyond |
487 | * either the query's netmask or the minimum netmask among the |
488 | * represented values. If these bits don't match the query, we can |
489 | * eliminate some cases. |
490 | */ |
491 | order = bitncmp(ip_addr(prefix), ip_addr(argument), |
492 | Min(commonbits, ip_bits(argument))); |
493 | |
494 | if (order != 0) |
495 | { |
496 | switch (strategy) |
497 | { |
498 | case RTLessStrategyNumber: |
499 | case RTLessEqualStrategyNumber: |
500 | if (order > 0) |
501 | bitmap = 0; |
502 | break; |
503 | |
504 | case RTGreaterEqualStrategyNumber: |
505 | case RTGreaterStrategyNumber: |
506 | if (order < 0) |
507 | bitmap = 0; |
508 | break; |
509 | |
510 | case RTNotEqualStrategyNumber: |
511 | break; |
512 | |
513 | default: |
514 | /* For all other cases, we can be sure there is no match */ |
515 | bitmap = 0; |
516 | break; |
517 | } |
518 | |
519 | if (!bitmap) |
520 | break; |
521 | |
522 | /* |
523 | * Remaining checks make no sense when common bits don't match. |
524 | */ |
525 | continue; |
526 | } |
527 | |
528 | /* |
529 | * Check 3: next network bit |
530 | * |
531 | * We can filter out branch 2 or 3 using the next network bit of the |
532 | * argument, if it is available. |
533 | * |
534 | * This check matters for the performance of the search. The results |
535 | * would be correct without it. |
536 | */ |
537 | if (bitmap & ((1 << 2) | (1 << 3)) && |
538 | commonbits < ip_bits(argument)) |
539 | { |
540 | int nextbit; |
541 | |
542 | nextbit = ip_addr(argument)[commonbits / 8] & |
543 | (1 << (7 - commonbits % 8)); |
544 | |
545 | switch (strategy) |
546 | { |
547 | case RTLessStrategyNumber: |
548 | case RTLessEqualStrategyNumber: |
549 | if (!nextbit) |
550 | bitmap &= 1 | (1 << 1) | (1 << 2); |
551 | break; |
552 | |
553 | case RTGreaterEqualStrategyNumber: |
554 | case RTGreaterStrategyNumber: |
555 | if (nextbit) |
556 | bitmap &= 1 | (1 << 1) | (1 << 3); |
557 | break; |
558 | |
559 | case RTNotEqualStrategyNumber: |
560 | break; |
561 | |
562 | default: |
563 | if (!nextbit) |
564 | bitmap &= 1 | (1 << 1) | (1 << 2); |
565 | else |
566 | bitmap &= 1 | (1 << 1) | (1 << 3); |
567 | break; |
568 | } |
569 | |
570 | if (!bitmap) |
571 | break; |
572 | } |
573 | |
574 | /* |
575 | * Remaining checks are only for the basic comparison strategies. This |
576 | * test relies on the strategy number ordering defined in stratnum.h. |
577 | */ |
578 | if (strategy < RTEqualStrategyNumber || |
579 | strategy > RTGreaterEqualStrategyNumber) |
580 | continue; |
581 | |
582 | /* |
583 | * Check 4: network bit count |
584 | * |
585 | * At this point, we know that the common network bits of the prefix |
586 | * and the argument are the same, so we can go forward and check the |
587 | * ip_bits. |
588 | */ |
589 | switch (strategy) |
590 | { |
591 | case RTLessStrategyNumber: |
592 | case RTLessEqualStrategyNumber: |
593 | if (commonbits == ip_bits(argument)) |
594 | bitmap &= 1 | (1 << 1); |
595 | else if (commonbits > ip_bits(argument)) |
596 | bitmap = 0; |
597 | break; |
598 | |
599 | case RTGreaterEqualStrategyNumber: |
600 | case RTGreaterStrategyNumber: |
601 | if (commonbits < ip_bits(argument)) |
602 | bitmap &= (1 << 2) | (1 << 3); |
603 | break; |
604 | } |
605 | |
606 | if (!bitmap) |
607 | break; |
608 | |
609 | /* Remaining checks don't make sense with different ip_bits. */ |
610 | if (commonbits != ip_bits(argument)) |
611 | continue; |
612 | |
613 | /* |
614 | * Check 5: next host bit |
615 | * |
616 | * We can filter out branch 0 or 1 using the next host bit of the |
617 | * argument, if it is available. |
618 | * |
619 | * This check matters for the performance of the search. The results |
620 | * would be correct without it. There is no point in running it for |
621 | * leafs as we have to check the whole address on the next step. |
622 | */ |
623 | if (!leaf && bitmap & (1 | (1 << 1)) && |
624 | commonbits < ip_maxbits(argument)) |
625 | { |
626 | int nextbit; |
627 | |
628 | nextbit = ip_addr(argument)[commonbits / 8] & |
629 | (1 << (7 - commonbits % 8)); |
630 | |
631 | switch (strategy) |
632 | { |
633 | case RTLessStrategyNumber: |
634 | case RTLessEqualStrategyNumber: |
635 | if (!nextbit) |
636 | bitmap &= 1 | (1 << 2) | (1 << 3); |
637 | break; |
638 | |
639 | case RTGreaterEqualStrategyNumber: |
640 | case RTGreaterStrategyNumber: |
641 | if (nextbit) |
642 | bitmap &= (1 << 1) | (1 << 2) | (1 << 3); |
643 | break; |
644 | |
645 | case RTNotEqualStrategyNumber: |
646 | break; |
647 | |
648 | default: |
649 | if (!nextbit) |
650 | bitmap &= 1 | (1 << 2) | (1 << 3); |
651 | else |
652 | bitmap &= (1 << 1) | (1 << 2) | (1 << 3); |
653 | break; |
654 | } |
655 | |
656 | if (!bitmap) |
657 | break; |
658 | } |
659 | |
660 | /* |
661 | * Check 6: whole address |
662 | * |
663 | * This is the last check for correctness of the basic comparison |
664 | * strategies. It's only appropriate at leaf entries. |
665 | */ |
666 | if (leaf) |
667 | { |
668 | /* Redo ordering comparison using all address bits */ |
669 | order = bitncmp(ip_addr(prefix), ip_addr(argument), |
670 | ip_maxbits(prefix)); |
671 | |
672 | switch (strategy) |
673 | { |
674 | case RTLessStrategyNumber: |
675 | if (order >= 0) |
676 | bitmap = 0; |
677 | break; |
678 | |
679 | case RTLessEqualStrategyNumber: |
680 | if (order > 0) |
681 | bitmap = 0; |
682 | break; |
683 | |
684 | case RTEqualStrategyNumber: |
685 | if (order != 0) |
686 | bitmap = 0; |
687 | break; |
688 | |
689 | case RTGreaterEqualStrategyNumber: |
690 | if (order < 0) |
691 | bitmap = 0; |
692 | break; |
693 | |
694 | case RTGreaterStrategyNumber: |
695 | if (order <= 0) |
696 | bitmap = 0; |
697 | break; |
698 | |
699 | case RTNotEqualStrategyNumber: |
700 | if (order == 0) |
701 | bitmap = 0; |
702 | break; |
703 | } |
704 | |
705 | if (!bitmap) |
706 | break; |
707 | } |
708 | } |
709 | |
710 | return bitmap; |
711 | } |
712 | |