Annotation of embedaddon/bird2/proto/mrt/mrt.c, revision 1.1.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>