Annotation of embedaddon/bird/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, 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: return tab;
! 232:
! 233: return NULL;
! 234: }
! 235:
! 236: static rtable *
! 237: mrt_next_table(struct mrt_table_dump_state *s)
! 238: {
! 239: rtable *tab = mrt_next_table_(s->table, s->table_ptr, s->table_expr);
! 240:
! 241: if (s->table)
! 242: rt_unlock_table(s->table);
! 243:
! 244: s->table = tab;
! 245:
! 246: if (s->table)
! 247: rt_lock_table(s->table);
! 248:
! 249: return s->table;
! 250: }
! 251:
! 252: static int
! 253: mrt_open_file(struct mrt_table_dump_state *s)
! 254: {
! 255: char fmt1[BIRD_PATH_MAX];
! 256: char name[BIRD_PATH_MAX];
! 257:
! 258: if (!bstrsub(fmt1, sizeof(fmt1), s->filename, "%N", s->table->name) ||
! 259: !tm_format_real_time(name, sizeof(name), fmt1, now_real))
! 260: {
! 261: mrt_log(s, "Invalid filename '%s'", s->filename);
! 262: return 0;
! 263: }
! 264:
! 265: s->file = rf_open(s->pool, name, "a");
! 266: if (!s->file)
! 267: {
! 268: mrt_log(s, "Unable to open MRT file '%s': %m", name);
! 269: return 0;
! 270: }
! 271:
! 272: s->fd = rf_fileno(s->file);
! 273: s->time_offset = now_real - now;
! 274:
! 275: return 1;
! 276: }
! 277:
! 278: static void
! 279: mrt_close_file(struct mrt_table_dump_state *s)
! 280: {
! 281: rfree(s->file);
! 282: s->file = NULL;
! 283: s->fd = -1;
! 284: }
! 285:
! 286:
! 287: /*
! 288: * MRT Table Dump: Peer Index Table
! 289: */
! 290:
! 291: #define PEER_KEY(n) n->peer_id, n->peer_as, n->peer_ip
! 292: #define PEER_NEXT(n) n->next
! 293: #define PEER_EQ(id1,as1,ip1,id2,as2,ip2) \
! 294: id1 == id2 && as1 == as2 && ipa_equal(ip1, ip2)
! 295: #define PEER_FN(id,as,ip) ipa_hash(ip)
! 296:
! 297: static void
! 298: mrt_peer_table_header(struct mrt_table_dump_state *s, u32 router_id, const char *name)
! 299: {
! 300: buffer *b = &s->buf;
! 301:
! 302: /* Collector BGP ID */
! 303: mrt_put_u32(b, router_id);
! 304:
! 305: /* View Name */
! 306: uint name_length = name ? strlen(name) : 0;
! 307: name_length = MIN(name_length, 65535);
! 308: mrt_put_u16(b, name_length);
! 309: mrt_put_data(b, name, name_length);
! 310:
! 311: /* Peer Count, will be fixed later */
! 312: s->peer_count = 0;
! 313: s->peer_count_offset = mrt_buffer_pos(b);
! 314: mrt_put_u16(b, 0);
! 315:
! 316: HASH_INIT(s->peer_hash, s->pool, 10);
! 317: }
! 318:
! 319: static void
! 320: mrt_peer_table_entry(struct mrt_table_dump_state *s, u32 peer_id, u32 peer_as, ip_addr peer_ip)
! 321: {
! 322: buffer *b = &s->buf;
! 323:
! 324: uint type = MRT_PEER_TYPE_32BIT_ASN;
! 325: if (ipa_is_ip6(peer_ip))
! 326: type |= MRT_PEER_TYPE_IPV6;
! 327:
! 328: /* Dump peer to buffer */
! 329: mrt_put_u8(b, type);
! 330: mrt_put_u32(b, peer_id);
! 331: mrt_put_ipa(b, peer_ip);
! 332: mrt_put_u32(b, peer_as);
! 333:
! 334: /* Add peer to hash table */
! 335: struct mrt_peer_entry *n = lp_allocz(s->peer_lp, sizeof(struct mrt_peer_entry));
! 336: n->peer_id = peer_id;
! 337: n->peer_as = peer_as;
! 338: n->peer_ip = peer_ip;
! 339: n->index = s->peer_count++;
! 340:
! 341: HASH_INSERT(s->peer_hash, PEER, n);
! 342: }
! 343:
! 344: static void
! 345: mrt_peer_table_dump(struct mrt_table_dump_state *s)
! 346: {
! 347: mrt_init_message(&s->buf, MRT_TABLE_DUMP_V2, MRT_PEER_INDEX_TABLE);
! 348: mrt_peer_table_header(s, config->router_id, s->table->name);
! 349:
! 350: /* 0 is fake peer for non-BGP routes */
! 351: mrt_peer_table_entry(s, 0, 0, IPA_NONE);
! 352:
! 353: #ifdef CONFIG_BGP
! 354: struct proto *P;
! 355: WALK_LIST(P, active_proto_list)
! 356: if (P->proto == &proto_bgp)
! 357: {
! 358: struct bgp_proto *p = (void *) P;
! 359: mrt_peer_table_entry(s, p->remote_id, p->remote_as, p->cf->remote_ip);
! 360: }
! 361: #endif
! 362:
! 363: /* Fix Peer Count */
! 364: put_u16(s->buf.start + s->peer_count_offset, s->peer_count);
! 365:
! 366: mrt_dump_message(&s->buf, s->fd);
! 367: }
! 368:
! 369: static void
! 370: mrt_peer_table_flush(struct mrt_table_dump_state *s)
! 371: {
! 372: lp_flush(s->peer_lp);
! 373: HASH_FREE(s->peer_hash);
! 374: }
! 375:
! 376:
! 377: /*
! 378: * MRT Table Dump: RIB Table
! 379: */
! 380:
! 381: static void
! 382: mrt_rib_table_header(struct mrt_table_dump_state *s, net *n)
! 383: {
! 384: buffer *b = &s->buf;
! 385:
! 386: /* Sequence Number */
! 387: mrt_put_u32(b, s->seqnum);
! 388:
! 389: /* Network Prefix */
! 390: ip_addr a = n->n.prefix;
! 391: ipa_hton(a);
! 392:
! 393: mrt_put_u8(b, n->n.pxlen);
! 394: mrt_put_data(b, &a, BYTES(n->n.pxlen));
! 395:
! 396: /* Entry Count, will be fixed later */
! 397: s->entry_count = 0;
! 398: s->entry_count_offset = mrt_buffer_pos(b);
! 399: mrt_put_u16(b, 0);
! 400: }
! 401:
! 402: static void
! 403: mrt_rib_table_entry(struct mrt_table_dump_state *s, rte *r, struct ea_list *tmpa)
! 404: {
! 405: buffer *b = &s->buf;
! 406: uint peer = 0;
! 407:
! 408: #ifdef CONFIG_BGP
! 409: /* Find peer index */
! 410: if (r->attrs->src->proto->proto == &proto_bgp)
! 411: {
! 412: struct bgp_proto *p = (void *) r->attrs->src->proto;
! 413: struct mrt_peer_entry *n =
! 414: HASH_FIND(s->peer_hash, PEER, p->remote_id, p->remote_as, p->cf->remote_ip);
! 415:
! 416: peer = n ? n->index : 0;
! 417: }
! 418: #endif
! 419:
! 420: /* Peer Index and Originated Time */
! 421: mrt_put_u16(b, peer);
! 422: mrt_put_u32(b, r->lastmod + s->time_offset);
! 423:
! 424: /* Path Identifier */
! 425: if (s->add_path)
! 426: mrt_put_u32(b, r->attrs->src->private_id);
! 427:
! 428: /* Route Attributes */
! 429: mrt_put_u16(b, 0);
! 430:
! 431: #ifdef CONFIG_BGP
! 432: if (r->attrs->eattrs || tmpa)
! 433: {
! 434: struct ea_list *eattrs = r->attrs->eattrs;
! 435:
! 436: if (!rta_is_cached(r->attrs) || tmpa)
! 437: {
! 438: /* Attributes must be merged and sorted for bgp_encode_attrs() */
! 439: tmpa = ea_append(tmpa, eattrs);
! 440: eattrs = alloca(ea_scan(tmpa));
! 441: ea_merge(tmpa, eattrs);
! 442: ea_sort(eattrs);
! 443: }
! 444:
! 445: mrt_buffer_need(b, MRT_ATTR_BUFFER_SIZE);
! 446: int alen = bgp_encode_attrs(NULL, b->pos, eattrs, MRT_ATTR_BUFFER_SIZE);
! 447:
! 448: if (alen < 0)
! 449: {
! 450: mrt_log(s, "Attribute list too long for %I/%d",
! 451: r->net->n.prefix, r->net->n.pxlen);
! 452: alen = 0;
! 453: }
! 454:
! 455: put_u16(b->pos - 2, alen);
! 456: b->pos += alen;
! 457: }
! 458: #endif
! 459:
! 460: s->entry_count++;
! 461: }
! 462:
! 463: static void
! 464: mrt_rib_table_dump(struct mrt_table_dump_state *s, net *n, int add_path)
! 465: {
! 466: rte *rt, *rt0;
! 467: int subtype;
! 468:
! 469: s->add_path = add_path;
! 470:
! 471: #ifndef IPV6
! 472: subtype = !add_path ? MRT_RIB_IPV4_UNICAST : MRT_RIB_IPV4_UNICAST_ADDPATH;
! 473: #else
! 474: subtype = !add_path ? MRT_RIB_IPV6_UNICAST : MRT_RIB_IPV6_UNICAST_ADDPATH;
! 475: #endif
! 476:
! 477: mrt_init_message(&s->buf, MRT_TABLE_DUMP_V2, subtype);
! 478: mrt_rib_table_header(s, n);
! 479:
! 480: for (rt0 = n->routes; rt = rt0; rt0 = rt0->next)
! 481: {
! 482: if (rte_is_filtered(rt))
! 483: continue;
! 484:
! 485: /* Skip routes that should be reported in the other phase */
! 486: if (!s->always_add_path && (!rt->attrs->src->private_id != !s->add_path))
! 487: {
! 488: s->want_add_path = 1;
! 489: continue;
! 490: }
! 491:
! 492: struct ea_list *tmp_attrs = rte_make_tmp_attrs(rt, s->linpool);
! 493:
! 494: if (f_run(s->filter, &rt, &tmp_attrs, s->linpool, 0) <= F_ACCEPT)
! 495: mrt_rib_table_entry(s, rt, tmp_attrs);
! 496:
! 497: if (rt != rt0)
! 498: rte_free(rt);
! 499:
! 500: lp_flush(s->linpool);
! 501: }
! 502:
! 503: /* Fix Entry Count */
! 504: put_u16(s->buf.start + s->entry_count_offset, s->entry_count);
! 505:
! 506: /* Update max counter */
! 507: s->max -= 1 + s->entry_count;
! 508:
! 509: /* Skip empty entries */
! 510: if (!s->entry_count)
! 511: return;
! 512:
! 513: s->seqnum++;
! 514: mrt_dump_message(&s->buf, s->fd);
! 515: }
! 516:
! 517:
! 518: /*
! 519: * MRT Table Dump: main logic
! 520: */
! 521:
! 522: static struct mrt_table_dump_state *
! 523: mrt_table_dump_init(pool *pp)
! 524: {
! 525: pool *pool = rp_new(pp, "MRT Table Dump");
! 526: struct mrt_table_dump_state *s = mb_allocz(pool, sizeof(struct mrt_table_dump_state));
! 527:
! 528: s->pool = pool;
! 529: s->linpool = lp_new(pool, 4080);
! 530: s->peer_lp = lp_new(pool, 4080);
! 531: mrt_buffer_init(&s->buf, pool, 2 * MRT_ATTR_BUFFER_SIZE);
! 532:
! 533: /* We lock the current config as we may reference it indirectly by filter */
! 534: s->config = config;
! 535: config_add_obstacle(s->config);
! 536:
! 537: s->fd = -1;
! 538:
! 539: return s;
! 540: }
! 541:
! 542: static void
! 543: mrt_table_dump_free(struct mrt_table_dump_state *s)
! 544: {
! 545: if (s->table_open)
! 546: FIB_ITERATE_UNLINK(&s->fit, &s->table->fib);
! 547:
! 548: if (s->table)
! 549: rt_unlock_table(s->table);
! 550:
! 551: if (s->table_ptr)
! 552: rt_unlock_table(s->table_ptr);
! 553:
! 554: config_del_obstacle(s->config);
! 555:
! 556: rfree(s->pool);
! 557: }
! 558:
! 559:
! 560: static int
! 561: mrt_table_dump_step(struct mrt_table_dump_state *s)
! 562: {
! 563: s->max = 2048;
! 564:
! 565: if (s->table_open)
! 566: goto step;
! 567:
! 568: while (mrt_next_table(s))
! 569: {
! 570: if (!mrt_open_file(s))
! 571: continue;
! 572:
! 573: mrt_peer_table_dump(s);
! 574:
! 575: FIB_ITERATE_INIT(&s->fit, &s->table->fib);
! 576: s->table_open = 1;
! 577:
! 578: step:
! 579: FIB_ITERATE_START(&s->table->fib, &s->fit, fn)
! 580: {
! 581: if (s->max < 0)
! 582: {
! 583: FIB_ITERATE_PUT(&s->fit, fn);
! 584: return 0;
! 585: }
! 586:
! 587: /* With Always ADD_PATH option, we jump directly to second phase */
! 588: s->want_add_path = s->always_add_path;
! 589:
! 590: if (s->want_add_path == 0)
! 591: mrt_rib_table_dump(s, (net *) fn, 0);
! 592:
! 593: if (s->want_add_path == 1)
! 594: mrt_rib_table_dump(s, (net *) fn, 1);
! 595: }
! 596: FIB_ITERATE_END(fn);
! 597: s->table_open = 0;
! 598:
! 599: mrt_close_file(s);
! 600: mrt_peer_table_flush(s);
! 601: }
! 602:
! 603: return 1;
! 604: }
! 605:
! 606: static void
! 607: mrt_timer(timer *t)
! 608: {
! 609: struct mrt_proto *p = t->data;
! 610: struct mrt_config *cf = (void *) (p->p.cf);
! 611:
! 612: if (p->table_dump)
! 613: {
! 614: log(L_WARN "%s: Earlier RIB table dump still not finished, skipping next one", p->p.name);
! 615: return;
! 616: }
! 617:
! 618: TRACE(D_EVENTS, "RIB table dump started");
! 619:
! 620: struct mrt_table_dump_state *s = mrt_table_dump_init(p->p.pool);
! 621:
! 622: s->proto = p;
! 623: s->table_expr = cf->table_expr;
! 624: s->table_ptr = cf->table_cf ? cf->table_cf->table : NULL;
! 625: s->filter = cf->filter;
! 626: s->filename = cf->filename;
! 627: s->always_add_path = cf->always_add_path;
! 628:
! 629: if (s->table_ptr)
! 630: rt_lock_table(s->table_ptr);
! 631:
! 632: p->table_dump = s;
! 633: ev_schedule(p->event);
! 634: }
! 635:
! 636: static void
! 637: mrt_event(void *P)
! 638: {
! 639: struct mrt_proto *p = P;
! 640:
! 641: if (!p->table_dump)
! 642: return;
! 643:
! 644: if (!mrt_table_dump_step(p->table_dump))
! 645: {
! 646: ev_schedule(p->event);
! 647: return;
! 648: }
! 649:
! 650: mrt_table_dump_free(p->table_dump);
! 651: p->table_dump = NULL;
! 652:
! 653: TRACE(D_EVENTS, "RIB table dump done");
! 654:
! 655: if (p->p.proto_state == PS_STOP)
! 656: proto_notify_state(&p->p, PS_DOWN);
! 657: }
! 658:
! 659:
! 660: /*
! 661: * MRT Table Dump: CLI command
! 662: */
! 663:
! 664: static void
! 665: mrt_dump_cont(struct cli *c)
! 666: {
! 667: if (!mrt_table_dump_step(c->rover))
! 668: return;
! 669:
! 670: cli_printf(c, 0, "");
! 671: mrt_table_dump_free(c->rover);
! 672: c->cont = c->cleanup = c->rover = NULL;
! 673: }
! 674:
! 675: static void
! 676: mrt_dump_cleanup(struct cli *c)
! 677: {
! 678: mrt_table_dump_free(c->rover);
! 679: c->rover = NULL;
! 680: }
! 681:
! 682: void
! 683: mrt_dump_cmd(struct mrt_dump_data *d)
! 684: {
! 685: if (cli_access_restricted())
! 686: return;
! 687:
! 688: if (!d->table_expr && !d->table_ptr)
! 689: cf_error("Table not specified");
! 690:
! 691: if (!d->filename)
! 692: cf_error("File not specified");
! 693:
! 694: struct mrt_table_dump_state *s = mrt_table_dump_init(this_cli->pool);
! 695:
! 696: s->cli = this_cli;
! 697: s->table_expr = d->table_expr;
! 698: s->table_ptr = d->table_ptr;
! 699: s->filter = d->filter;
! 700: s->filename = d->filename;
! 701:
! 702: if (s->table_ptr)
! 703: rt_lock_table(s->table_ptr);
! 704:
! 705: this_cli->cont = mrt_dump_cont;
! 706: this_cli->cleanup = mrt_dump_cleanup;
! 707: this_cli->rover = s;
! 708: }
! 709:
! 710:
! 711: /*
! 712: * MRT BGP4MP dump
! 713: */
! 714:
! 715: static buffer *
! 716: mrt_bgp_buffer(void)
! 717: {
! 718: /* Static buffer for BGP4MP dump, TODO: change to use MRT protocol */
! 719: static buffer b;
! 720:
! 721: if (!b.start)
! 722: mrt_buffer_init(&b, &root_pool, 1024);
! 723:
! 724: return &b;
! 725: }
! 726:
! 727: static void
! 728: mrt_bgp_header(buffer *b, struct mrt_bgp_data *d)
! 729: {
! 730: if (d->as4)
! 731: {
! 732: mrt_put_u32(b, d->peer_as);
! 733: mrt_put_u32(b, d->local_as);
! 734: }
! 735: else
! 736: {
! 737: mrt_put_u16(b, (d->peer_as <= 0xFFFF) ? d->peer_as : AS_TRANS);
! 738: mrt_put_u16(b, (d->local_as <= 0xFFFF) ? d->local_as : AS_TRANS);
! 739: }
! 740:
! 741: mrt_put_u16(b, (d->index <= 0xFFFF) ? d->index : 0);
! 742: mrt_put_u16(b, d->af);
! 743:
! 744: if (d->af == BGP_AF_IPV4)
! 745: {
! 746: mrt_put_ip4(b, ipa_to_ip4(d->peer_ip));
! 747: mrt_put_ip4(b, ipa_to_ip4(d->local_ip));
! 748: }
! 749: else
! 750: {
! 751: mrt_put_ip6(b, ipa_to_ip6(d->peer_ip));
! 752: mrt_put_ip6(b, ipa_to_ip6(d->local_ip));
! 753: }
! 754: }
! 755:
! 756: void
! 757: mrt_dump_bgp_message(struct mrt_bgp_data *d)
! 758: {
! 759: const u16 subtypes[] = {
! 760: MRT_BGP4MP_MESSAGE, MRT_BGP4MP_MESSAGE_AS4,
! 761: MRT_BGP4MP_MESSAGE_LOCAL, MRT_BGP4MP_MESSAGE_AS4_LOCAL,
! 762: MRT_BGP4MP_MESSAGE_ADDPATH, MRT_BGP4MP_MESSAGE_AS4_ADDPATH,
! 763: MRT_BGP4MP_MESSAGE_LOCAL_ADDPATH, MRT_BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH,
! 764: };
! 765:
! 766: buffer *b = mrt_bgp_buffer();
! 767: mrt_init_message(b, MRT_BGP4MP, subtypes[d->as4 + 4*d->add_path]);
! 768: mrt_bgp_header(b, d);
! 769: mrt_put_data(b, d->message, d->msg_len);
! 770: mrt_dump_message(b, config->mrtdump_file);
! 771: }
! 772:
! 773: void
! 774: mrt_dump_bgp_state_change(struct mrt_bgp_data *d)
! 775: {
! 776: /* Convert state from our BS_* values to values used in MRTDump */
! 777: const u16 states[BS_MAX] = {1, 2, 3, 4, 5, 6, 1};
! 778:
! 779: if (states[d->old_state] == states[d->new_state])
! 780: return;
! 781:
! 782: /* Always use AS4 mode for STATE_CHANGE */
! 783: d->as4 = 1;
! 784:
! 785: buffer *b = mrt_bgp_buffer();
! 786: mrt_init_message(b, MRT_BGP4MP, MRT_BGP4MP_STATE_CHANGE_AS4);
! 787: mrt_bgp_header(b, d);
! 788: mrt_put_u16(b, states[d->old_state]);
! 789: mrt_put_u16(b, states[d->new_state]);
! 790: mrt_dump_message(b, config->mrtdump_file);
! 791: }
! 792:
! 793:
! 794: /*
! 795: * MRT protocol glue
! 796: */
! 797:
! 798: void
! 799: mrt_check_config(struct proto_config *C)
! 800: {
! 801: struct mrt_config *cf = (void *) C;
! 802:
! 803: /* c.table must be always defined, but it is relevant only if table_expr is not set */
! 804: if (!cf->table_expr)
! 805: cf->table_cf = cf->c.table;
! 806:
! 807: if (!cf->table_expr && !cf->table_cf)
! 808: cf_error("Table not specified");
! 809:
! 810: if (!cf->filename)
! 811: cf_error("File not specified");
! 812:
! 813: if (!cf->period)
! 814: cf_error("Period not specified");
! 815: }
! 816:
! 817: static struct proto *
! 818: mrt_init(struct proto_config *C)
! 819: {
! 820: struct proto *P = proto_new(C, sizeof(struct mrt_proto));
! 821:
! 822: return P;
! 823: }
! 824:
! 825: static int
! 826: mrt_start(struct proto *P)
! 827: {
! 828: struct mrt_proto *p = (void *) P;
! 829: struct mrt_config *cf = (void *) (P->cf);
! 830:
! 831: p->timer = tm_new_set(P->pool, mrt_timer, p, 0, cf->period);
! 832: p->event = ev_new_set(P->pool, mrt_event, p);
! 833:
! 834: tm_start(p->timer, cf->period);
! 835:
! 836: return PS_UP;
! 837: }
! 838:
! 839: static int
! 840: mrt_shutdown(struct proto *P)
! 841: {
! 842: struct mrt_proto *p = (void *) P;
! 843:
! 844: return p->table_dump ? PS_STOP : PS_DOWN;
! 845: }
! 846:
! 847: static int
! 848: mrt_reconfigure(struct proto *P, struct proto_config *CF)
! 849: {
! 850: struct mrt_proto *p = (void *) P;
! 851: struct mrt_config *old = (void *) (P->cf);
! 852: struct mrt_config *new = (void *) CF;
! 853:
! 854: if (new->period != old->period)
! 855: {
! 856: TRACE(D_EVENTS, "Changing period from %d to %d s", old->period, new->period);
! 857:
! 858: bird_clock_t new_time = p->timer->expires - old->period + new->period;
! 859: tm_start(p->timer, (new_time > now) ? (new_time - now) : 0);
! 860: p->timer->recurrent = new->period;
! 861: }
! 862:
! 863: return 1;
! 864: }
! 865:
! 866: static void
! 867: mrt_copy_config(struct proto_config *dest, struct proto_config *src)
! 868: {
! 869: /* Just a shallow copy, not many items here */
! 870: proto_copy_rest(dest, src, sizeof(struct mrt_config));
! 871: }
! 872:
! 873:
! 874: struct protocol proto_mrt = {
! 875: .name = "MRT",
! 876: .template = "mrt%d",
! 877: .config_size = sizeof(struct mrt_config),
! 878: .init = mrt_init,
! 879: .start = mrt_start,
! 880: .shutdown = mrt_shutdown,
! 881: .reconfigure = mrt_reconfigure,
! 882: .copy_config = mrt_copy_config,
! 883: };
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>