Annotation of embedaddon/bird2/nest/a-path.c, revision 1.1.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>