Annotation of embedaddon/bird/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/filter.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
! 24:
! 25: struct adata *
! 26: as_path_prepend(struct linpool *pool, struct adata *olda, u32 as)
! 27: {
! 28: struct adata *newa;
! 29:
! 30: if (olda->length && olda->data[0] == AS_PATH_SEQUENCE && olda->data[1] < 255)
! 31: /* Starting with sequence => just prepend the AS number */
! 32: {
! 33: int nl = olda->length + BS;
! 34: newa = lp_alloc(pool, sizeof(struct adata) + nl);
! 35: newa->length = nl;
! 36: newa->data[0] = AS_PATH_SEQUENCE;
! 37: newa->data[1] = olda->data[1] + 1;
! 38: memcpy(newa->data + BS + 2, olda->data + 2, olda->length - 2);
! 39: }
! 40: else /* Create new path segment */
! 41: {
! 42: int nl = olda->length + BS + 2;
! 43: newa = lp_alloc(pool, sizeof(struct adata) + nl);
! 44: newa->length = nl;
! 45: newa->data[0] = AS_PATH_SEQUENCE;
! 46: newa->data[1] = 1;
! 47: memcpy(newa->data + BS + 2, olda->data, olda->length);
! 48: }
! 49: put_as(newa->data + 2, as);
! 50: return newa;
! 51: }
! 52:
! 53: int
! 54: as_path_convert_to_old(struct adata *path, byte *dst, int *new_used)
! 55: {
! 56: byte *src = path->data;
! 57: byte *src_end = src + path->length;
! 58: byte *dst_start = dst;
! 59: u32 as;
! 60: int i, n;
! 61: *new_used = 0;
! 62:
! 63: while (src < src_end)
! 64: {
! 65: n = src[1];
! 66: *dst++ = *src++;
! 67: *dst++ = *src++;
! 68:
! 69: for(i=0; i<n; i++)
! 70: {
! 71: as = get_u32(src);
! 72: if (as > 0xFFFF)
! 73: {
! 74: as = AS_TRANS;
! 75: *new_used = 1;
! 76: }
! 77: put_u16(dst, as);
! 78: src += 4;
! 79: dst += 2;
! 80: }
! 81: }
! 82:
! 83: return dst - dst_start;
! 84: }
! 85:
! 86: int
! 87: as_path_convert_to_new(struct adata *path, byte *dst, int req_as)
! 88: {
! 89: byte *src = path->data;
! 90: byte *src_end = src + path->length;
! 91: byte *dst_start = dst;
! 92: u32 as;
! 93: int i, t, n;
! 94:
! 95:
! 96: while ((src < src_end) && (req_as > 0))
! 97: {
! 98: t = *src++;
! 99: n = *src++;
! 100:
! 101: if (t == AS_PATH_SEQUENCE)
! 102: {
! 103: if (n > req_as)
! 104: n = req_as;
! 105:
! 106: req_as -= n;
! 107: }
! 108: else // t == AS_PATH_SET
! 109: req_as--;
! 110:
! 111: *dst++ = t;
! 112: *dst++ = n;
! 113:
! 114: for(i=0; i<n; i++)
! 115: {
! 116: as = get_u16(src);
! 117: put_u32(dst, as);
! 118: src += 2;
! 119: dst += 4;
! 120: }
! 121: }
! 122:
! 123: return dst - dst_start;
! 124: }
! 125:
! 126: void
! 127: as_path_format(struct adata *path, byte *buf, uint size)
! 128: {
! 129: byte *p = path->data;
! 130: byte *e = p + path->length;
! 131: byte *end = buf + size - 16;
! 132: int sp = 1;
! 133: int l, isset;
! 134:
! 135: while (p < e)
! 136: {
! 137: if (buf > end)
! 138: {
! 139: strcpy(buf, " ...");
! 140: return;
! 141: }
! 142: isset = (*p++ == AS_PATH_SET);
! 143: l = *p++;
! 144: if (isset)
! 145: {
! 146: if (!sp)
! 147: *buf++ = ' ';
! 148: *buf++ = '{';
! 149: sp = 0;
! 150: }
! 151: while (l-- && buf <= end)
! 152: {
! 153: if (!sp)
! 154: *buf++ = ' ';
! 155: buf += bsprintf(buf, "%u", get_as(p));
! 156: p += BS;
! 157: sp = 0;
! 158: }
! 159: if (isset)
! 160: {
! 161: *buf++ = ' ';
! 162: *buf++ = '}';
! 163: sp = 0;
! 164: }
! 165: }
! 166: *buf = 0;
! 167: }
! 168:
! 169: int
! 170: as_path_getlen(struct adata *path)
! 171: {
! 172: return as_path_getlen_int(path, BS);
! 173: }
! 174:
! 175: int
! 176: as_path_getlen_int(struct adata *path, int bs)
! 177: {
! 178: int res = 0;
! 179: u8 *p = path->data;
! 180: u8 *q = p+path->length;
! 181: int len;
! 182:
! 183: while (p<q)
! 184: {
! 185: switch (*p++)
! 186: {
! 187: case AS_PATH_SET: len = *p++; res++; p += bs * len; break;
! 188: case AS_PATH_SEQUENCE: len = *p++; res += len; p += bs * len; break;
! 189: default: bug("as_path_getlen: Invalid path segment");
! 190: }
! 191: }
! 192: return res;
! 193: }
! 194:
! 195: int
! 196: as_path_get_last(struct adata *path, u32 *orig_as)
! 197: {
! 198: int found = 0;
! 199: u32 res = 0;
! 200: u8 *p = path->data;
! 201: u8 *q = p+path->length;
! 202: int len;
! 203:
! 204: while (p<q)
! 205: {
! 206: switch (*p++)
! 207: {
! 208: case AS_PATH_SET:
! 209: if (len = *p++)
! 210: {
! 211: found = 0;
! 212: p += BS * len;
! 213: }
! 214: break;
! 215: case AS_PATH_SEQUENCE:
! 216: if (len = *p++)
! 217: {
! 218: found = 1;
! 219: res = get_as(p + BS * (len - 1));
! 220: p += BS * len;
! 221: }
! 222: break;
! 223: default: bug("Invalid path segment");
! 224: }
! 225: }
! 226:
! 227: if (found)
! 228: *orig_as = res;
! 229: return found;
! 230: }
! 231:
! 232: u32
! 233: as_path_get_last_nonaggregated(struct adata *path)
! 234: {
! 235: u8 *p = path->data;
! 236: u8 *q = p+path->length;
! 237: u32 res = 0;
! 238: int len;
! 239:
! 240: while (p<q)
! 241: {
! 242: switch (*p++)
! 243: {
! 244: case AS_PATH_SET:
! 245: return res;
! 246:
! 247: case AS_PATH_SEQUENCE:
! 248: if (len = *p++)
! 249: res = get_as(p + BS * (len - 1));
! 250: p += BS * len;
! 251: break;
! 252:
! 253: default: bug("Invalid path segment");
! 254: }
! 255: }
! 256:
! 257: return res;
! 258: }
! 259:
! 260:
! 261: int
! 262: as_path_get_first(struct adata *path, u32 *last_as)
! 263: {
! 264: u8 *p = path->data;
! 265:
! 266: if ((path->length == 0) || (p[0] != AS_PATH_SEQUENCE) || (p[1] == 0))
! 267: return 0;
! 268: else
! 269: {
! 270: *last_as = get_as(p+2);
! 271: return 1;
! 272: }
! 273: }
! 274:
! 275: int
! 276: as_path_contains(struct adata *path, u32 as, int min)
! 277: {
! 278: u8 *p = path->data;
! 279: u8 *q = p+path->length;
! 280: int num = 0;
! 281: int i, n;
! 282:
! 283: while (p<q)
! 284: {
! 285: n = p[1];
! 286: p += 2;
! 287: for(i=0; i<n; i++)
! 288: {
! 289: if (get_as(p) == as)
! 290: if (++num == min)
! 291: return 1;
! 292: p += BS;
! 293: }
! 294: }
! 295: return 0;
! 296: }
! 297:
! 298: int
! 299: as_path_match_set(struct adata *path, struct f_tree *set)
! 300: {
! 301: u8 *p = path->data;
! 302: u8 *q = p+path->length;
! 303: int i, n;
! 304:
! 305: while (p<q)
! 306: {
! 307: n = p[1];
! 308: p += 2;
! 309: for (i=0; i<n; i++)
! 310: {
! 311: struct f_val v = {T_INT, .val.i = get_as(p)};
! 312: if (find_tree(set, v))
! 313: return 1;
! 314: p += BS;
! 315: }
! 316: }
! 317:
! 318: return 0;
! 319: }
! 320:
! 321: struct adata *
! 322: as_path_filter(struct linpool *pool, struct adata *path, struct f_tree *set, u32 key, int pos)
! 323: {
! 324: if (!path)
! 325: return NULL;
! 326:
! 327: int len = path->length;
! 328: u8 *p = path->data;
! 329: u8 *q = path->data + len;
! 330: u8 *d, *d2;
! 331: int i, bt, sn, dn;
! 332: u8 buf[len];
! 333:
! 334: d = buf;
! 335: while (p<q)
! 336: {
! 337: /* Read block header (type and length) */
! 338: bt = p[0];
! 339: sn = p[1];
! 340: dn = 0;
! 341: p += 2;
! 342: d2 = d + 2;
! 343:
! 344: for (i = 0; i < sn; i++)
! 345: {
! 346: u32 as = get_as(p);
! 347: int match;
! 348:
! 349: if (set)
! 350: match = !!find_tree(set, (struct f_val){T_INT, .val.i = as});
! 351: else
! 352: match = (as == key);
! 353:
! 354: if (match == pos)
! 355: {
! 356: put_as(d2, as);
! 357: d2 += BS;
! 358: dn++;
! 359: }
! 360:
! 361: p += BS;
! 362: }
! 363:
! 364: if (dn > 0)
! 365: {
! 366: /* Nonempty block, set block header and advance */
! 367: d[0] = bt;
! 368: d[1] = dn;
! 369: d = d2;
! 370: }
! 371: }
! 372:
! 373: uint nl = d - buf;
! 374: if (nl == path->length)
! 375: return path;
! 376:
! 377: struct adata *res = lp_alloc(pool, sizeof(struct adata) + nl);
! 378: res->length = nl;
! 379: memcpy(res->data, buf, nl);
! 380:
! 381: return res;
! 382: }
! 383:
! 384:
! 385: struct pm_pos
! 386: {
! 387: u8 set;
! 388: u8 mark;
! 389: union
! 390: {
! 391: char *sp;
! 392: u32 asn;
! 393: } val;
! 394: };
! 395:
! 396: static int
! 397: parse_path(struct adata *path, struct pm_pos *pos)
! 398: {
! 399: u8 *p = path->data;
! 400: u8 *q = p + path->length;
! 401: struct pm_pos *opos = pos;
! 402: int i, len;
! 403:
! 404:
! 405: while (p < q)
! 406: switch (*p++)
! 407: {
! 408: case AS_PATH_SET:
! 409: pos->set = 1;
! 410: pos->mark = 0;
! 411: pos->val.sp = p;
! 412: len = *p;
! 413: p += 1 + BS * len;
! 414: pos++;
! 415: break;
! 416:
! 417: case AS_PATH_SEQUENCE:
! 418: len = *p++;
! 419: for (i = 0; i < len; i++)
! 420: {
! 421: pos->set = 0;
! 422: pos->mark = 0;
! 423: pos->val.asn = get_as(p);
! 424: p += BS;
! 425: pos++;
! 426: }
! 427: break;
! 428:
! 429: default:
! 430: bug("as_path_match: Invalid path component");
! 431: }
! 432:
! 433: return pos - opos;
! 434: }
! 435:
! 436:
! 437: static int
! 438: pm_match(struct pm_pos *pos, u32 asn, u32 asn2)
! 439: {
! 440: u32 gas;
! 441: if (! pos->set)
! 442: return ((pos->val.asn >= asn) && (pos->val.asn <= asn2));
! 443:
! 444: u8 *p = pos->val.sp;
! 445: int len = *p++;
! 446: int i;
! 447:
! 448: for (i = 0; i < len; i++)
! 449: {
! 450: gas = get_as(p + i * BS);
! 451:
! 452: if ((gas >= asn) && (gas <= asn2))
! 453: return 1;
! 454: }
! 455:
! 456: return 0;
! 457: }
! 458:
! 459: static void
! 460: pm_mark(struct pm_pos *pos, int i, int plen, int *nl, int *nh)
! 461: {
! 462: int j;
! 463:
! 464: if (pos[i].set)
! 465: pos[i].mark = 1;
! 466:
! 467: for (j = i + 1; (j < plen) && pos[j].set && (! pos[j].mark); j++)
! 468: pos[j].mark = 1;
! 469: pos[j].mark = 1;
! 470:
! 471: /* We are going downwards, therefore every mark is
! 472: new low and just the first mark is new high */
! 473:
! 474: *nl = i + (pos[i].set ? 0 : 1);
! 475:
! 476: if (*nh < 0)
! 477: *nh = j;
! 478: }
! 479:
! 480: /* AS path matching is nontrivial. Because AS path can
! 481: * contain sets, it is not a plain wildcard matching. A set
! 482: * in an AS path is interpreted as it might represent any
! 483: * sequence of AS numbers from that set (possibly with
! 484: * repetitions). So it is also a kind of a pattern,
! 485: * more complicated than a path mask.
! 486: *
! 487: * The algorithm for AS path matching is a variant
! 488: * of nondeterministic finite state machine, where
! 489: * positions in AS path are states, and items in
! 490: * path mask are input for that finite state machine.
! 491: * During execution of the algorithm we maintain a set
! 492: * of marked states - a state is marked if it can be
! 493: * reached by any walk through NFSM with regard to
! 494: * currently processed part of input. When we process
! 495: * next part of mask, we advance each marked state.
! 496: * We start with marked first position, when we
! 497: * run out of marked positions, we reject. When
! 498: * we process the whole mask, we accept if final position
! 499: * (auxiliary position after last real position in AS path)
! 500: * is marked.
! 501: */
! 502:
! 503: int
! 504: as_path_match(struct adata *path, struct f_path_mask *mask)
! 505: {
! 506: struct pm_pos pos[2048 + 1];
! 507: int plen = parse_path(path, pos);
! 508: int l, h, i, nh, nl;
! 509: u32 val = 0;
! 510: u32 val2 = 0;
! 511:
! 512: /* l and h are bound of interval of positions where
! 513: are marked states */
! 514:
! 515: pos[plen].set = 0;
! 516: pos[plen].mark = 0;
! 517:
! 518: l = h = 0;
! 519: pos[0].mark = 1;
! 520:
! 521: while (mask)
! 522: {
! 523: /* We remove this mark to not step after pos[plen] */
! 524: pos[plen].mark = 0;
! 525:
! 526: switch (mask->kind)
! 527: {
! 528: case PM_ASTERISK:
! 529: for (i = l; i <= plen; i++)
! 530: pos[i].mark = 1;
! 531: h = plen;
! 532: break;
! 533:
! 534: case PM_ASN: /* Define single ASN as ASN..ASN - very narrow interval */
! 535: val2 = val = mask->val;
! 536: goto step;
! 537: case PM_ASN_EXPR:
! 538: val2 = val = f_eval_asn((struct f_inst *) mask->val);
! 539: goto step;
! 540: case PM_ASN_RANGE:
! 541: val = mask->val;
! 542: val2 = mask->val2;
! 543: goto step;
! 544: case PM_QUESTION:
! 545: step:
! 546: nh = nl = -1;
! 547: for (i = h; i >= l; i--)
! 548: if (pos[i].mark)
! 549: {
! 550: pos[i].mark = 0;
! 551: if ((mask->kind == PM_QUESTION) || pm_match(pos + i, val, val2))
! 552: pm_mark(pos, i, plen, &nl, &nh);
! 553: }
! 554:
! 555: if (nh < 0)
! 556: return 0;
! 557:
! 558: h = nh;
! 559: l = nl;
! 560: break;
! 561: }
! 562:
! 563: mask = mask->next;
! 564: }
! 565:
! 566: return pos[plen].mark;
! 567: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>