Return to mrt.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / bird / proto / mrt |
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: };