Annotation of embedaddon/bird/nest/rt-roa.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  *     BIRD -- Route Origin Authorization
        !             3:  *
        !             4:  *
        !             5:  *     Can be freely distributed and used under the terms of the GNU GPL.
        !             6:  */
        !             7: 
        !             8: #undef LOCAL_DEBUG
        !             9: 
        !            10: #include "nest/bird.h"
        !            11: #include "nest/route.h"
        !            12: #include "nest/cli.h"
        !            13: #include "lib/lists.h"
        !            14: #include "lib/resource.h"
        !            15: #include "lib/event.h"
        !            16: #include "lib/string.h"
        !            17: #include "conf/conf.h"
        !            18: 
        !            19: 
        !            20: pool *roa_pool;
        !            21: static slab *roa_slab;                 /* Slab of struct roa_item */
        !            22: static list roa_table_list;            /* List of struct roa_table */
        !            23: struct roa_table *roa_table_default;   /* The first ROA table in the config */
        !            24: 
        !            25: static inline int
        !            26: src_match(struct roa_item *it, byte src)
        !            27: { return !src || it->src == src; }
        !            28: 
        !            29: /**
        !            30:  * roa_add_item - add a ROA entry
        !            31:  * @t: ROA table
        !            32:  * @prefix: prefix of the ROA entry
        !            33:  * @pxlen: prefix length of the ROA entry
        !            34:  * @maxlen: max length field of the ROA entry
        !            35:  * @asn: AS number field of the ROA entry
        !            36:  * @src: source of the ROA entry (ROA_SRC_*)
        !            37:  *
        !            38:  * The function adds a new ROA entry to the ROA table. If the same ROA
        !            39:  * is already in the table, nothing is added. @src field is used to
        !            40:  * distinguish different sources of ROAs.
        !            41:  */
        !            42: void
        !            43: roa_add_item(struct roa_table *t, ip_addr prefix, byte pxlen, byte maxlen, u32 asn, byte src)
        !            44: {
        !            45:   struct roa_node *n = fib_get(&t->fib, &prefix, pxlen);
        !            46: 
        !            47:   // if ((n->items == NULL) && (n->n.x0 != ROA_INVALID))
        !            48:   // t->cached_items--;
        !            49: 
        !            50:   struct roa_item *it;
        !            51:   for (it = n->items; it; it = it->next)
        !            52:     if ((it->maxlen == maxlen) && (it->asn == asn) && src_match(it, src))
        !            53:       return;
        !            54: 
        !            55:   it = sl_alloc(roa_slab);
        !            56:   it->asn = asn;
        !            57:   it->maxlen = maxlen;
        !            58:   it->src = src;
        !            59:   it->next = n->items;
        !            60:   n->items = it;
        !            61: }
        !            62: 
        !            63: /**
        !            64:  * roa_delete_item - delete a ROA entry
        !            65:  * @t: ROA table
        !            66:  * @prefix: prefix of the ROA entry
        !            67:  * @pxlen: prefix length of the ROA entry
        !            68:  * @maxlen: max length field of the ROA entry
        !            69:  * @asn: AS number field of the ROA entry
        !            70:  * @src: source of the ROA entry (ROA_SRC_*)
        !            71:  *
        !            72:  * The function removes a specified ROA entry from the ROA table and
        !            73:  * frees it. If @src field is not ROA_SRC_ANY, only entries from
        !            74:  * that source are considered.
        !            75:  */
        !            76: void
        !            77: roa_delete_item(struct roa_table *t, ip_addr prefix, byte pxlen, byte maxlen, u32 asn, byte src)
        !            78: {
        !            79:   struct roa_node *n = fib_find(&t->fib, &prefix, pxlen);
        !            80: 
        !            81:   if (!n)
        !            82:     return;
        !            83: 
        !            84:   struct roa_item *it, **itp;
        !            85:   for (itp = &n->items; it = *itp; itp = &it->next)
        !            86:     if ((it->maxlen == maxlen) && (it->asn == asn) && src_match(it, src))
        !            87:       break;
        !            88: 
        !            89:   if (!it)
        !            90:     return;
        !            91: 
        !            92:   *itp = it->next;
        !            93:   sl_free(roa_slab, it);
        !            94: 
        !            95:   // if ((n->items == NULL) && (n->n.x0 != ROA_INVALID))
        !            96:   // t->cached_items++;
        !            97: }
        !            98: 
        !            99: 
        !           100: /**
        !           101:  * roa_flush - flush a ROA table
        !           102:  * @t: ROA table
        !           103:  * @src: source of ROA entries (ROA_SRC_*)
        !           104:  *
        !           105:  * The function removes and frees ROA entries from the ROA table. If
        !           106:  * @src is ROA_SRC_ANY, all entries in the table are removed,
        !           107:  * otherwise only all entries from that source are removed.
        !           108:  */
        !           109: void
        !           110: roa_flush(struct roa_table *t, byte src)
        !           111: {
        !           112:   struct roa_item *it, **itp;
        !           113:   struct roa_node *n;
        !           114: 
        !           115:   FIB_WALK(&t->fib, fn)
        !           116:     {
        !           117:       n = (struct roa_node *) fn;
        !           118: 
        !           119:       itp = &n->items;
        !           120:       while (it = *itp)
        !           121:        if (src_match(it, src))
        !           122:          {
        !           123:            *itp = it->next;
        !           124:            sl_free(roa_slab, it);
        !           125:          }
        !           126:        else
        !           127:          itp = &it->next;
        !           128:     }
        !           129:   FIB_WALK_END;
        !           130: 
        !           131:   // TODO add cleanup of roa_nodes
        !           132: }
        !           133: 
        !           134: 
        !           135: 
        !           136: /*
        !           137: byte
        !           138: roa_check(struct roa_table *t, ip_addr prefix, byte pxlen, u32 asn)
        !           139: {
        !           140:   struct roa_node *n = fib_find(&t->fib, &prefix, pxlen);
        !           141: 
        !           142:   if (n && n->n.x0 == ROA_UNKNOWN)
        !           143:     return ROA_UNKNOWN;
        !           144: 
        !           145:   if (n && n->n.x0 == ROA_VALID && asn == n->cached_asn)
        !           146:     return ROA_VALID;
        !           147: 
        !           148:   byte rv = roa_match(t, n, prefix, pxlen, asn);
        !           149: 
        !           150:   if (rv != ROA_INVALID)
        !           151:     {
        !           152:       if (!n)
        !           153:        {
        !           154:          if (t->cached_items >= t->cached_items_max)
        !           155:          n = fib_get(&t->fib, &prefix, pxlen);
        !           156:          t->cached_items++;
        !           157:        }
        !           158: 
        !           159:       n->cached_asn = asn;
        !           160:       n->n.x0 = rv;
        !           161:     }
        !           162: 
        !           163:   return rv;
        !           164: }
        !           165: */
        !           166: 
        !           167: /**
        !           168:  * roa_check - check validity of route origination in a ROA table 
        !           169:  * @t: ROA table
        !           170:  * @prefix: network prefix to check
        !           171:  * @pxlen: length of network prefix
        !           172:  * @asn: AS number of network prefix
        !           173:  *
        !           174:  * Implements RFC 6483 route validation for the given network
        !           175:  * prefix. The procedure is to find all candidate ROAs - ROAs whose
        !           176:  * prefixes cover the give network prefix. If there is no candidate
        !           177:  * ROA, return ROA_UNKNOWN. If there is a candidate ROA with matching
        !           178:  * ASN and maxlen field greater than or equal to the given prefix
        !           179:  * length, return ROA_VALID. Otherwise return ROA_INVALID. If caller
        !           180:  * cannot determine origin AS, 0 could be used (in that case ROA_VALID
        !           181:  * cannot happen).
        !           182:  */
        !           183: byte
        !           184: roa_check(struct roa_table *t, ip_addr prefix, byte pxlen, u32 asn)
        !           185: {
        !           186:   struct roa_node *n;
        !           187:   ip_addr px;
        !           188:   byte anything = 0;
        !           189: 
        !           190:   int len;
        !           191:   for (len = pxlen; len >= 0; len--)
        !           192:     {
        !           193:       px = ipa_and(prefix, ipa_mkmask(len));
        !           194:       n = fib_find(&t->fib, &px, len);
        !           195: 
        !           196:       if (!n)
        !           197:        continue;
        !           198: 
        !           199:       struct roa_item *it;
        !           200:       for (it = n->items; it; it = it->next)
        !           201:        {
        !           202:          anything = 1;
        !           203:          if ((it->maxlen >= pxlen) && (it->asn == asn) && asn)
        !           204:            return ROA_VALID;
        !           205:        }
        !           206:     }
        !           207: 
        !           208:   return anything ? ROA_INVALID : ROA_UNKNOWN;
        !           209: }
        !           210: 
        !           211: static void
        !           212: roa_node_init(struct fib_node *fn)
        !           213: {
        !           214:   struct roa_node *n = (struct roa_node *) fn;
        !           215:   n->items = NULL;
        !           216: }
        !           217: 
        !           218: static inline void
        !           219: roa_populate(struct roa_table *t)
        !           220: {
        !           221:   struct roa_item_config *ric;
        !           222:   for (ric = t->cf->roa_items; ric; ric = ric->next)
        !           223:     roa_add_item(t, ric->prefix, ric->pxlen, ric->maxlen, ric->asn, ROA_SRC_CONFIG);
        !           224: }
        !           225: 
        !           226: static void
        !           227: roa_new_table(struct roa_table_config *cf)
        !           228: {
        !           229:   struct roa_table *t;
        !           230: 
        !           231:   t = mb_allocz(roa_pool, sizeof(struct roa_table));
        !           232:   fib_init(&t->fib, roa_pool, sizeof(struct roa_node), 0, roa_node_init);
        !           233:   t->name = cf->name;
        !           234:   t->cf = cf;
        !           235: 
        !           236:   cf->table = t;
        !           237:   add_tail(&roa_table_list, &t->n);
        !           238: 
        !           239:   roa_populate(t);
        !           240: }
        !           241: 
        !           242: struct roa_table_config *
        !           243: roa_new_table_config(struct symbol *s)
        !           244: {
        !           245:   struct roa_table_config *rtc = cfg_allocz(sizeof(struct roa_table_config));
        !           246: 
        !           247:   cf_define_symbol(s, SYM_ROA, rtc);
        !           248:   rtc->name = s->name;
        !           249:   add_tail(&new_config->roa_tables, &rtc->n);
        !           250:   return rtc;
        !           251: }
        !           252: 
        !           253: /**
        !           254:  * roa_add_item_config - add a static ROA entry to a ROA table configuration
        !           255:  *
        !           256:  * Arguments are self-explanatory. The first is the ROA table config, rest
        !           257:  * are specifying the ROA entry.
        !           258:  */
        !           259: void
        !           260: roa_add_item_config(struct roa_table_config *rtc, ip_addr prefix, byte pxlen, byte maxlen, u32 asn)
        !           261: {
        !           262:   struct roa_item_config *ric = cfg_allocz(sizeof(struct roa_item_config));
        !           263: 
        !           264:   ric->prefix = prefix;
        !           265:   ric->pxlen = pxlen;
        !           266:   ric->maxlen = maxlen;
        !           267:   ric->asn = asn;
        !           268:   ric->next = rtc->roa_items;
        !           269:   rtc->roa_items = ric;
        !           270: }
        !           271: 
        !           272: /**
        !           273:  * roa_init - initialize ROA tables
        !           274:  *
        !           275:  * This function is called during BIRD startup. It initializes
        !           276:  * the ROA table module.
        !           277:  */
        !           278: void
        !           279: roa_init(void)
        !           280: {
        !           281:   roa_pool = rp_new(&root_pool, "ROA tables");
        !           282:   roa_slab = sl_new(roa_pool, sizeof(struct roa_item));
        !           283:   init_list(&roa_table_list);
        !           284: }
        !           285: 
        !           286: void
        !           287: roa_preconfig(struct config *c)
        !           288: {
        !           289:   init_list(&c->roa_tables);
        !           290: }
        !           291: 
        !           292: 
        !           293: /**
        !           294:  * roa_commit - commit new ROA table configuration
        !           295:  * @new: new configuration
        !           296:  * @old: original configuration or %NULL if it's boot time config
        !           297:  *
        !           298:  * Scan differences between @old and @new configuration and modify the
        !           299:  * ROA tables according to these changes. If @new defines a previously
        !           300:  * unknown table, create it, if it omits a table existing in @old,
        !           301:  * delete it (there are no references, only indirect through struct
        !           302:  * roa_table_config). If it exists in both configurations, update the
        !           303:  * configured ROA entries.
        !           304:  */
        !           305: void
        !           306: roa_commit(struct config *new, struct config *old)
        !           307: {
        !           308:   struct roa_table_config *cf;
        !           309:   struct roa_table *t;
        !           310: 
        !           311:   if (old)
        !           312:     WALK_LIST(t, roa_table_list)
        !           313:       {
        !           314:        struct symbol *sym = cf_find_symbol(new, t->name);
        !           315:        if (sym && sym->class == SYM_ROA)
        !           316:          {
        !           317:            /* Found old table in new config */
        !           318:            cf = sym->def;
        !           319:            cf->table = t;
        !           320:            t->name = cf->name;
        !           321:            t->cf = cf;
        !           322: 
        !           323:            /* Reconfigure it */
        !           324:            roa_flush(t, ROA_SRC_CONFIG);
        !           325:            roa_populate(t);
        !           326:          }
        !           327:        else
        !           328:          {
        !           329:            t->cf->table = NULL;
        !           330: 
        !           331:            /* Free it now */
        !           332:            roa_flush(t, ROA_SRC_ANY);
        !           333:            rem_node(&t->n);
        !           334:            fib_free(&t->fib);
        !           335:            mb_free(t);
        !           336:          }
        !           337:       }
        !           338: 
        !           339:   /* Add new tables */
        !           340:   WALK_LIST(cf, new->roa_tables)
        !           341:     if (! cf->table)
        !           342:       roa_new_table(cf);
        !           343: 
        !           344:   roa_table_default = EMPTY_LIST(new->roa_tables) ? NULL :
        !           345:     ((struct roa_table_config *) HEAD(new->roa_tables))->table;
        !           346: }
        !           347: 
        !           348: 
        !           349: 
        !           350: static void
        !           351: roa_show_node(struct cli *c, struct roa_node *rn, int len, u32 asn)
        !           352: {
        !           353:   struct roa_item *ri;
        !           354: 
        !           355:   for (ri = rn->items; ri; ri = ri->next)
        !           356:     if ((ri->maxlen >= len) && (!asn || (ri->asn == asn)))
        !           357:       cli_printf(c, -1019, "%I/%d max %d as %u", rn->n.prefix, rn->n.pxlen, ri->maxlen, ri->asn);
        !           358: }
        !           359: 
        !           360: static void
        !           361: roa_show_cont(struct cli *c)
        !           362: {
        !           363:   struct roa_show_data *d = c->rover;
        !           364:   struct fib *fib = &d->table->fib;
        !           365:   struct fib_iterator *it = &d->fit;
        !           366:   struct roa_node *rn;
        !           367:   unsigned max = 32;
        !           368: 
        !           369:   FIB_ITERATE_START(fib, it, f)
        !           370:     {
        !           371:       rn = (struct roa_node *) f;
        !           372: 
        !           373:       if (!max--)
        !           374:        {
        !           375:          FIB_ITERATE_PUT(it, f);
        !           376:          return;
        !           377:        }
        !           378: 
        !           379:       if ((d->mode == ROA_SHOW_ALL) ||
        !           380:          net_in_net(rn->n.prefix, rn->n.pxlen, d->prefix, d->pxlen))
        !           381:        roa_show_node(c, rn, 0, d->asn);
        !           382:     }
        !           383:   FIB_ITERATE_END(f);
        !           384: 
        !           385:   cli_printf(c, 0, "");
        !           386:   c->cont = c->cleanup = NULL;
        !           387: }
        !           388: 
        !           389: static void
        !           390: roa_show_cleanup(struct cli *c)
        !           391: {
        !           392:   struct roa_show_data *d = c->rover;
        !           393: 
        !           394:   /* Unlink the iterator */
        !           395:   fit_get(&d->table->fib, &d->fit);
        !           396: }
        !           397: 
        !           398: void
        !           399: roa_show(struct roa_show_data *d)
        !           400: {
        !           401:   struct roa_node *rn;
        !           402:   ip_addr px;
        !           403:   int len;
        !           404: 
        !           405:   switch (d->mode)
        !           406:     {
        !           407:     case ROA_SHOW_ALL:
        !           408:     case ROA_SHOW_IN:
        !           409:       FIB_ITERATE_INIT(&d->fit, &d->table->fib);
        !           410:       this_cli->cont = roa_show_cont;
        !           411:       this_cli->cleanup = roa_show_cleanup;
        !           412:       this_cli->rover = d;
        !           413:       break;
        !           414: 
        !           415:     case ROA_SHOW_PX:
        !           416:       rn = fib_find(&d->table->fib, &d->prefix, d->pxlen);
        !           417:       if (rn)
        !           418:        {
        !           419:          roa_show_node(this_cli, rn, 0, d->asn);
        !           420:          cli_msg(0, "");
        !           421:        }
        !           422:       else
        !           423:        cli_msg(-8001, "Network not in table");
        !           424:       break;
        !           425: 
        !           426:     case ROA_SHOW_FOR:
        !           427:       for (len = d->pxlen; len >= 0; len--)
        !           428:        {
        !           429:          px = ipa_and(d->prefix, ipa_mkmask(len));
        !           430:          rn = fib_find(&d->table->fib, &px, len);
        !           431: 
        !           432:          if (!rn)
        !           433:            continue;
        !           434: 
        !           435:          roa_show_node(this_cli, rn, 0, d->asn);
        !           436:        }
        !           437:       cli_msg(0, "");
        !           438:       break;
        !           439:     }
        !           440: }

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