Annotation of embedaddon/bird/proto/mrt/mrt.c, revision 1.1.1.1
1.1 misho 1: /*
2: * BIRD -- Multi-Threaded Routing Toolkit (MRT) Protocol
3: *
4: * (c) 2017--2018 Ondrej Zajicek <santiago@crfreenet.org>
5: * (c) 2017--2018 CZ.NIC z.s.p.o.
6: *
7: * Can be freely distributed and used under the terms of the GNU GPL.
8: */
9:
10: /**
11: * DOC: Multi-Threaded Routing Toolkit (MRT) protocol
12: *
13: * The MRT protocol is implemented in just one file: |mrt.c|. It contains of
14: * several parts: Generic functions for preparing MRT messages in a buffer,
15: * functions for MRT table dump (called from timer or CLI), functions for MRT
16: * BGP4MP dump (called from BGP), and the usual protocol glue. For the MRT table
17: * dump, the key structure is struct mrt_table_dump_state, which contains all
18: * necessary data and created when the MRT dump cycle is started for the
19: * duration of the MRT dump. The MBGP4MP dump is currently not bound to MRT
20: * protocol instance and uses the config->mrtdump_file fd.
21: *
22: * The protocol is simple, just periodically scans routing table and export it
23: * to a file. It does not use the regular update mechanism, but a direct access
24: * in order to handle iteration through multiple routing tables. The table dump
25: * needs to dump all peers first and then use indexes to address the peers, we
26: * use a hash table (@peer_hash) to find peer index based on BGP protocol key
27: * attributes.
28: *
29: * One thing worth documenting is the locking. During processing, the currently
30: * processed table (@table field in the state structure) is locked and also the
31: * explicitly named table is locked (@table_ptr field in the state structure) if
32: * specified. Between dumps no table is locked. Also the current config is
33: * locked (by config_add_obstacle()) during table dumps as some data (strings,
34: * filters) are shared from the config and the running table dump may be
35: * interrupted by reconfiguration.
36: *
37: * Supported standards:
38: * - RFC 6396 - MRT format standard
39: * - RFC 8050 - ADD_PATH extension
40: */
41:
42: #include <unistd.h>
43: #include <limits.h>
44: #include <errno.h>
45:
46: #include "mrt.h"
47:
48: #include "nest/cli.h"
49: #include "filter/filter.h"
50: #include "proto/bgp/bgp.h"
51: #include "sysdep/unix/unix.h"
52:
53:
54: #ifdef PATH_MAX
55: #define BIRD_PATH_MAX PATH_MAX
56: #else
57: #define BIRD_PATH_MAX 4096
58: #endif
59:
60: #define mrt_log(s, msg, args...) \
61: ({ \
62: if (s->cli) \
63: cli_printf(s->cli, -8009, msg, ## args); \
64: if (s->proto) \
65: log(L_ERR "%s: " msg, s->proto->p.name, ## args); \
66: })
67:
68:
69: /*
70: * MRT buffer code
71: */
72:
73: static void
74: mrt_buffer_init(buffer *b, pool *pool, size_t n)
75: {
76: b->start = mb_alloc(pool, n);
77: b->pos = b->start;
78: b->end = b->start + n;
79: }
80:
81: static void
82: mrt_buffer_grow(buffer *b, size_t n)
83: {
84: size_t used = b->pos - b->start;
85: size_t size = b->end - b->start;
86: size_t req = used + n;
87:
88: while (size < req)
89: size = size * 3 / 2;
90:
91: b->start = mb_realloc(b->start, size);
92: b->pos = b->start + used;
93: b->end = b->start + size;
94: }
95:
96: static inline void
97: mrt_buffer_need(buffer *b, size_t n)
98: {
99: if (b->pos + n > b->end)
100: mrt_buffer_grow(b, n);
101: }
102:
103: static inline uint
104: mrt_buffer_pos(buffer *b)
105: {
106: return b->pos - b->start;
107: }
108:
109: static inline void
110: mrt_buffer_flush(buffer *b)
111: {
112: b->pos = b->start;
113: }
114:
115: #define MRT_DEFINE_TYPE(S, T) \
116: static inline void mrt_put_##S##_(buffer *b, T x) \
117: { \
118: put_##S(b->pos, x); \
119: b->pos += sizeof(T); \
120: } \
121: \
122: static inline void mrt_put_##S(buffer *b, T x) \
123: { \
124: mrt_buffer_need(b, sizeof(T)); \
125: put_##S(b->pos, x); \
126: b->pos += sizeof(T); \
127: }
128:
129: MRT_DEFINE_TYPE(u8, u8)
130: MRT_DEFINE_TYPE(u16, u16)
131: MRT_DEFINE_TYPE(u32, u32)
132: MRT_DEFINE_TYPE(u64, u64)
133: MRT_DEFINE_TYPE(ip4, ip4_addr)
134: MRT_DEFINE_TYPE(ip6, ip6_addr)
135:
136: static inline void
137: mrt_put_ipa(buffer *b, ip_addr x)
138: {
139: if (ipa_is_ip4(x))
140: mrt_put_ip4(b, ipa_to_ip4(x));
141: else
142: mrt_put_ip6(b, ipa_to_ip6(x));
143: }
144:
145: static inline void
146: mrt_put_data(buffer *b, const void *src, size_t n)
147: {
148: if (!n)
149: return;
150:
151: mrt_buffer_need(b, n);
152: memcpy(b->pos, src, n);
153: b->pos += n;
154: }
155:
156: static void
157: mrt_init_message(buffer *b, u16 type, u16 subtype)
158: {
159: /* Reset buffer */
160: mrt_buffer_flush(b);
161: mrt_buffer_need(b, MRT_HDR_LENGTH);
162:
163: /* Prepare header */
164: mrt_put_u32_(b, 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>