Annotation of embedaddon/bird/nest/a-path.c, revision 1.1.1.2

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:
1.1.1.2 ! misho     538:          ASSERT(0);
1.1       misho     539:        case PM_ASN_RANGE:
                    540:          val = mask->val;
                    541:          val2 = mask->val2;
                    542:           goto step;
                    543:        case PM_QUESTION:
                    544:        step:
                    545:          nh = nl = -1;
                    546:          for (i = h; i >= l; i--)
                    547:            if (pos[i].mark)
                    548:              {
                    549:                pos[i].mark = 0;
                    550:                if ((mask->kind == PM_QUESTION) || pm_match(pos + i, val, val2))
                    551:                  pm_mark(pos, i, plen, &nl, &nh);
                    552:              }
                    553: 
                    554:          if (nh < 0)
                    555:            return 0;
                    556: 
                    557:          h = nh;
                    558:          l = nl;
                    559:          break;
                    560:        }
                    561: 
                    562:       mask = mask->next;
                    563:     }
                    564: 
                    565:   return pos[plen].mark;
                    566: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>