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