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