Annotation of embedaddon/bird2/proto/mrt/mrt.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  *     BIRD -- Multi-Threaded Routing Toolkit (MRT) Protocol
        !             3:  *
        !             4:  *     (c) 2017--2018 Ondrej Zajicek <santiago@crfreenet.org>
        !             5:  *     (c) 2017--2018 CZ.NIC z.s.p.o.
        !             6:  *
        !             7:  *     Can be freely distributed and used under the terms of the GNU GPL.
        !             8:  */
        !             9: 
        !            10: /**
        !            11:  * DOC: Multi-Threaded Routing Toolkit (MRT) protocol
        !            12:  *
        !            13:  * The MRT protocol is implemented in just one file: |mrt.c|. It contains of
        !            14:  * several parts: Generic functions for preparing MRT messages in a buffer,
        !            15:  * functions for MRT table dump (called from timer or CLI), functions for MRT
        !            16:  * BGP4MP dump (called from BGP), and the usual protocol glue. For the MRT table
        !            17:  * dump, the key structure is struct mrt_table_dump_state, which contains all
        !            18:  * necessary data and created when the MRT dump cycle is started for the
        !            19:  * duration of the MRT dump. The MBGP4MP dump is currently not bound to MRT
        !            20:  * protocol instance and uses the config->mrtdump_file fd.
        !            21:  *
        !            22:  * The protocol is simple, just periodically scans routing table and export it
        !            23:  * to a file. It does not use the regular update mechanism, but a direct access
        !            24:  * in order to handle iteration through multiple routing tables. The table dump
        !            25:  * needs to dump all peers first and then use indexes to address the peers, we
        !            26:  * use a hash table (@peer_hash) to find peer index based on BGP protocol key
        !            27:  * attributes.
        !            28:  *
        !            29:  * One thing worth documenting is the locking. During processing, the currently
        !            30:  * processed table (@table field in the state structure) is locked and also the
        !            31:  * explicitly named table is locked (@table_ptr field in the state structure) if
        !            32:  * specified. Between dumps no table is locked. Also the current config is
        !            33:  * locked (by config_add_obstacle()) during table dumps as some data (strings,
        !            34:  * filters) are shared from the config and the running table dump may be
        !            35:  * interrupted by reconfiguration.
        !            36:  *
        !            37:  * Supported standards:
        !            38:  * - RFC 6396 - MRT format standard
        !            39:  * - RFC 8050 - ADD_PATH extension
        !            40:  */
        !            41: 
        !            42: #include <unistd.h>
        !            43: #include <limits.h>
        !            44: #include <errno.h>
        !            45: 
        !            46: #include "mrt.h"
        !            47: 
        !            48: #include "nest/cli.h"
        !            49: #include "filter/filter.h"
        !            50: #include "proto/bgp/bgp.h"
        !            51: #include "sysdep/unix/unix.h"
        !            52: 
        !            53: 
        !            54: #ifdef PATH_MAX
        !            55: #define BIRD_PATH_MAX PATH_MAX
        !            56: #else
        !            57: #define BIRD_PATH_MAX 4096
        !            58: #endif
        !            59: 
        !            60: #define mrt_log(s, msg, args...)                               \
        !            61:   ({                                                           \
        !            62:     if (s->cli)                                                        \
        !            63:       cli_printf(s->cli, -8009, msg, ## args);                 \
        !            64:     if (s->proto)                                              \
        !            65:       log(L_ERR "%s: " msg, s->proto->p.name, ## args);                \
        !            66:   })
        !            67: 
        !            68: 
        !            69: /*
        !            70:  *     MRT buffer code
        !            71:  */
        !            72: 
        !            73: static void
        !            74: mrt_buffer_init(buffer *b, pool *pool, size_t n)
        !            75: {
        !            76:   b->start = mb_alloc(pool, n);
        !            77:   b->pos = b->start;
        !            78:   b->end = b->start + n;
        !            79: }
        !            80: 
        !            81: static void
        !            82: mrt_buffer_grow(buffer *b, size_t n)
        !            83: {
        !            84:   size_t used = b->pos - b->start;
        !            85:   size_t size = b->end - b->start;
        !            86:   size_t req = used + n;
        !            87: 
        !            88:   while (size < req)
        !            89:     size = size * 3 / 2;
        !            90: 
        !            91:   b->start = mb_realloc(b->start, size);
        !            92:   b->pos = b->start + used;
        !            93:   b->end = b->start + size;
        !            94: }
        !            95: 
        !            96: static inline void
        !            97: mrt_buffer_need(buffer *b, size_t n)
        !            98: {
        !            99:   if (b->pos + n > b->end)
        !           100:     mrt_buffer_grow(b, n);
        !           101: }
        !           102: 
        !           103: static inline uint
        !           104: mrt_buffer_pos(buffer *b)
        !           105: {
        !           106:   return b->pos - b->start;
        !           107: }
        !           108: 
        !           109: static inline void
        !           110: mrt_buffer_flush(buffer *b)
        !           111: {
        !           112:   b->pos = b->start;
        !           113: }
        !           114: 
        !           115: #define MRT_DEFINE_TYPE(S, T)                                          \
        !           116:   static inline void mrt_put_##S##_(buffer *b, T x)                    \
        !           117:   {                                                                    \
        !           118:     put_##S(b->pos, x);                                                        \
        !           119:     b->pos += sizeof(T);                                               \
        !           120:   }                                                                    \
        !           121:                                                                        \
        !           122:   static inline void mrt_put_##S(buffer *b, T x)                       \
        !           123:   {                                                                    \
        !           124:     mrt_buffer_need(b, sizeof(T));                                     \
        !           125:     put_##S(b->pos, x);                                                        \
        !           126:     b->pos += sizeof(T);                                               \
        !           127:   }
        !           128: 
        !           129: MRT_DEFINE_TYPE(u8, u8)
        !           130: MRT_DEFINE_TYPE(u16, u16)
        !           131: MRT_DEFINE_TYPE(u32, u32)
        !           132: MRT_DEFINE_TYPE(u64, u64)
        !           133: MRT_DEFINE_TYPE(ip4, ip4_addr)
        !           134: MRT_DEFINE_TYPE(ip6, ip6_addr)
        !           135: 
        !           136: static inline void
        !           137: mrt_put_ipa(buffer *b, ip_addr x)
        !           138: {
        !           139:   if (ipa_is_ip4(x))
        !           140:     mrt_put_ip4(b, ipa_to_ip4(x));
        !           141:   else
        !           142:     mrt_put_ip6(b, ipa_to_ip6(x));
        !           143: }
        !           144: 
        !           145: static inline void
        !           146: mrt_put_data(buffer *b, const void *src, size_t n)
        !           147: {
        !           148:   if (!n)
        !           149:     return;
        !           150: 
        !           151:   mrt_buffer_need(b, n);
        !           152:   memcpy(b->pos, src, n);
        !           153:   b->pos += n;
        !           154: }
        !           155: 
        !           156: static void
        !           157: mrt_init_message(buffer *b, u16 type, u16 subtype)
        !           158: {
        !           159:   /* Reset buffer */
        !           160:   mrt_buffer_flush(b);
        !           161:   mrt_buffer_need(b, MRT_HDR_LENGTH);
        !           162: 
        !           163:   /* Prepare header */
        !           164:   mrt_put_u32_(b, current_real_time() TO_S); /* now_real */
        !           165:   mrt_put_u16_(b, type);
        !           166:   mrt_put_u16_(b, subtype);
        !           167: 
        !           168:   /* Message length, will be fixed later */
        !           169:   mrt_put_u32_(b, 0);
        !           170: }
        !           171: 
        !           172: static void
        !           173: mrt_dump_message(buffer *b, int fd)
        !           174: {
        !           175:   uint len = mrt_buffer_pos(b);
        !           176: 
        !           177:   /* Fix message length */
        !           178:   ASSERT(len >= MRT_HDR_LENGTH);
        !           179:   put_u32(b->start + 8, len - MRT_HDR_LENGTH);
        !           180: 
        !           181:   if (fd < 0)
        !           182:     return;
        !           183: 
        !           184:   if (write(fd, b->start, len) < 0)
        !           185:     log(L_ERR "Write to MRT file failed: %m"); /* TODO: name of file */
        !           186: }
        !           187: 
        !           188: static int
        !           189: bstrsub(char *dst, size_t n, const char *src, const char *key, const char *val)
        !           190: {
        !           191:   const char *last, *next;
        !           192:   char *pos = dst;
        !           193:   size_t step, klen = strlen(key), vlen = strlen(val);
        !           194: 
        !           195:   for (last = src; next = strstr(last, key); last = next + klen)
        !           196:   {
        !           197:     step = next - last;
        !           198:     if (n <= step + vlen)
        !           199:       return 0;
        !           200: 
        !           201:     memcpy(pos, last, step);
        !           202:     ADVANCE(pos, n, step);
        !           203: 
        !           204:     memcpy(pos, val, vlen);
        !           205:     ADVANCE(pos, n, vlen);
        !           206:   }
        !           207: 
        !           208:   step = strlen(last);
        !           209:   if (n <= step)
        !           210:     return 0;
        !           211: 
        !           212:   memcpy(pos, last, step);
        !           213:   ADVANCE(pos, n, step);
        !           214: 
        !           215:   pos[0] = 0;
        !           216:   return 1;
        !           217: }
        !           218: 
        !           219: static inline rtable *
        !           220: mrt_next_table_(rtable *tab, rtable *tab_ptr, const char *pattern)
        !           221: {
        !           222:   /* Handle explicit table, return it in the first pass */
        !           223:   if (tab_ptr)
        !           224:     return !tab ? tab_ptr : NULL;
        !           225: 
        !           226:   /* Walk routing_tables list, starting after tab (if non-NULL) */
        !           227:   for (tab = !tab ? HEAD(routing_tables) : NODE_NEXT(tab);
        !           228:        NODE_VALID(tab);
        !           229:        tab = NODE_NEXT(tab))
        !           230:     if (patmatch(pattern, tab->name) &&
        !           231:        ((tab->addr_type == NET_IP4) || (tab->addr_type == NET_IP6)))
        !           232:       return tab;
        !           233: 
        !           234:   return NULL;
        !           235: }
        !           236: 
        !           237: static rtable *
        !           238: mrt_next_table(struct mrt_table_dump_state *s)
        !           239: {
        !           240:   rtable *tab = mrt_next_table_(s->table, s->table_ptr, s->table_expr);
        !           241: 
        !           242:   if (s->table)
        !           243:     rt_unlock_table(s->table);
        !           244: 
        !           245:   s->table = tab;
        !           246:   s->ipv4 = tab ? (tab->addr_type == NET_IP4) : 0;
        !           247:   s->bws->mp_reach = !s->ipv4;
        !           248: 
        !           249:   if (s->table)
        !           250:     rt_lock_table(s->table);
        !           251: 
        !           252:   return s->table;
        !           253: }
        !           254: 
        !           255: static int
        !           256: mrt_open_file(struct mrt_table_dump_state *s)
        !           257: {
        !           258:   char fmt1[BIRD_PATH_MAX];
        !           259:   char name[BIRD_PATH_MAX];
        !           260:   btime now = current_time();
        !           261:   btime now_real = current_real_time();
        !           262: 
        !           263:   if (!bstrsub(fmt1, sizeof(fmt1), s->filename, "%N", s->table->name) ||
        !           264:       !tm_format_real_time(name, sizeof(name), fmt1, now_real))
        !           265:   {
        !           266:     mrt_log(s, "Invalid filename '%s'", s->filename);
        !           267:     return 0;
        !           268:   }
        !           269: 
        !           270:   s->file = rf_open(s->pool, name, "a");
        !           271:   if (!s->file)
        !           272:   {
        !           273:     mrt_log(s, "Unable to open MRT file '%s': %m", name);
        !           274:     return 0;
        !           275:   }
        !           276: 
        !           277:   s->fd = rf_fileno(s->file);
        !           278:   s->time_offset = now_real - now;
        !           279: 
        !           280:   return 1;
        !           281: }
        !           282: 
        !           283: static void
        !           284: mrt_close_file(struct mrt_table_dump_state *s)
        !           285: {
        !           286:   rfree(s->file);
        !           287:   s->file = NULL;
        !           288:   s->fd = -1;
        !           289: }
        !           290: 
        !           291: 
        !           292: /*
        !           293:  *     MRT Table Dump: Peer Index Table
        !           294:  */
        !           295: 
        !           296: #define PEER_KEY(n)            n->peer_id, n->peer_as, n->peer_ip
        !           297: #define PEER_NEXT(n)           n->next
        !           298: #define PEER_EQ(id1,as1,ip1,id2,as2,ip2) \
        !           299:   id1 == id2 && as1 == as2 && ipa_equal(ip1, ip2)
        !           300: #define PEER_FN(id,as,ip)      ipa_hash(ip)
        !           301: 
        !           302: static void
        !           303: mrt_peer_table_header(struct mrt_table_dump_state *s, u32 router_id, const char *name)
        !           304: {
        !           305:   buffer *b = &s->buf;
        !           306: 
        !           307:   /* Collector BGP ID */
        !           308:   mrt_put_u32(b, router_id);
        !           309: 
        !           310:   /* View Name */
        !           311:   uint name_length = name ? strlen(name) : 0;
        !           312:   name_length = MIN(name_length, 65535);
        !           313:   mrt_put_u16(b, name_length);
        !           314:   mrt_put_data(b, name, name_length);
        !           315: 
        !           316:   /* Peer Count, will be fixed later */
        !           317:   s->peer_count = 0;
        !           318:   s->peer_count_offset = mrt_buffer_pos(b);
        !           319:   mrt_put_u16(b, 0);
        !           320: 
        !           321:   HASH_INIT(s->peer_hash, s->pool, 10);
        !           322: }
        !           323: 
        !           324: static void
        !           325: mrt_peer_table_entry(struct mrt_table_dump_state *s, u32 peer_id, u32 peer_as, ip_addr peer_ip)
        !           326: {
        !           327:   buffer *b = &s->buf;
        !           328: 
        !           329:   uint type = MRT_PEER_TYPE_32BIT_ASN;
        !           330:   if (ipa_is_ip6(peer_ip))
        !           331:     type |= MRT_PEER_TYPE_IPV6;
        !           332: 
        !           333:   /* Dump peer to buffer */
        !           334:   mrt_put_u8(b, type);
        !           335:   mrt_put_u32(b, peer_id);
        !           336:   mrt_put_ipa(b, peer_ip);
        !           337:   mrt_put_u32(b, peer_as);
        !           338: 
        !           339:   /* Add peer to hash table */
        !           340:   struct mrt_peer_entry *n = lp_allocz(s->peer_lp, sizeof(struct mrt_peer_entry));
        !           341:   n->peer_id = peer_id;
        !           342:   n->peer_as = peer_as;
        !           343:   n->peer_ip = peer_ip;
        !           344:   n->index = s->peer_count++;
        !           345: 
        !           346:   HASH_INSERT(s->peer_hash, PEER, n);
        !           347: }
        !           348: 
        !           349: static void
        !           350: mrt_peer_table_dump(struct mrt_table_dump_state *s)
        !           351: {
        !           352:   mrt_init_message(&s->buf, MRT_TABLE_DUMP_V2, MRT_PEER_INDEX_TABLE);
        !           353:   mrt_peer_table_header(s, config->router_id, s->table->name);
        !           354: 
        !           355:   /* 0 is fake peer for non-BGP routes */
        !           356:   mrt_peer_table_entry(s, 0, 0, IPA_NONE);
        !           357: 
        !           358: #ifdef CONFIG_BGP
        !           359:   struct proto *P;
        !           360:   WALK_LIST(P, proto_list)
        !           361:     if ((P->proto == &proto_bgp) && (P->proto_state != PS_DOWN))
        !           362:     {
        !           363:       struct bgp_proto *p = (void *) P;
        !           364:       mrt_peer_table_entry(s, p->remote_id, p->remote_as, p->remote_ip);
        !           365:     }
        !           366: #endif
        !           367: 
        !           368:   /* Fix Peer Count */
        !           369:   put_u16(s->buf.start + s->peer_count_offset, s->peer_count);
        !           370: 
        !           371:   mrt_dump_message(&s->buf, s->fd);
        !           372: }
        !           373: 
        !           374: static void
        !           375: mrt_peer_table_flush(struct mrt_table_dump_state *s)
        !           376: {
        !           377:   lp_flush(s->peer_lp);
        !           378:   HASH_FREE(s->peer_hash);
        !           379: }
        !           380: 
        !           381: 
        !           382: /*
        !           383:  *     MRT Table Dump: RIB Table
        !           384:  */
        !           385: 
        !           386: static void
        !           387: mrt_rib_table_header(struct mrt_table_dump_state *s, net_addr *n)
        !           388: {
        !           389:   buffer *b = &s->buf;
        !           390: 
        !           391:   /* Sequence Number */
        !           392:   mrt_put_u32(b, s->seqnum);
        !           393: 
        !           394:   /* Network Prefix */
        !           395:   if (s->ipv4)
        !           396:   {
        !           397:     ASSERT(n->type == NET_IP4);
        !           398:     ip4_addr a = ip4_hton(net4_prefix(n));
        !           399:     uint len = net4_pxlen(n);
        !           400: 
        !           401:     mrt_put_u8(b, len);
        !           402:     mrt_put_data(b, &a, BYTES(len));
        !           403:   }
        !           404:   else
        !           405:   {
        !           406:     ASSERT(n->type == NET_IP6);
        !           407:     ip6_addr a = ip6_hton(net6_prefix(n));
        !           408:     uint len = net6_pxlen(n);
        !           409: 
        !           410:     mrt_put_u8(b, len);
        !           411:     mrt_put_data(b, &a, BYTES(len));
        !           412:   }
        !           413: 
        !           414:   /* Entry Count, will be fixed later */
        !           415:   s->entry_count = 0;
        !           416:   s->entry_count_offset = mrt_buffer_pos(b);
        !           417:   mrt_put_u16(b, 0);
        !           418: }
        !           419: 
        !           420: static void
        !           421: mrt_rib_table_entry(struct mrt_table_dump_state *s, rte *r)
        !           422: {
        !           423:   buffer *b = &s->buf;
        !           424:   uint peer = 0;
        !           425: 
        !           426: #ifdef CONFIG_BGP
        !           427:   /* Find peer index */
        !           428:   if (r->attrs->src->proto->proto == &proto_bgp)
        !           429:   {
        !           430:     struct bgp_proto *p = (void *) r->attrs->src->proto;
        !           431:     struct mrt_peer_entry *n =
        !           432:       HASH_FIND(s->peer_hash, PEER, p->remote_id, p->remote_as, p->remote_ip);
        !           433: 
        !           434:     peer = n ? n->index : 0;
        !           435:   }
        !           436: #endif
        !           437: 
        !           438:   /* Peer Index and Originated Time */
        !           439:   mrt_put_u16(b, peer);
        !           440:   mrt_put_u32(b, (r->lastmod + s->time_offset) TO_S);
        !           441: 
        !           442:   /* Path Identifier */
        !           443:   if (s->add_path)
        !           444:     mrt_put_u32(b, r->attrs->src->private_id);
        !           445: 
        !           446:   /* Route Attributes */
        !           447:   mrt_put_u16(b, 0);
        !           448: 
        !           449: #ifdef CONFIG_BGP
        !           450:   if (r->attrs->eattrs)
        !           451:   {
        !           452:     struct ea_list *eattrs = r->attrs->eattrs;
        !           453: 
        !           454:     if (!rta_is_cached(r->attrs))
        !           455:       ea_normalize(eattrs);
        !           456: 
        !           457:     mrt_buffer_need(b, MRT_ATTR_BUFFER_SIZE);
        !           458:     int alen = bgp_encode_attrs(s->bws, eattrs, b->pos, b->end);
        !           459: 
        !           460:     if (alen < 0)
        !           461:     {
        !           462:       mrt_log(s, "Attribute list too long for %N", r->net->n.addr);
        !           463:       alen = 0;
        !           464:     }
        !           465: 
        !           466:     put_u16(b->pos - 2, alen);
        !           467:     b->pos += alen;
        !           468:   }
        !           469: #endif
        !           470: 
        !           471:   s->entry_count++;
        !           472: }
        !           473: 
        !           474: static void
        !           475: mrt_rib_table_dump(struct mrt_table_dump_state *s, net *n, int add_path)
        !           476: {
        !           477:   s->add_path = s->bws->add_path = add_path;
        !           478: 
        !           479:   int subtype = s->ipv4 ?
        !           480:     (!add_path ? MRT_RIB_IPV4_UNICAST : MRT_RIB_IPV4_UNICAST_ADDPATH) :
        !           481:     (!add_path ? MRT_RIB_IPV6_UNICAST : MRT_RIB_IPV6_UNICAST_ADDPATH);
        !           482: 
        !           483:   mrt_init_message(&s->buf, MRT_TABLE_DUMP_V2, subtype);
        !           484:   mrt_rib_table_header(s, n->n.addr);
        !           485: 
        !           486:   rte *rt, *rt0;
        !           487:   for (rt0 = n->routes; rt = rt0; rt0 = rt0->next)
        !           488:   {
        !           489:     if (rte_is_filtered(rt))
        !           490:       continue;
        !           491: 
        !           492:     /* Skip routes that should be reported in the other phase */
        !           493:     if (!s->always_add_path && (!rt->attrs->src->private_id != !s->add_path))
        !           494:     {
        !           495:       s->want_add_path = 1;
        !           496:       continue;
        !           497:     }
        !           498: 
        !           499:     rte_make_tmp_attrs(&rt, s->linpool, NULL);
        !           500: 
        !           501:     if (f_run(s->filter, &rt, s->linpool, 0) <= F_ACCEPT)
        !           502:       mrt_rib_table_entry(s, rt);
        !           503: 
        !           504:     if (rt != rt0)
        !           505:       rte_free(rt);
        !           506: 
        !           507:     lp_flush(s->linpool);
        !           508:   }
        !           509: 
        !           510:   /* Fix Entry Count */
        !           511:   put_u16(s->buf.start + s->entry_count_offset, s->entry_count);
        !           512: 
        !           513:   /* Update max counter */
        !           514:   s->max -= 1 + s->entry_count;
        !           515: 
        !           516:   /* Skip empty entries */
        !           517:   if (!s->entry_count)
        !           518:     return;
        !           519: 
        !           520:   s->seqnum++;
        !           521:   mrt_dump_message(&s->buf, s->fd);
        !           522: }
        !           523: 
        !           524: 
        !           525: /*
        !           526:  *     MRT Table Dump: main logic
        !           527:  */
        !           528: 
        !           529: static struct mrt_table_dump_state *
        !           530: mrt_table_dump_init(pool *pp)
        !           531: {
        !           532:   pool *pool = rp_new(pp, "MRT Table Dump");
        !           533:   struct mrt_table_dump_state *s = mb_allocz(pool, sizeof(struct mrt_table_dump_state));
        !           534: 
        !           535:   s->pool = pool;
        !           536:   s->linpool = lp_new(pool, 4080);
        !           537:   s->peer_lp = lp_new(pool, 4080);
        !           538:   mrt_buffer_init(&s->buf, pool, 2 * MRT_ATTR_BUFFER_SIZE);
        !           539: 
        !           540:   /* We lock the current config as we may reference it indirectly by filter */
        !           541:   s->config = config;
        !           542:   config_add_obstacle(s->config);
        !           543: 
        !           544:   s->fd = -1;
        !           545: 
        !           546:   return s;
        !           547: }
        !           548: 
        !           549: static void
        !           550: mrt_table_dump_free(struct mrt_table_dump_state *s)
        !           551: {
        !           552:   if (s->table_open)
        !           553:     FIB_ITERATE_UNLINK(&s->fit, &s->table->fib);
        !           554: 
        !           555:   if (s->table)
        !           556:     rt_unlock_table(s->table);
        !           557: 
        !           558:   if (s->table_ptr)
        !           559:     rt_unlock_table(s->table_ptr);
        !           560: 
        !           561:   config_del_obstacle(s->config);
        !           562: 
        !           563:   rfree(s->pool);
        !           564: }
        !           565: 
        !           566: 
        !           567: static int
        !           568: mrt_table_dump_step(struct mrt_table_dump_state *s)
        !           569: {
        !           570:   struct bgp_write_state bws = { .as4_session = 1 };
        !           571: 
        !           572:   s->max = 2048;
        !           573:   s->bws = &bws;
        !           574: 
        !           575:   if (s->table_open)
        !           576:     goto step;
        !           577: 
        !           578:   while (mrt_next_table(s))
        !           579:   {
        !           580:     if (!mrt_open_file(s))
        !           581:       continue;
        !           582: 
        !           583:     mrt_peer_table_dump(s);
        !           584: 
        !           585:     FIB_ITERATE_INIT(&s->fit, &s->table->fib);
        !           586:     s->table_open = 1;
        !           587: 
        !           588:   step:
        !           589:     FIB_ITERATE_START(&s->table->fib, &s->fit, net, n)
        !           590:     {
        !           591:       if (s->max < 0)
        !           592:       {
        !           593:        FIB_ITERATE_PUT(&s->fit);
        !           594:        return 0;
        !           595:       }
        !           596: 
        !           597:       /* With Always ADD_PATH option, we jump directly to second phase */
        !           598:       s->want_add_path = s->always_add_path;
        !           599: 
        !           600:       if (s->want_add_path == 0)
        !           601:        mrt_rib_table_dump(s, n, 0);
        !           602: 
        !           603:       if (s->want_add_path == 1)
        !           604:        mrt_rib_table_dump(s, n, 1);
        !           605:     }
        !           606:     FIB_ITERATE_END;
        !           607:     s->table_open = 0;
        !           608: 
        !           609:     mrt_close_file(s);
        !           610:     mrt_peer_table_flush(s);
        !           611:   }
        !           612: 
        !           613:   return 1;
        !           614: }
        !           615: 
        !           616: static void
        !           617: mrt_timer(timer *t)
        !           618: {
        !           619:   struct mrt_proto *p = t->data;
        !           620:   struct mrt_config *cf = (void *) (p->p.cf);
        !           621: 
        !           622:   if (p->table_dump)
        !           623:   {
        !           624:     log(L_WARN "%s: Earlier RIB table dump still not finished, skipping next one", p->p.name);
        !           625:     return;
        !           626:   }
        !           627: 
        !           628:   TRACE(D_EVENTS, "RIB table dump started");
        !           629: 
        !           630:   struct mrt_table_dump_state *s = mrt_table_dump_init(p->p.pool);
        !           631: 
        !           632:   s->proto = p;
        !           633:   s->table_expr = cf->table_expr;
        !           634:   s->table_ptr = cf->table_cf ? cf->table_cf->table : NULL;
        !           635:   s->filter = cf->filter;
        !           636:   s->filename = cf->filename;
        !           637:   s->always_add_path = cf->always_add_path;
        !           638: 
        !           639:   if (s->table_ptr)
        !           640:     rt_lock_table(s->table_ptr);
        !           641: 
        !           642:   p->table_dump = s;
        !           643:   ev_schedule(p->event);
        !           644: }
        !           645: 
        !           646: static void
        !           647: mrt_event(void *P)
        !           648: {
        !           649:   struct mrt_proto *p = P;
        !           650: 
        !           651:   if (!p->table_dump)
        !           652:     return;
        !           653: 
        !           654:   if (!mrt_table_dump_step(p->table_dump))
        !           655:   {
        !           656:     ev_schedule(p->event);
        !           657:     return;
        !           658:   }
        !           659: 
        !           660:   mrt_table_dump_free(p->table_dump);
        !           661:   p->table_dump = NULL;
        !           662: 
        !           663:   TRACE(D_EVENTS, "RIB table dump done");
        !           664: 
        !           665:   if (p->p.proto_state == PS_STOP)
        !           666:     proto_notify_state(&p->p, PS_DOWN);
        !           667: }
        !           668: 
        !           669: 
        !           670: /*
        !           671:  *     MRT Table Dump: CLI command
        !           672:  */
        !           673: 
        !           674: static void
        !           675: mrt_dump_cont(struct cli *c)
        !           676: {
        !           677:   if (!mrt_table_dump_step(c->rover))
        !           678:     return;
        !           679: 
        !           680:   cli_printf(c, 0, "");
        !           681:   mrt_table_dump_free(c->rover);
        !           682:   c->cont = c->cleanup = c->rover = NULL;
        !           683: }
        !           684: 
        !           685: static void
        !           686: mrt_dump_cleanup(struct cli *c)
        !           687: {
        !           688:   mrt_table_dump_free(c->rover);
        !           689:   c->rover = NULL;
        !           690: }
        !           691: 
        !           692: void
        !           693: mrt_dump_cmd(struct mrt_dump_data *d)
        !           694: {
        !           695:   if (cli_access_restricted())
        !           696:     return;
        !           697: 
        !           698:   if (!d->table_expr && !d->table_ptr)
        !           699:     cf_error("Table not specified");
        !           700: 
        !           701:   if (!d->filename)
        !           702:     cf_error("File not specified");
        !           703: 
        !           704:   struct mrt_table_dump_state *s = mrt_table_dump_init(this_cli->pool);
        !           705: 
        !           706:   s->cli = this_cli;
        !           707:   s->table_expr = d->table_expr;
        !           708:   s->table_ptr = d->table_ptr;
        !           709:   s->filter = d->filter;
        !           710:   s->filename = d->filename;
        !           711: 
        !           712:   if (s->table_ptr)
        !           713:     rt_lock_table(s->table_ptr);
        !           714: 
        !           715:   this_cli->cont = mrt_dump_cont;
        !           716:   this_cli->cleanup = mrt_dump_cleanup;
        !           717:   this_cli->rover = s;
        !           718: }
        !           719: 
        !           720: 
        !           721: /*
        !           722:  *     MRT BGP4MP dump
        !           723:  */
        !           724: 
        !           725: static buffer *
        !           726: mrt_bgp_buffer(void)
        !           727: {
        !           728:   /* Static buffer for BGP4MP dump, TODO: change to use MRT protocol */
        !           729:   static buffer b;
        !           730: 
        !           731:   if (!b.start)
        !           732:     mrt_buffer_init(&b, &root_pool, 1024);
        !           733: 
        !           734:   return &b;
        !           735: }
        !           736: 
        !           737: static void
        !           738: mrt_bgp_header(buffer *b, struct mrt_bgp_data *d)
        !           739: {
        !           740:   if (d->as4)
        !           741:   {
        !           742:     mrt_put_u32(b, d->peer_as);
        !           743:     mrt_put_u32(b, d->local_as);
        !           744:   }
        !           745:   else
        !           746:   {
        !           747:     mrt_put_u16(b, (d->peer_as <= 0xFFFF) ? d->peer_as : AS_TRANS);
        !           748:     mrt_put_u16(b, (d->local_as <= 0xFFFF) ? d->local_as : AS_TRANS);
        !           749:   }
        !           750: 
        !           751:   mrt_put_u16(b, (d->index <= 0xFFFF) ? d->index : 0);
        !           752:   mrt_put_u16(b, d->af);
        !           753: 
        !           754:   if (d->af == BGP_AFI_IPV4)
        !           755:   {
        !           756:     mrt_put_ip4(b, ipa_to_ip4(d->peer_ip));
        !           757:     mrt_put_ip4(b, ipa_to_ip4(d->local_ip));
        !           758:   }
        !           759:   else
        !           760:   {
        !           761:     mrt_put_ip6(b, ipa_to_ip6(d->peer_ip));
        !           762:     mrt_put_ip6(b, ipa_to_ip6(d->local_ip));
        !           763:   }
        !           764: }
        !           765: 
        !           766: void
        !           767: mrt_dump_bgp_message(struct mrt_bgp_data *d)
        !           768: {
        !           769:   const u16 subtypes[] = {
        !           770:     MRT_BGP4MP_MESSAGE,                        MRT_BGP4MP_MESSAGE_AS4,
        !           771:     MRT_BGP4MP_MESSAGE_LOCAL,          MRT_BGP4MP_MESSAGE_AS4_LOCAL,
        !           772:     MRT_BGP4MP_MESSAGE_ADDPATH,                MRT_BGP4MP_MESSAGE_AS4_ADDPATH,
        !           773:     MRT_BGP4MP_MESSAGE_LOCAL_ADDPATH,  MRT_BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH,
        !           774:   };
        !           775: 
        !           776:   buffer *b = mrt_bgp_buffer();
        !           777:   mrt_init_message(b, MRT_BGP4MP, subtypes[d->as4 + 4*d->add_path]);
        !           778:   mrt_bgp_header(b, d);
        !           779:   mrt_put_data(b, d->message, d->msg_len);
        !           780:   mrt_dump_message(b, config->mrtdump_file);
        !           781: }
        !           782: 
        !           783: void
        !           784: mrt_dump_bgp_state_change(struct mrt_bgp_data *d)
        !           785: {
        !           786:   /* Convert state from our BS_* values to values used in MRTDump */
        !           787:   const u16 states[BS_MAX] = {1, 2, 3, 4, 5, 6, 1};
        !           788: 
        !           789:   if (states[d->old_state] == states[d->new_state])
        !           790:     return;
        !           791: 
        !           792:   /* Always use AS4 mode for STATE_CHANGE */
        !           793:   d->as4 = 1;
        !           794: 
        !           795:   buffer *b = mrt_bgp_buffer();
        !           796:   mrt_init_message(b, MRT_BGP4MP, MRT_BGP4MP_STATE_CHANGE_AS4);
        !           797:   mrt_bgp_header(b, d);
        !           798:   mrt_put_u16(b, states[d->old_state]);
        !           799:   mrt_put_u16(b, states[d->new_state]);
        !           800:   mrt_dump_message(b, config->mrtdump_file);
        !           801: }
        !           802: 
        !           803: 
        !           804: /*
        !           805:  *     MRT protocol glue
        !           806:  */
        !           807: 
        !           808: void
        !           809: mrt_check_config(struct proto_config *CF)
        !           810: {
        !           811:   struct mrt_config *cf = (void *) CF;
        !           812: 
        !           813:   if (!cf->table_expr && !cf->table_cf)
        !           814:     cf_error("Table not specified");
        !           815: 
        !           816:   if (!cf->filename)
        !           817:     cf_error("File not specified");
        !           818: 
        !           819:   if (!cf->period)
        !           820:     cf_error("Period not specified");
        !           821: }
        !           822: 
        !           823: static struct proto *
        !           824: mrt_init(struct proto_config *CF)
        !           825: {
        !           826:   struct proto *P = proto_new(CF);
        !           827: 
        !           828:   return P;
        !           829: }
        !           830: 
        !           831: static int
        !           832: mrt_start(struct proto *P)
        !           833: {
        !           834:   struct mrt_proto *p = (void *) P;
        !           835:   struct mrt_config *cf = (void *) (P->cf);
        !           836: 
        !           837:   p->timer = tm_new_init(P->pool, mrt_timer, p, cf->period S, 0);
        !           838:   p->event = ev_new_init(P->pool, mrt_event, p);
        !           839: 
        !           840:   tm_start(p->timer, cf->period S);
        !           841: 
        !           842:   return PS_UP;
        !           843: }
        !           844: 
        !           845: static int
        !           846: mrt_shutdown(struct proto *P)
        !           847: {
        !           848:   struct mrt_proto *p = (void *) P;
        !           849: 
        !           850:   return p->table_dump ? PS_STOP : PS_DOWN;
        !           851: }
        !           852: 
        !           853: static int
        !           854: mrt_reconfigure(struct proto *P, struct proto_config *CF)
        !           855: {
        !           856:   struct mrt_proto *p = (void *) P;
        !           857:   struct mrt_config *old = (void *) (P->cf);
        !           858:   struct mrt_config *new = (void *) CF;
        !           859: 
        !           860:   if (new->period != old->period)
        !           861:   {
        !           862:     TRACE(D_EVENTS, "Changing period from %u to %u s", old->period, new->period);
        !           863: 
        !           864:     btime now = current_time();
        !           865:     btime new_time = p->timer->expires - (old->period S) + (new->period S);
        !           866:     p->timer->recurrent = new->period S;
        !           867:     tm_set(p->timer, MAX(now, new_time));
        !           868:   }
        !           869: 
        !           870:   return 1;
        !           871: }
        !           872: 
        !           873: static void
        !           874: mrt_copy_config(struct proto_config *dest UNUSED, struct proto_config *src UNUSED)
        !           875: {
        !           876:   /* Do nothing */
        !           877: }
        !           878: 
        !           879: 
        !           880: struct protocol proto_mrt = {
        !           881:   .name =              "MRT",
        !           882:   .template =          "mrt%d",
        !           883:   .class =             PROTOCOL_MRT,
        !           884:   .proto_size =                sizeof(struct mrt_proto),
        !           885:   .config_size =       sizeof(struct mrt_config),
        !           886:   .init =              mrt_init,
        !           887:   .start =             mrt_start,
        !           888:   .shutdown =          mrt_shutdown,
        !           889:   .reconfigure =       mrt_reconfigure,
        !           890:   .copy_config =       mrt_copy_config,
        !           891: };

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