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>