Annotation of embedaddon/bird2/nest/a-path.c, revision 1.1
1.1 ! misho 1: /*
! 2: * BIRD -- Path Operations
! 3: *
! 4: * (c) 2000 Martin Mares <mj@ucw.cz>
! 5: * (c) 2000 Pavel Machek <pavel@ucw.cz>
! 6: *
! 7: * Can be freely distributed and used under the terms of the GNU GPL.
! 8: */
! 9:
! 10: #include "nest/bird.h"
! 11: #include "nest/route.h"
! 12: #include "nest/attrs.h"
! 13: #include "lib/resource.h"
! 14: #include "lib/unaligned.h"
! 15: #include "lib/string.h"
! 16: #include "filter/data.h"
! 17:
! 18: // static inline void put_as(byte *data, u32 as) { put_u32(data, as); }
! 19: // static inline u32 get_as(byte *data) { return get_u32(data); }
! 20:
! 21: #define put_as put_u32
! 22: #define get_as get_u32
! 23: #define BS 4 /* Default block size of ASN (autonomous system number) */
! 24:
! 25: #define BAD(DSC, VAL) ({ err_dsc = DSC; err_val = VAL; goto bad; })
! 26:
! 27: int
! 28: as_path_valid(byte *data, uint len, int bs, int confed, char *err, uint elen)
! 29: {
! 30: byte *pos = data;
! 31: char *err_dsc = NULL;
! 32: uint err_val = 0;
! 33:
! 34: while (len)
! 35: {
! 36: if (len < 2)
! 37: BAD("segment framing error", 0);
! 38:
! 39: /* Process one AS path segment */
! 40: uint type = pos[0];
! 41: uint slen = 2 + bs * pos[1];
! 42:
! 43: if (len < slen)
! 44: BAD("segment framing error", len);
! 45:
! 46: switch (type)
! 47: {
! 48: case AS_PATH_SET:
! 49: case AS_PATH_SEQUENCE:
! 50: break;
! 51:
! 52: case AS_PATH_CONFED_SEQUENCE:
! 53: case AS_PATH_CONFED_SET:
! 54: if (!confed)
! 55: BAD("AS_CONFED* segment", type);
! 56: break;
! 57:
! 58: default:
! 59: BAD("unknown segment", type);
! 60: }
! 61:
! 62: if (pos[1] == 0)
! 63: BAD("zero-length segment", type);
! 64:
! 65: pos += slen;
! 66: len -= slen;
! 67: }
! 68:
! 69: return 1;
! 70:
! 71: bad:
! 72: if (err)
! 73: if (bsnprintf(err, elen, "%s (%u) at %d", err_dsc, err_val, (int) (pos - data)) < 0)
! 74: err[0] = 0;
! 75:
! 76: return 0;
! 77: }
! 78:
! 79: int
! 80: as_path_16to32(byte *dst, const byte *src, uint len)
! 81: {
! 82: byte *dst0 = dst;
! 83: const byte *end = src + len;
! 84: uint i, n;
! 85:
! 86: while (src < end)
! 87: {
! 88: n = src[1];
! 89: *dst++ = *src++;
! 90: *dst++ = *src++;
! 91:
! 92: for (i = 0; i < n; i++)
! 93: {
! 94: put_u32(dst, get_u16(src));
! 95: src += 2;
! 96: dst += 4;
! 97: }
! 98: }
! 99:
! 100: return dst - dst0;
! 101: }
! 102:
! 103: int
! 104: as_path_32to16(byte *dst, const byte *src, uint len)
! 105: {
! 106: byte *dst0 = dst;
! 107: const byte *end = src + len;
! 108: uint i, n;
! 109:
! 110: while (src < end)
! 111: {
! 112: n = src[1];
! 113: *dst++ = *src++;
! 114: *dst++ = *src++;
! 115:
! 116: for (i = 0; i < n; i++)
! 117: {
! 118: put_u16(dst, get_u32(src));
! 119: src += 4;
! 120: dst += 2;
! 121: }
! 122: }
! 123:
! 124: return dst - dst0;
! 125: }
! 126:
! 127: int
! 128: as_path_contains_as4(const struct adata *path)
! 129: {
! 130: const byte *pos = path->data;
! 131: const byte *end = pos + path->length;
! 132: uint i, n;
! 133:
! 134: while (pos < end)
! 135: {
! 136: n = pos[1];
! 137: pos += 2;
! 138:
! 139: for (i = 0; i < n; i++)
! 140: {
! 141: if (get_as(pos) > 0xFFFF)
! 142: return 1;
! 143:
! 144: pos += BS;
! 145: }
! 146: }
! 147:
! 148: return 0;
! 149: }
! 150:
! 151: int
! 152: as_path_contains_confed(const struct adata *path)
! 153: {
! 154: const byte *pos = path->data;
! 155: const byte *end = pos + path->length;
! 156:
! 157: while (pos < end)
! 158: {
! 159: uint type = pos[0];
! 160: uint slen = 2 + BS * pos[1];
! 161:
! 162: if ((type == AS_PATH_CONFED_SEQUENCE) ||
! 163: (type == AS_PATH_CONFED_SET))
! 164: return 1;
! 165:
! 166: pos += slen;
! 167: }
! 168:
! 169: return 0;
! 170: }
! 171:
! 172: struct adata *
! 173: as_path_strip_confed(struct linpool *pool, const struct adata *path)
! 174: {
! 175: struct adata *res = lp_alloc_adata(pool, path->length);
! 176: const byte *src = path->data;
! 177: const byte *end = src + path->length;
! 178: byte *dst = res->data;
! 179:
! 180: while (src < end)
! 181: {
! 182: uint type = src[0];
! 183: uint slen = 2 + BS * src[1];
! 184:
! 185: /* Copy regular segments */
! 186: if ((type == AS_PATH_SET) || (type == AS_PATH_SEQUENCE))
! 187: {
! 188: memcpy(dst, src, slen);
! 189: dst += slen;
! 190: }
! 191:
! 192: src += slen;
! 193: }
! 194:
! 195: /* Fix the result length */
! 196: res->length = dst - res->data;
! 197:
! 198: return res;
! 199: }
! 200:
! 201: struct adata *
! 202: as_path_prepend2(struct linpool *pool, const struct adata *op, int seq, u32 as)
! 203: {
! 204: struct adata *np;
! 205: const byte *pos = op->data;
! 206: uint len = op->length;
! 207:
! 208: if (len && (pos[0] == seq) && (pos[1] < 255))
! 209: {
! 210: /* Starting with matching segment => just prepend the AS number */
! 211: np = lp_alloc_adata(pool, len + BS);
! 212: np->data[0] = seq;
! 213: np->data[1] = pos[1] + 1;
! 214: put_as(np->data + 2, as);
! 215:
! 216: uint dlen = BS * pos[1];
! 217: memcpy(np->data + 2 + BS, pos + 2, dlen);
! 218: ADVANCE(pos, len, 2 + dlen);
! 219: }
! 220: else
! 221: {
! 222: /* Create a new path segment */
! 223: np = lp_alloc_adata(pool, len + 2 + BS);
! 224: np->data[0] = seq;
! 225: np->data[1] = 1;
! 226: put_as(np->data + 2, as);
! 227: }
! 228:
! 229: if (len)
! 230: {
! 231: byte *dst = np->data + 2 + BS * np->data[1];
! 232:
! 233: memcpy(dst, pos, len);
! 234: }
! 235:
! 236: return np;
! 237: }
! 238:
! 239:
! 240: struct adata *
! 241: as_path_to_old(struct linpool *pool, const struct adata *path)
! 242: {
! 243: struct adata *res = lp_alloc_adata(pool, path->length);
! 244: byte *pos = res->data;
! 245: byte *end = pos + res->length;
! 246: uint i, n;
! 247: u32 as;
! 248:
! 249: /* Copy the whole path */
! 250: memcpy(res->data, path->data, path->length);
! 251:
! 252: /* Replace 32-bit AS numbers with AS_TRANS */
! 253: while (pos < end)
! 254: {
! 255: n = pos[1];
! 256: pos += 2;
! 257:
! 258: for (i = 0; i < n; i++)
! 259: {
! 260: as = get_as(pos);
! 261: if (as > 0xFFFF)
! 262: put_as(pos, AS_TRANS);
! 263:
! 264: pos += BS;
! 265: }
! 266: }
! 267:
! 268: return res;
! 269: }
! 270:
! 271: /*
! 272: * Cut the path to the length @num, measured to the usual path metric. Note that
! 273: * AS_CONFED_* segments have zero length and must be added if they are on edge.
! 274: */
! 275: struct adata *
! 276: as_path_cut(struct linpool *pool, const struct adata *path, uint num)
! 277: {
! 278: const byte *pos = path->data;
! 279: const byte *end = pos + path->length;
! 280:
! 281: while (pos < end)
! 282: {
! 283: uint t = pos[0];
! 284: uint l = pos[1];
! 285: uint n = 0;
! 286:
! 287: switch (t)
! 288: {
! 289: case AS_PATH_SET: n = 1; break;
! 290: case AS_PATH_SEQUENCE: n = l; break;
! 291: case AS_PATH_CONFED_SEQUENCE: n = 0; break;
! 292: case AS_PATH_CONFED_SET: n = 0; break;
! 293: default: bug("as_path_cut: Invalid path segment");
! 294: }
! 295:
! 296: /* Cannot add whole segment, so try partial one and finish */
! 297: if (num < n)
! 298: {
! 299: const byte *nend = pos;
! 300: if (num)
! 301: nend += 2 + BS * num;
! 302:
! 303: struct adata *res = lp_alloc_adata(pool, path->length);
! 304: res->length = nend - (const byte *) path->data;
! 305: memcpy(res->data, path->data, res->length);
! 306:
! 307: if (num)
! 308: {
! 309: byte *dpos = ((byte *) res->data) + (pos - (const byte *) path->data);
! 310: dpos[1] = num;
! 311: }
! 312:
! 313: return res;
! 314: }
! 315:
! 316: num -= n;
! 317: pos += 2 + BS * l;
! 318: }
! 319:
! 320: struct adata *res = lp_alloc_adata(pool, path->length);
! 321: res->length = path->length;
! 322: memcpy(res->data, path->data, res->length);
! 323: return res;
! 324: }
! 325:
! 326: /*
! 327: * Merge (concatenate) paths @p1 and @p2 and return the result.
! 328: * In contrast to other as_path_* functions, @p1 and @p2 may be reused.
! 329: */
! 330: const struct adata *
! 331: as_path_merge(struct linpool *pool, const struct adata *p1, const struct adata *p2)
! 332: {
! 333: if (p1->length == 0)
! 334: return p2;
! 335:
! 336: if (p2->length == 0)
! 337: return p1;
! 338:
! 339: struct adata *res = lp_alloc_adata(pool, p1->length + p2->length);
! 340: memcpy(res->data, p1->data, p1->length);
! 341: memcpy(res->data + p1->length, p2->data, p2->length);
! 342:
! 343: return res;
! 344: }
! 345:
! 346: void
! 347: as_path_format(const struct adata *path, byte *bb, uint size)
! 348: {
! 349: buffer buf = { .start = bb, .pos = bb, .end = bb + size }, *b = &buf;
! 350: const byte *pos = path->data;
! 351: const byte *end = pos + path->length;
! 352: const char *ops, *cls;
! 353:
! 354: b->pos[0] = 0;
! 355:
! 356: while (pos < end)
! 357: {
! 358: uint type = pos[0];
! 359: uint len = pos[1];
! 360: pos += 2;
! 361:
! 362: switch (type)
! 363: {
! 364: case AS_PATH_SET: ops = "{"; cls = "}"; break;
! 365: case AS_PATH_SEQUENCE: ops = NULL; cls = NULL; break;
! 366: case AS_PATH_CONFED_SEQUENCE: ops = "("; cls = ")"; break;
! 367: case AS_PATH_CONFED_SET: ops = "({"; cls = "})"; break;
! 368: default: bug("Invalid path segment");
! 369: }
! 370:
! 371: if (ops)
! 372: buffer_puts(b, ops);
! 373:
! 374: while (len--)
! 375: {
! 376: buffer_print(b, len ? "%u " : "%u", get_as(pos));
! 377: pos += BS;
! 378: }
! 379:
! 380: if (cls)
! 381: buffer_puts(b, cls);
! 382:
! 383: if (pos < end)
! 384: buffer_puts(b, " ");
! 385: }
! 386:
! 387: /* Handle overflow */
! 388: if (b->pos == b->end)
! 389: strcpy(b->end - 12, "...");
! 390: }
! 391:
! 392: int
! 393: as_path_getlen(const struct adata *path)
! 394: {
! 395: const byte *pos = path->data;
! 396: const byte *end = pos + path->length;
! 397: uint res = 0;
! 398:
! 399: while (pos < end)
! 400: {
! 401: uint t = pos[0];
! 402: uint l = pos[1];
! 403: uint n = 0;
! 404:
! 405: switch (t)
! 406: {
! 407: case AS_PATH_SET: n = 1; break;
! 408: case AS_PATH_SEQUENCE: n = l; break;
! 409: case AS_PATH_CONFED_SEQUENCE: n = 0; break;
! 410: case AS_PATH_CONFED_SET: n = 0; break;
! 411: default: bug("as_path_getlen: Invalid path segment");
! 412: }
! 413:
! 414: res += n;
! 415: pos += 2 + BS * l;
! 416: }
! 417:
! 418: return res;
! 419: }
! 420:
! 421: int
! 422: as_path_get_last(const struct adata *path, u32 *orig_as)
! 423: {
! 424: const byte *pos = path->data;
! 425: const byte *end = pos + path->length;
! 426: int found = 0;
! 427: u32 val = 0;
! 428:
! 429: while (pos < end)
! 430: {
! 431: uint type = pos[0];
! 432: uint len = pos[1];
! 433: pos += 2;
! 434:
! 435: if (!len)
! 436: continue;
! 437:
! 438: switch (type)
! 439: {
! 440: case AS_PATH_SET:
! 441: case AS_PATH_CONFED_SET:
! 442: found = 0;
! 443: break;
! 444:
! 445: case AS_PATH_SEQUENCE:
! 446: case AS_PATH_CONFED_SEQUENCE:
! 447: val = get_as(pos + BS * (len - 1));
! 448: found = 1;
! 449: break;
! 450:
! 451: default:
! 452: bug("Invalid path segment");
! 453: }
! 454:
! 455: pos += BS * len;
! 456: }
! 457:
! 458: if (found)
! 459: *orig_as = val;
! 460: return found;
! 461: }
! 462:
! 463: u32
! 464: as_path_get_last_nonaggregated(const struct adata *path)
! 465: {
! 466: const byte *pos = path->data;
! 467: const byte *end = pos + path->length;
! 468: u32 val = 0;
! 469:
! 470: while (pos < end)
! 471: {
! 472: uint type = pos[0];
! 473: uint len = pos[1];
! 474: pos += 2;
! 475:
! 476: if (!len)
! 477: continue;
! 478:
! 479: switch (type)
! 480: {
! 481: case AS_PATH_SET:
! 482: case AS_PATH_CONFED_SET:
! 483: return val;
! 484:
! 485: case AS_PATH_SEQUENCE:
! 486: case AS_PATH_CONFED_SEQUENCE:
! 487: val = get_as(pos + BS * (len - 1));
! 488: break;
! 489:
! 490: default:
! 491: bug("Invalid path segment");
! 492: }
! 493:
! 494: pos += BS * len;
! 495: }
! 496:
! 497: return val;
! 498: }
! 499:
! 500: int
! 501: as_path_get_first(const struct adata *path, u32 *last_as)
! 502: {
! 503: const u8 *p = path->data;
! 504:
! 505: if ((path->length == 0) || (p[0] != AS_PATH_SEQUENCE) || (p[1] == 0))
! 506: return 0;
! 507:
! 508: *last_as = get_as(p+2);
! 509: return 1;
! 510: }
! 511:
! 512: int
! 513: as_path_get_first_regular(const struct adata *path, u32 *last_as)
! 514: {
! 515: const byte *pos = path->data;
! 516: const byte *end = pos + path->length;
! 517:
! 518: while (pos < end)
! 519: {
! 520: uint type = pos[0];
! 521: uint len = pos[1];
! 522: pos += 2;
! 523:
! 524: switch (type)
! 525: {
! 526: case AS_PATH_SET:
! 527: return 0;
! 528:
! 529: case AS_PATH_SEQUENCE:
! 530: if (len == 0)
! 531: return 0;
! 532:
! 533: *last_as = get_as(pos);
! 534: return 1;
! 535:
! 536: case AS_PATH_CONFED_SEQUENCE:
! 537: case AS_PATH_CONFED_SET:
! 538: break;
! 539:
! 540: default:
! 541: bug("Invalid path segment");
! 542: }
! 543:
! 544: pos += BS * len;
! 545: }
! 546:
! 547: return 0;
! 548: }
! 549:
! 550: int
! 551: as_path_contains(const struct adata *path, u32 as, int min)
! 552: {
! 553: const u8 *p = path->data;
! 554: const u8 *q = p+path->length;
! 555: int num = 0;
! 556: int i, n;
! 557:
! 558: while (p<q)
! 559: {
! 560: n = p[1];
! 561: p += 2;
! 562: for(i=0; i<n; i++)
! 563: {
! 564: if (get_as(p) == as)
! 565: if (++num == min)
! 566: return 1;
! 567: p += BS;
! 568: }
! 569: }
! 570: return 0;
! 571: }
! 572:
! 573: int
! 574: as_path_match_set(const struct adata *path, const struct f_tree *set)
! 575: {
! 576: const u8 *p = path->data;
! 577: const u8 *q = p+path->length;
! 578: int i, n;
! 579:
! 580: while (p<q)
! 581: {
! 582: n = p[1];
! 583: p += 2;
! 584: for (i=0; i<n; i++)
! 585: {
! 586: struct f_val v = {T_INT, .val.i = get_as(p)};
! 587: if (find_tree(set, &v))
! 588: return 1;
! 589: p += BS;
! 590: }
! 591: }
! 592:
! 593: return 0;
! 594: }
! 595:
! 596: const struct adata *
! 597: as_path_filter(struct linpool *pool, const struct adata *path, const struct f_tree *set, u32 key, int pos)
! 598: {
! 599: if (!path)
! 600: return NULL;
! 601:
! 602: int len = path->length;
! 603: const u8 *p = path->data;
! 604: const u8 *q = path->data + len;
! 605: u8 *d, *d2;
! 606: int i, bt, sn, dn;
! 607: u8 buf[len];
! 608:
! 609: d = buf;
! 610: while (p<q)
! 611: {
! 612: /* Read block header (type and length) */
! 613: bt = p[0];
! 614: sn = p[1];
! 615: dn = 0;
! 616: p += 2;
! 617: d2 = d + 2;
! 618:
! 619: for (i = 0; i < sn; i++)
! 620: {
! 621: u32 as = get_as(p);
! 622: int match;
! 623:
! 624: if (set)
! 625: {
! 626: struct f_val v = {T_INT, .val.i = as};
! 627: match = !!find_tree(set, &v);
! 628: }
! 629: else
! 630: match = (as == key);
! 631:
! 632: if (match == pos)
! 633: {
! 634: put_as(d2, as);
! 635: d2 += BS;
! 636: dn++;
! 637: }
! 638:
! 639: p += BS;
! 640: }
! 641:
! 642: if (dn > 0)
! 643: {
! 644: /* Nonempty block, set block header and advance */
! 645: d[0] = bt;
! 646: d[1] = dn;
! 647: d = d2;
! 648: }
! 649: }
! 650:
! 651: uint nl = d - buf;
! 652: if (nl == path->length)
! 653: return path;
! 654:
! 655: struct adata *res = lp_alloc(pool, sizeof(struct adata) + nl);
! 656: res->length = nl;
! 657: memcpy(res->data, buf, nl);
! 658:
! 659: return res;
! 660: }
! 661:
! 662:
! 663: struct pm_pos
! 664: {
! 665: u8 set;
! 666: u8 mark;
! 667: union
! 668: {
! 669: const char *sp;
! 670: u32 asn;
! 671: } val;
! 672: };
! 673:
! 674: static int
! 675: parse_path(const struct adata *path, struct pm_pos *pp)
! 676: {
! 677: const byte *pos = path->data;
! 678: const byte *end = pos + path->length;
! 679: struct pm_pos *op = pp;
! 680: uint i;
! 681:
! 682: while (pos < end)
! 683: {
! 684: uint type = pos[0];
! 685: uint len = pos[1];
! 686: pos += 2;
! 687:
! 688: switch (type)
! 689: {
! 690: case AS_PATH_SET:
! 691: case AS_PATH_CONFED_SET:
! 692: pp->set = 1;
! 693: pp->mark = 0;
! 694: pp->val.sp = pos - 1;
! 695: pp++;
! 696:
! 697: pos += BS * len;
! 698: break;
! 699:
! 700: case AS_PATH_SEQUENCE:
! 701: case AS_PATH_CONFED_SEQUENCE:
! 702: for (i = 0; i < len; i++)
! 703: {
! 704: pp->set = 0;
! 705: pp->mark = 0;
! 706: pp->val.asn = get_as(pos);
! 707: pp++;
! 708:
! 709: pos += BS;
! 710: }
! 711: break;
! 712:
! 713: default:
! 714: bug("Invalid path segment");
! 715: }
! 716: }
! 717:
! 718: return pp - op;
! 719: }
! 720:
! 721: static int
! 722: pm_match(struct pm_pos *pos, u32 asn, u32 asn2)
! 723: {
! 724: u32 gas;
! 725: if (! pos->set)
! 726: return ((pos->val.asn >= asn) && (pos->val.asn <= asn2));
! 727:
! 728: const u8 *p = pos->val.sp;
! 729: int len = *p++;
! 730: int i;
! 731:
! 732: for (i = 0; i < len; i++)
! 733: {
! 734: gas = get_as(p + i * BS);
! 735:
! 736: if ((gas >= asn) && (gas <= asn2))
! 737: return 1;
! 738: }
! 739:
! 740: return 0;
! 741: }
! 742:
! 743: static int
! 744: pm_match_set(struct pm_pos *pos, const struct f_tree *set)
! 745: {
! 746: struct f_val asn = { .type = T_INT };
! 747:
! 748: if (! pos->set)
! 749: {
! 750: asn.val.i = pos->val.asn;
! 751: return !!find_tree(set, &asn);
! 752: }
! 753:
! 754: const u8 *p = pos->val.sp;
! 755: int len = *p++;
! 756: int i;
! 757:
! 758: for (i = 0; i < len; i++)
! 759: {
! 760: asn.val.i = get_as(p + i * BS);
! 761: if (find_tree(set, &asn))
! 762: return 1;
! 763: }
! 764:
! 765: return 0;
! 766: }
! 767:
! 768: static void
! 769: pm_mark(struct pm_pos *pos, int i, int plen, int *nl, int *nh)
! 770: {
! 771: int j;
! 772:
! 773: if (pos[i].set)
! 774: pos[i].mark = 1;
! 775:
! 776: for (j = i + 1; (j < plen) && pos[j].set && (! pos[j].mark); j++)
! 777: pos[j].mark = 1;
! 778: pos[j].mark = 1;
! 779:
! 780: /* We are going downwards, therefore every mark is
! 781: new low and just the first mark is new high */
! 782:
! 783: *nl = i + (pos[i].set ? 0 : 1);
! 784:
! 785: if (*nh < 0)
! 786: *nh = j;
! 787: }
! 788:
! 789: /* AS path matching is nontrivial. Because AS path can
! 790: * contain sets, it is not a plain wildcard matching. A set
! 791: * in an AS path is interpreted as it might represent any
! 792: * sequence of AS numbers from that set (possibly with
! 793: * repetitions). So it is also a kind of a pattern,
! 794: * more complicated than a path mask.
! 795: *
! 796: * The algorithm for AS path matching is a variant
! 797: * of nondeterministic finite state machine, where
! 798: * positions in AS path are states, and items in
! 799: * path mask are input for that finite state machine.
! 800: * During execution of the algorithm we maintain a set
! 801: * of marked states - a state is marked if it can be
! 802: * reached by any walk through NFSM with regard to
! 803: * currently processed part of input. When we process
! 804: * next part of mask, we advance each marked state.
! 805: * We start with marked first position, when we
! 806: * run out of marked positions, we reject. When
! 807: * we process the whole mask, we accept if final position
! 808: * (auxiliary position after last real position in AS path)
! 809: * is marked.
! 810: */
! 811: int
! 812: as_path_match(const struct adata *path, const struct f_path_mask *mask)
! 813: {
! 814: struct pm_pos pos[2048 + 1];
! 815: int plen = parse_path(path, pos);
! 816: int l, h, i, nh, nl;
! 817: u32 val = 0;
! 818: u32 val2 = 0;
! 819:
! 820: /* l and h are bound of interval of positions where
! 821: are marked states */
! 822:
! 823: pos[plen].set = 0;
! 824: pos[plen].mark = 0;
! 825:
! 826: l = h = 0;
! 827: pos[0].mark = 1;
! 828:
! 829: for (uint m=0; m < mask->len; m++)
! 830: {
! 831: /* We remove this mark to not step after pos[plen] */
! 832: pos[plen].mark = 0;
! 833:
! 834: switch (mask->item[m].kind)
! 835: {
! 836: case PM_ASTERISK:
! 837: for (i = l; i <= plen; i++)
! 838: pos[i].mark = 1;
! 839: h = plen;
! 840: break;
! 841:
! 842: case PM_ASN: /* Define single ASN as ASN..ASN - very narrow interval */
! 843: val2 = val = mask->item[m].asn;
! 844: goto step;
! 845: case PM_ASN_EXPR:
! 846: bug("Expressions should be evaluated on AS path mask construction.");
! 847: case PM_ASN_RANGE:
! 848: val = mask->item[m].from;
! 849: val2 = mask->item[m].to;
! 850: goto step;
! 851: case PM_QUESTION:
! 852: case PM_ASN_SET:
! 853: step:
! 854: nh = nl = -1;
! 855: for (i = h; i >= l; i--)
! 856: if (pos[i].mark)
! 857: {
! 858: pos[i].mark = 0;
! 859: if ((mask->item[m].kind == PM_QUESTION) ||
! 860: ((mask->item[m].kind != PM_ASN_SET) ?
! 861: pm_match(pos + i, val, val2) :
! 862: pm_match_set(pos + i, mask->item[m].set)))
! 863: pm_mark(pos, i, plen, &nl, &nh);
! 864: }
! 865:
! 866: if (nh < 0)
! 867: return 0;
! 868:
! 869: h = nh;
! 870: l = nl;
! 871: break;
! 872: }
! 873: }
! 874:
! 875: return pos[plen].mark;
! 876: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>