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>