1 /* $OpenBSD: mrt.c,v 1.123 2024/12/16 16:10:10 claudio Exp $ */
2
3 /*
4 * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <sys/types.h>
20 #include <sys/queue.h>
21
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <limits.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <time.h>
28 #include <unistd.h>
29
30 #include "bgpd.h"
31 #include "rde.h"
32 #include "session.h"
33
34 #include "mrt.h"
35 #include "log.h"
36
37 static int mrt_attr_dump(struct ibuf *, struct rde_aspath *,
38 struct rde_community *, struct bgpd_addr *, int);
39 static int mrt_dump_entry_mp(struct mrt *, struct prefix *, uint16_t,
40 struct rde_peer*);
41 static int mrt_dump_entry(struct mrt *, struct prefix *, uint16_t,
42 struct rde_peer*);
43 static int mrt_dump_entry_v2(struct mrt *, struct rib_entry *, uint32_t);
44 static int mrt_dump_peer(struct ibuf *, struct rde_peer *);
45 static int mrt_dump_hdr_se(struct ibuf **, struct peer *, uint16_t,
46 uint16_t, uint32_t, int);
47 static int mrt_dump_hdr_rde(struct ibuf **, uint16_t type, uint16_t,
48 uint32_t);
49 static int mrt_open(struct mrt *, time_t);
50
51 #define RDEIDX 0
52 #define SEIDX 1
53 #define TYPE2IDX(x) ((x == MRT_TABLE_DUMP || \
54 x == MRT_TABLE_DUMP_MP || \
55 x == MRT_TABLE_DUMP_V2) ? RDEIDX : SEIDX \
56 )
57
58 static uint8_t
mrt_update_msg_guess_aid(struct ibuf * pkg)59 mrt_update_msg_guess_aid(struct ibuf *pkg)
60 {
61 struct ibuf buf;
62 uint16_t wlen, alen, len, afi;
63 uint8_t type, flags, aid, safi;
64
65 ibuf_from_ibuf(&buf, pkg);
66
67 if (ibuf_skip(&buf, MSGSIZE_HEADER) == -1 ||
68 ibuf_get_n16(&buf, &wlen) == -1)
69 goto bad;
70
71 if (wlen > 0) {
72 /* UPDATE has withdraw routes, therefore IPv4 */
73 return AID_INET;
74 }
75
76 if (ibuf_get_n16(&buf, &alen) == -1)
77 goto bad;
78
79 if (alen < ibuf_size(&buf)) {
80 /* UPDATE has NLRI prefixes, therefore IPv4 */
81 return AID_INET;
82 }
83
84 if (wlen == 0 && alen == 0) {
85 /* UPDATE is an IPv4 EoR marker */
86 return AID_INET;
87 }
88
89 /* bad attribute length */
90 if (alen > ibuf_size(&buf))
91 goto bad;
92
93 /* try to extract AFI/SAFI from the MP attributes */
94 while (ibuf_size(&buf) > 0) {
95 if (ibuf_get_n8(&buf, &flags) == -1 ||
96 ibuf_get_n8(&buf, &type) == -1)
97 goto bad;
98 if (flags & ATTR_EXTLEN) {
99 if (ibuf_get_n16(&buf, &len) == -1)
100 goto bad;
101 } else {
102 uint8_t tmp;
103 if (ibuf_get_n8(&buf, &tmp) == -1)
104 goto bad;
105 len = tmp;
106 }
107 if (len > ibuf_size(&buf))
108 goto bad;
109
110 if (type == ATTR_MP_REACH_NLRI ||
111 type == ATTR_MP_UNREACH_NLRI) {
112 if (ibuf_get_n16(&buf, &afi) == -1 ||
113 ibuf_get_n8(&buf, &safi) == -1)
114 goto bad;
115 if (afi2aid(afi, safi, &aid) == -1)
116 goto bad;
117 return aid;
118 }
119 if (ibuf_skip(&buf, len) == -1)
120 goto bad;
121 }
122
123 bad:
124 return AID_UNSPEC;
125 }
126
127 static uint16_t
mrt_bgp_msg_subtype(struct mrt * mrt,struct ibuf * pkg,struct peer * peer,enum msg_type msgtype,int in)128 mrt_bgp_msg_subtype(struct mrt *mrt, struct ibuf *pkg, struct peer *peer,
129 enum msg_type msgtype, int in)
130 {
131 uint16_t subtype = BGP4MP_MESSAGE;
132 uint8_t aid, mask;
133
134 if (peer->capa.neg.as4byte)
135 subtype = BGP4MP_MESSAGE_AS4;
136
137 if (msgtype != MSG_UPDATE)
138 return subtype;
139
140 /*
141 * RFC8050 adjust types for add-path enabled sessions.
142 * It is necessary to extract the AID from UPDATES to decide
143 * if the add-path types are needed or not. The ADDPATH
144 * subtypes only matter for BGP UPDATES.
145 */
146
147 mask = in ? CAPA_AP_RECV : CAPA_AP_SEND;
148 /* only guess if add-path could be active */
149 if (peer->capa.neg.add_path[0] & mask) {
150 aid = mrt_update_msg_guess_aid(pkg);
151 if (aid != AID_UNSPEC &&
152 (peer->capa.neg.add_path[aid] & mask)) {
153 if (peer->capa.neg.as4byte)
154 subtype = BGP4MP_MESSAGE_AS4_ADDPATH;
155 else
156 subtype = BGP4MP_MESSAGE_ADDPATH;
157 }
158 }
159
160 return subtype;
161 }
162
163 void
mrt_dump_bgp_msg(struct mrt * mrt,struct ibuf * pkg,struct peer * peer,enum msg_type msgtype)164 mrt_dump_bgp_msg(struct mrt *mrt, struct ibuf *pkg, struct peer *peer,
165 enum msg_type msgtype)
166 {
167 struct ibuf *buf;
168 int in = 0;
169 uint16_t subtype = BGP4MP_MESSAGE;
170
171 /* get the direction of the message to swap address and AS fields */
172 if (mrt->type == MRT_ALL_IN || mrt->type == MRT_UPDATE_IN)
173 in = 1;
174
175 subtype = mrt_bgp_msg_subtype(mrt, pkg, peer, msgtype, in);
176
177 if (mrt_dump_hdr_se(&buf, peer, MSG_PROTOCOL_BGP4MP_ET, subtype,
178 ibuf_size(pkg), in) == -1)
179 goto fail;
180
181 if (ibuf_add_ibuf(buf, pkg) == -1)
182 goto fail;
183
184 ibuf_close(mrt->wbuf, buf);
185 return;
186
187 fail:
188 log_warn("%s: ibuf error", __func__);
189 ibuf_free(buf);
190 }
191
192 void
mrt_dump_state(struct mrt * mrt,uint16_t old_state,uint16_t new_state,struct peer * peer)193 mrt_dump_state(struct mrt *mrt, uint16_t old_state, uint16_t new_state,
194 struct peer *peer)
195 {
196 struct ibuf *buf;
197 uint16_t subtype = BGP4MP_STATE_CHANGE;
198
199 if (peer->capa.neg.as4byte)
200 subtype = BGP4MP_STATE_CHANGE_AS4;
201
202 if (mrt_dump_hdr_se(&buf, peer, MSG_PROTOCOL_BGP4MP_ET, subtype,
203 2 * sizeof(short), 0) == -1)
204 goto fail;
205
206 if (ibuf_add_n16(buf, old_state) == -1)
207 goto fail;
208 if (ibuf_add_n16(buf, new_state) == -1)
209 goto fail;
210
211 ibuf_close(mrt->wbuf, buf);
212 return;
213
214 fail:
215 log_warn("%s: ibuf error", __func__);
216 ibuf_free(buf);
217 }
218
219 static int
mrt_attr_dump(struct ibuf * buf,struct rde_aspath * a,struct rde_community * c,struct bgpd_addr * nexthop,int v2)220 mrt_attr_dump(struct ibuf *buf, struct rde_aspath *a, struct rde_community *c,
221 struct bgpd_addr *nexthop, int v2)
222 {
223 struct attr *oa;
224 u_char *pdata;
225 uint32_t tmp;
226 int neednewpath = 0;
227 uint16_t plen, afi;
228 uint8_t l, safi;
229
230 /* origin */
231 if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_ORIGIN,
232 &a->origin, 1) == -1)
233 return (-1);
234
235 /* aspath */
236 plen = aspath_length(a->aspath);
237 pdata = aspath_dump(a->aspath);
238
239 if (!v2)
240 pdata = aspath_deflate(pdata, &plen, &neednewpath);
241 if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_ASPATH, pdata,
242 plen) == -1) {
243 if (!v2)
244 free(pdata);
245 return (-1);
246 }
247 if (!v2)
248 free(pdata);
249
250 if (nexthop && nexthop->aid == AID_INET) {
251 /* nexthop, already network byte order */
252 if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_NEXTHOP,
253 &nexthop->v4.s_addr, 4) == -1)
254 return (-1);
255 }
256
257 /* MED, non transitive */
258 if (a->med != 0) {
259 tmp = htonl(a->med);
260 if (attr_writebuf(buf, ATTR_OPTIONAL, ATTR_MED, &tmp, 4) == -1)
261 return (-1);
262 }
263
264 /* local preference */
265 tmp = htonl(a->lpref);
266 if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_LOCALPREF, &tmp, 4) == -1)
267 return (-1);
268
269 /* communities */
270 if (community_writebuf(c, ATTR_COMMUNITIES, 0, buf) == -1 ||
271 community_writebuf(c, ATTR_EXT_COMMUNITIES, 0, buf) == -1 ||
272 community_writebuf(c, ATTR_LARGE_COMMUNITIES, 0, buf) == -1)
273 return (-1);
274
275 /* dump all other path attributes without modification */
276 for (l = 0; l < a->others_len; l++) {
277 if ((oa = a->others[l]) == NULL)
278 break;
279 if (attr_writebuf(buf, oa->flags, oa->type,
280 oa->data, oa->len) == -1)
281 return (-1);
282 }
283
284 if (nexthop && nexthop->aid != AID_INET) {
285 struct ibuf *nhbuf;
286
287 if ((nhbuf = ibuf_dynamic(0, UCHAR_MAX)) == NULL)
288 return (-1);
289 if (!v2) {
290 if (aid2afi(nexthop->aid, &afi, &safi))
291 goto fail;
292 if (ibuf_add_n16(nhbuf, afi) == -1)
293 goto fail;
294 if (ibuf_add_n8(nhbuf, safi) == -1)
295 goto fail;
296 }
297 switch (nexthop->aid) {
298 case AID_INET6:
299 if (ibuf_add_n8(nhbuf, sizeof(struct in6_addr)) == -1)
300 goto fail;
301 if (ibuf_add(nhbuf, &nexthop->v6,
302 sizeof(struct in6_addr)) == -1)
303 goto fail;
304 break;
305 case AID_VPN_IPv4:
306 if (ibuf_add_n8(nhbuf, sizeof(uint64_t) +
307 sizeof(struct in_addr)) == -1)
308 goto fail;
309 if (ibuf_add_n64(nhbuf, 0) == -1) /* set RD to 0 */
310 goto fail;
311 if (ibuf_add(nhbuf, &nexthop->v4,
312 sizeof(nexthop->v4)) == -1)
313 goto fail;
314 break;
315 case AID_VPN_IPv6:
316 if (ibuf_add_n8(nhbuf, sizeof(uint64_t) +
317 sizeof(struct in6_addr)) == -1)
318 goto fail;
319 if (ibuf_add_n64(nhbuf, 0) == -1) /* set RD to 0 */
320 goto fail;
321 if (ibuf_add(nhbuf, &nexthop->v6,
322 sizeof(nexthop->v6)) == -1)
323 goto fail;
324 break;
325 }
326 if (!v2)
327 if (ibuf_add_n8(nhbuf, 0) == -1)
328 goto fail;
329 if (attr_writebuf(buf, ATTR_OPTIONAL, ATTR_MP_REACH_NLRI,
330 ibuf_data(nhbuf), ibuf_size(nhbuf)) == -1) {
331 fail:
332 ibuf_free(nhbuf);
333 return (-1);
334 }
335 ibuf_free(nhbuf);
336 }
337
338 if (neednewpath) {
339 pdata = aspath_prepend(a->aspath, rde_local_as(), 0, &plen);
340 if (plen != 0)
341 if (attr_writebuf(buf, ATTR_OPTIONAL|ATTR_TRANSITIVE,
342 ATTR_AS4_PATH, pdata, plen) == -1) {
343 free(pdata);
344 return (-1);
345 }
346 free(pdata);
347 }
348
349 return (0);
350 }
351
352 static int
mrt_dump_entry_mp(struct mrt * mrt,struct prefix * p,uint16_t snum,struct rde_peer * peer)353 mrt_dump_entry_mp(struct mrt *mrt, struct prefix *p, uint16_t snum,
354 struct rde_peer *peer)
355 {
356 struct ibuf *buf, *hbuf = NULL, *h2buf = NULL;
357 struct nexthop *n;
358 struct bgpd_addr nexthop, *nh;
359 uint16_t len;
360 uint8_t aid;
361
362 if ((buf = ibuf_dynamic(0, MAX_PKTSIZE)) == NULL) {
363 log_warn("mrt_dump_entry_mp: ibuf_dynamic");
364 return (-1);
365 }
366
367 if (mrt_attr_dump(buf, prefix_aspath(p), prefix_communities(p),
368 NULL, 0) == -1)
369 goto fail;
370 len = ibuf_size(buf);
371
372 if ((h2buf = ibuf_dynamic(MRT_BGP4MP_IPv4_HEADER_SIZE +
373 MRT_BGP4MP_IPv4_ENTRY_SIZE, MRT_BGP4MP_IPv6_HEADER_SIZE +
374 MRT_BGP4MP_IPv6_ENTRY_SIZE + MRT_BGP4MP_MAX_PREFIXLEN)) == NULL)
375 goto fail;
376
377 if (ibuf_add_n16(h2buf, peer->conf.local_short_as) == -1)
378 goto fail;
379 if (ibuf_add_n16(h2buf, peer->short_as) == -1)
380 goto fail;
381 if (ibuf_add_n16(h2buf, /* ifindex */ 0) == -1)
382 goto fail;
383
384 /* XXX is this for peer self? */
385 aid = peer->remote_addr.aid == AID_UNSPEC ? p->pt->aid :
386 peer->remote_addr.aid;
387 switch (aid) {
388 case AID_INET:
389 case AID_VPN_IPv4:
390 if (ibuf_add_n16(h2buf, AFI_IPv4) == -1)
391 goto fail;
392 if (ibuf_add(h2buf, &peer->local_v4_addr.v4,
393 sizeof(peer->local_v4_addr.v4)) == -1 ||
394 ibuf_add(h2buf, &peer->remote_addr.v4,
395 sizeof(peer->remote_addr.v4)) == -1)
396 goto fail;
397 break;
398 case AID_INET6:
399 case AID_VPN_IPv6:
400 if (ibuf_add_n16(h2buf, AFI_IPv6) == -1)
401 goto fail;
402 if (ibuf_add(h2buf, &peer->local_v6_addr.v6,
403 sizeof(peer->local_v6_addr.v6)) == -1 ||
404 ibuf_add(h2buf, &peer->remote_addr.v6,
405 sizeof(peer->remote_addr.v6)) == -1)
406 goto fail;
407 break;
408 default:
409 log_warnx("king bula found new AF %d in %s", aid, __func__);
410 goto fail;
411 }
412
413 if (ibuf_add_n16(h2buf, 0) == -1) /* view */
414 goto fail;
415 if (ibuf_add_n16(h2buf, 1) == -1) /* status */
416 goto fail;
417 /* originated timestamp */
418 if (ibuf_add_n32(h2buf, time(NULL) - (getmonotime() -
419 p->lastchange)) == -1)
420 goto fail;
421
422 n = prefix_nexthop(p);
423 if (n == NULL) {
424 memset(&nexthop, 0, sizeof(struct bgpd_addr));
425 nexthop.aid = p->pt->aid;
426 nh = &nexthop;
427 } else
428 nh = &n->exit_nexthop;
429
430 switch (p->pt->aid) {
431 case AID_INET:
432 if (ibuf_add_n16(h2buf, AFI_IPv4) == -1) /* afi */
433 goto fail;
434 if (ibuf_add_n8(h2buf, SAFI_UNICAST) == -1) /* safi */
435 goto fail;
436 if (ibuf_add_n8(h2buf, 4) == -1) /* nhlen */
437 goto fail;
438 if (ibuf_add(h2buf, &nh->v4, sizeof(nh->v4)) == -1)
439 goto fail;
440 break;
441 case AID_INET6:
442 if (ibuf_add_n16(h2buf, AFI_IPv6) == -1) /* afi */
443 goto fail;
444 if (ibuf_add_n8(h2buf, SAFI_UNICAST) == -1) /* safi */
445 goto fail;
446 if (ibuf_add_n8(h2buf, 16) == -1) /* nhlen */
447 goto fail;
448 if (ibuf_add(h2buf, &nh->v6, sizeof(nh->v6)) == -1)
449 goto fail;
450 break;
451 case AID_VPN_IPv4:
452 if (ibuf_add_n16(h2buf, AFI_IPv4) == -1) /* afi */
453 goto fail;
454 if (ibuf_add_n8(h2buf, SAFI_MPLSVPN) == -1) /* safi */
455 goto fail;
456 if (ibuf_add_n8(h2buf, sizeof(uint64_t) +
457 sizeof(struct in_addr)) == -1)
458 goto fail;
459 if (ibuf_add_n64(h2buf, 0) == -1) /* set RD to 0 */
460 goto fail;
461 if (ibuf_add(h2buf, &nh->v4, sizeof(nh->v4)) == -1)
462 goto fail;
463 break;
464 case AID_VPN_IPv6:
465 if (ibuf_add_n16(h2buf, AFI_IPv6) == -1) /* afi */
466 goto fail;
467 if (ibuf_add_n8(h2buf, SAFI_MPLSVPN) == -1) /* safi */
468 goto fail;
469 if (ibuf_add_n8(h2buf, sizeof(uint64_t) +
470 sizeof(struct in6_addr)) == -1)
471 goto fail;
472 if (ibuf_add_n64(h2buf, 0) == -1) /* set RD to 0 */
473 goto fail;
474 if (ibuf_add(h2buf, &nh->v6, sizeof(nh->v6)) == -1)
475 goto fail;
476 break;
477 case AID_FLOWSPECv4:
478 case AID_FLOWSPECv6:
479 if (p->pt->aid == AID_FLOWSPECv4) {
480 if (ibuf_add_n16(h2buf, AFI_IPv4) == -1) /* afi */
481 goto fail;
482 } else {
483 if (ibuf_add_n16(h2buf, AFI_IPv6) == -1) /* afi */
484 goto fail;
485 }
486 if (ibuf_add_n8(h2buf, SAFI_FLOWSPEC) == -1) /* safi */
487 goto fail;
488 if (ibuf_add_n8(h2buf, 0) == -1) /* nhlen */
489 goto fail;
490 break;
491 default:
492 log_warnx("king bula found new AF in %s", __func__);
493 goto fail;
494 }
495
496 if (pt_writebuf(h2buf, p->pt, 0, 0, 0) == -1)
497 goto fail;
498
499 if (ibuf_add_n16(h2buf, len) == -1)
500 goto fail;
501 len += ibuf_size(h2buf);
502
503 if (mrt_dump_hdr_rde(&hbuf, MSG_PROTOCOL_BGP4MP, BGP4MP_ENTRY,
504 len) == -1)
505 goto fail;
506
507 ibuf_close(mrt->wbuf, hbuf);
508 ibuf_close(mrt->wbuf, h2buf);
509 ibuf_close(mrt->wbuf, buf);
510
511 return (len + MRT_HEADER_SIZE);
512
513 fail:
514 log_warn("%s: ibuf error", __func__);
515 ibuf_free(hbuf);
516 ibuf_free(h2buf);
517 ibuf_free(buf);
518 return (-1);
519 }
520
521 static int
mrt_dump_entry(struct mrt * mrt,struct prefix * p,uint16_t snum,struct rde_peer * peer)522 mrt_dump_entry(struct mrt *mrt, struct prefix *p, uint16_t snum,
523 struct rde_peer *peer)
524 {
525 struct ibuf *buf, *hbuf = NULL;
526 struct nexthop *nexthop;
527 struct bgpd_addr addr, *nh;
528 size_t len;
529 uint16_t subtype;
530 uint8_t dummy;
531
532 if (p->pt->aid != peer->remote_addr.aid &&
533 p->pt->aid != AID_INET && p->pt->aid != AID_INET6)
534 /* only able to dump pure IPv4/IPv6 */
535 return (0);
536
537 if ((buf = ibuf_dynamic(0, MAX_PKTSIZE)) == NULL) {
538 log_warn("mrt_dump_entry: ibuf_dynamic");
539 return (-1);
540 }
541
542 nexthop = prefix_nexthop(p);
543 if (nexthop == NULL) {
544 memset(&addr, 0, sizeof(struct bgpd_addr));
545 addr.aid = p->pt->aid;
546 nh = &addr;
547 } else
548 nh = &nexthop->exit_nexthop;
549 if (mrt_attr_dump(buf, prefix_aspath(p), prefix_communities(p),
550 nh, 0) == -1)
551 goto fail;
552
553 len = ibuf_size(buf);
554 aid2afi(p->pt->aid, &subtype, &dummy);
555 if (mrt_dump_hdr_rde(&hbuf, MSG_TABLE_DUMP, subtype, len) == -1)
556 goto fail;
557
558 if (ibuf_add_n16(hbuf, 0) == -1)
559 goto fail;
560 if (ibuf_add_n16(hbuf, snum) == -1)
561 goto fail;
562
563 pt_getaddr(p->pt, &addr);
564 switch (p->pt->aid) {
565 case AID_INET:
566 if (ibuf_add(hbuf, &addr.v4, sizeof(addr.v4)) == -1)
567 goto fail;
568 break;
569 case AID_INET6:
570 if (ibuf_add(hbuf, &addr.v6, sizeof(addr.v6)) == -1)
571 goto fail;
572 break;
573 }
574 if (ibuf_add_n8(hbuf, p->pt->prefixlen) == -1)
575 goto fail;
576
577 if (ibuf_add_n8(hbuf, 1) == -1) /* state */
578 goto fail;
579 /* originated timestamp */
580 if (ibuf_add_n32(hbuf, time(NULL) - (getmonotime() -
581 p->lastchange)) == -1)
582 goto fail;
583 switch (p->pt->aid) {
584 case AID_INET:
585 if (ibuf_add(hbuf, &peer->remote_addr.v4,
586 sizeof(peer->remote_addr.v4)) == -1)
587 goto fail;
588 break;
589 case AID_INET6:
590 if (ibuf_add(hbuf, &peer->remote_addr.v6,
591 sizeof(peer->remote_addr.v6)) == -1)
592 goto fail;
593 break;
594 }
595 if (ibuf_add_n16(hbuf, peer->short_as) == -1)
596 goto fail;
597 if (ibuf_add_n16(hbuf, len) == -1)
598 goto fail;
599
600 ibuf_close(mrt->wbuf, hbuf);
601 ibuf_close(mrt->wbuf, buf);
602
603 return (len + MRT_HEADER_SIZE);
604
605 fail:
606 log_warn("%s: ibuf error", __func__);
607 ibuf_free(hbuf);
608 ibuf_free(buf);
609 return (-1);
610 }
611
612 static int
mrt_dump_entry_v2_rib(struct rib_entry * re,struct ibuf ** nb,struct ibuf ** apb,uint16_t * np,uint16_t * app)613 mrt_dump_entry_v2_rib(struct rib_entry *re, struct ibuf **nb, struct ibuf **apb,
614 uint16_t *np, uint16_t *app)
615 {
616 struct bgpd_addr addr;
617 struct ibuf *buf = NULL, **bp;
618 struct ibuf *tbuf = NULL;
619 struct prefix *p;
620 int addpath;
621
622 *np = 0;
623 *app = 0;
624
625 TAILQ_FOREACH(p, &re->prefix_h, entry.list.rib) {
626 struct nexthop *nexthop;
627 struct bgpd_addr *nh;
628
629 addpath = peer_has_add_path(prefix_peer(p), re->prefix->aid,
630 CAPA_AP_RECV);
631
632 if (addpath) {
633 bp = apb;
634 *app += 1;
635 } else {
636 bp = nb;
637 *np += 1;
638 }
639 if ((buf = *bp) == NULL) {
640 if ((buf = ibuf_dynamic(0, UINT_MAX)) == NULL)
641 goto fail;
642 *bp = buf;
643 }
644
645 nexthop = prefix_nexthop(p);
646 if (nexthop == NULL) {
647 memset(&addr, 0, sizeof(struct bgpd_addr));
648 addr.aid = re->prefix->aid;
649 nh = &addr;
650 } else
651 nh = &nexthop->exit_nexthop;
652
653 if (ibuf_add_n16(buf, prefix_peer(p)->mrt_idx) == -1)
654 goto fail;
655 /* originated timestamp */
656 if (ibuf_add_n32(buf, time(NULL) - (getmonotime() -
657 p->lastchange)) == -1)
658 goto fail;
659
660 /* RFC8050: path-id if add-path is used */
661 if (addpath)
662 if (ibuf_add_n32(buf, p->path_id) == -1)
663 goto fail;
664
665 if ((tbuf = ibuf_dynamic(0, MAX_PKTSIZE)) == NULL)
666 goto fail;
667 if (mrt_attr_dump(tbuf, prefix_aspath(p), prefix_communities(p),
668 nh, 1) == -1)
669 goto fail;
670 if (ibuf_add_n16(buf, ibuf_size(tbuf)) == -1)
671 goto fail;
672 if (ibuf_add_ibuf(buf, tbuf) == -1)
673 goto fail;
674 ibuf_free(tbuf);
675 tbuf = NULL;
676 }
677
678 return 0;
679
680 fail:
681 ibuf_free(tbuf);
682 return -1;
683 }
684
685 static int
mrt_dump_entry_v2(struct mrt * mrt,struct rib_entry * re,uint32_t snum)686 mrt_dump_entry_v2(struct mrt *mrt, struct rib_entry *re, uint32_t snum)
687 {
688 struct ibuf *hbuf = NULL, *nbuf = NULL, *apbuf = NULL, *pbuf;
689 size_t hlen, len;
690 uint16_t subtype, apsubtype, nump, apnump, afi;
691 uint8_t safi;
692
693 if ((pbuf = ibuf_dynamic(0, UINT_MAX)) == NULL) {
694 log_warn("%s: ibuf_dynamic", __func__);
695 return -1;
696 }
697
698 switch (re->prefix->aid) {
699 case AID_INET:
700 subtype = MRT_DUMP_V2_RIB_IPV4_UNICAST;
701 apsubtype = MRT_DUMP_V2_RIB_IPV4_UNICAST_ADDPATH;
702 break;
703 case AID_INET6:
704 subtype = MRT_DUMP_V2_RIB_IPV6_UNICAST;
705 apsubtype = MRT_DUMP_V2_RIB_IPV6_UNICAST_ADDPATH;
706 break;
707 default:
708 /*
709 * XXX The RFC defined the format for this type differently
710 * and it is prohibitly expensive to implement that format.
711 * Instead do what gobgp does and encode it like the other
712 * types.
713 */
714 subtype = MRT_DUMP_V2_RIB_GENERIC;
715 apsubtype = MRT_DUMP_V2_RIB_GENERIC_ADDPATH;
716 aid2afi(re->prefix->aid, &afi, &safi);
717
718 /* first add 3-bytes AFI/SAFI */
719 if (ibuf_add_n16(pbuf, afi) == -1)
720 goto fail;
721 if (ibuf_add_n8(pbuf, safi) == -1)
722 goto fail;
723 break;
724 }
725
726 if (pt_writebuf(pbuf, re->prefix, 0, 0, 0) == -1)
727 goto fail;
728
729 hlen = sizeof(snum) + sizeof(nump) + ibuf_size(pbuf);
730
731 if (mrt_dump_entry_v2_rib(re, &nbuf, &apbuf, &nump, &apnump))
732 goto fail;
733
734 if (nump > 0) {
735 len = ibuf_size(nbuf) + hlen;
736 if (mrt_dump_hdr_rde(&hbuf, MSG_TABLE_DUMP_V2, subtype,
737 len) == -1)
738 goto fail;
739
740 if (ibuf_add_n32(hbuf, snum) == -1)
741 goto fail;
742 if (ibuf_add_ibuf(hbuf, pbuf) == -1)
743 goto fail;
744 if (ibuf_add_n16(hbuf, nump) == -1)
745 goto fail;
746
747 ibuf_close(mrt->wbuf, hbuf);
748 ibuf_close(mrt->wbuf, nbuf);
749 hbuf = NULL;
750 nbuf = NULL;
751 }
752
753 if (apnump > 0) {
754 len = ibuf_size(apbuf) + hlen;
755 if (mrt_dump_hdr_rde(&hbuf, MSG_TABLE_DUMP_V2, apsubtype,
756 len) == -1)
757 goto fail;
758
759 if (ibuf_add_n32(hbuf, snum) == -1)
760 goto fail;
761 if (ibuf_add_ibuf(hbuf, pbuf) == -1)
762 goto fail;
763 if (ibuf_add_n16(hbuf, apnump) == -1)
764 goto fail;
765
766 ibuf_close(mrt->wbuf, hbuf);
767 ibuf_close(mrt->wbuf, apbuf);
768 hbuf = NULL;
769 apbuf = NULL;
770 }
771
772 ibuf_free(pbuf);
773 return (0);
774 fail:
775 log_warn("%s: ibuf error", __func__);
776 ibuf_free(apbuf);
777 ibuf_free(nbuf);
778 ibuf_free(hbuf);
779 ibuf_free(pbuf);
780 return (-1);
781 }
782
783 struct cb_arg {
784 struct ibuf *buf;
785 int nump;
786 };
787
788 static void
mrt_dump_v2_hdr_peer(struct rde_peer * peer,void * arg)789 mrt_dump_v2_hdr_peer(struct rde_peer *peer, void *arg)
790 {
791 struct cb_arg *a = arg;
792
793 if (a->nump == -1)
794 return;
795 peer->mrt_idx = a->nump;
796 if (mrt_dump_peer(a->buf, peer) == -1) {
797 a->nump = -1;
798 return;
799 }
800 a->nump++;
801 }
802
803 int
mrt_dump_v2_hdr(struct mrt * mrt,struct bgpd_config * conf)804 mrt_dump_v2_hdr(struct mrt *mrt, struct bgpd_config *conf)
805 {
806 struct ibuf *buf, *hbuf = NULL;
807 size_t len, off;
808 uint16_t nlen, nump;
809 struct cb_arg arg;
810
811 if ((buf = ibuf_dynamic(0, UINT_MAX)) == NULL) {
812 log_warn("%s: ibuf_dynamic", __func__);
813 return (-1);
814 }
815
816 if (ibuf_add_n32(buf, conf->bgpid) == -1)
817 goto fail;
818 nlen = strlen(mrt->rib);
819 if (nlen > 0)
820 nlen += 1;
821 if (ibuf_add_n16(buf, nlen) == -1)
822 goto fail;
823 if (ibuf_add(buf, mrt->rib, nlen) == -1)
824 goto fail;
825
826 off = ibuf_size(buf);
827 if (ibuf_add_zero(buf, sizeof(nump)) == -1)
828 goto fail;
829 arg.nump = 0;
830 arg.buf = buf;
831 peer_foreach(mrt_dump_v2_hdr_peer, &arg);
832 if (arg.nump == -1)
833 goto fail;
834
835 if (ibuf_set_n16(buf, off, arg.nump) == -1)
836 goto fail;
837
838 len = ibuf_size(buf);
839 if (mrt_dump_hdr_rde(&hbuf, MSG_TABLE_DUMP_V2,
840 MRT_DUMP_V2_PEER_INDEX_TABLE, len) == -1)
841 goto fail;
842
843 ibuf_close(mrt->wbuf, hbuf);
844 ibuf_close(mrt->wbuf, buf);
845
846 return (0);
847 fail:
848 log_warn("%s: ibuf error", __func__);
849 ibuf_free(hbuf);
850 ibuf_free(buf);
851 return (-1);
852 }
853
854 static int
mrt_dump_peer(struct ibuf * buf,struct rde_peer * peer)855 mrt_dump_peer(struct ibuf *buf, struct rde_peer *peer)
856 {
857 uint8_t type = 0;
858
859 if (peer->capa.as4byte)
860 type |= MRT_DUMP_V2_PEER_BIT_A;
861 if (peer->remote_addr.aid == AID_INET6)
862 type |= MRT_DUMP_V2_PEER_BIT_I;
863
864 if (ibuf_add_n8(buf, type) == -1)
865 goto fail;
866 if (ibuf_add_n32(buf, peer->remote_bgpid) == -1)
867 goto fail;
868
869 switch (peer->remote_addr.aid) {
870 case AID_INET:
871 if (ibuf_add(buf, &peer->remote_addr.v4,
872 sizeof(peer->remote_addr.v4)) == -1)
873 goto fail;
874 break;
875 case AID_INET6:
876 if (ibuf_add(buf, &peer->remote_addr.v6,
877 sizeof(peer->remote_addr.v6)) == -1)
878 goto fail;
879 break;
880 case AID_UNSPEC: /* XXX special handling for peerself? */
881 if (ibuf_add_n32(buf, 0) == -1)
882 goto fail;
883 break;
884 default:
885 log_warnx("king bula found new AF in %s", __func__);
886 goto fail;
887 }
888
889 if (peer->capa.as4byte) {
890 if (ibuf_add_n32(buf, peer->conf.remote_as) == -1)
891 goto fail;
892 } else {
893 if (ibuf_add_n16(buf, peer->short_as) == -1)
894 goto fail;
895 }
896 return (0);
897 fail:
898 log_warn("%s: ibuf error", __func__);
899 return (-1);
900 }
901
902 void
mrt_dump_upcall(struct rib_entry * re,void * ptr)903 mrt_dump_upcall(struct rib_entry *re, void *ptr)
904 {
905 struct mrt *mrtbuf = ptr;
906 struct prefix *p;
907
908 if (mrtbuf->type == MRT_TABLE_DUMP_V2) {
909 mrt_dump_entry_v2(mrtbuf, re, mrtbuf->seqnum++);
910 return;
911 }
912
913 /*
914 * dump all prefixes even the inactive ones. That is the way zebra
915 * dumps the table so we do the same. If only the active route should
916 * be dumped p should be set to p = pt->active.
917 */
918 TAILQ_FOREACH(p, &re->prefix_h, entry.list.rib) {
919 if (mrtbuf->type == MRT_TABLE_DUMP)
920 mrt_dump_entry(mrtbuf, p, mrtbuf->seqnum++,
921 prefix_peer(p));
922 else
923 mrt_dump_entry_mp(mrtbuf, p, mrtbuf->seqnum++,
924 prefix_peer(p));
925 }
926 }
927
928 void
mrt_done(struct mrt * mrtbuf)929 mrt_done(struct mrt *mrtbuf)
930 {
931 mrtbuf->state = MRT_STATE_REMOVE;
932 }
933
934 static int
mrt_dump_hdr_se(struct ibuf ** bp,struct peer * peer,uint16_t type,uint16_t subtype,uint32_t len,int swap)935 mrt_dump_hdr_se(struct ibuf ** bp, struct peer *peer, uint16_t type,
936 uint16_t subtype, uint32_t len, int swap)
937 {
938 struct timespec time;
939
940 if ((*bp = ibuf_dynamic(MRT_ET_HEADER_SIZE, MRT_ET_HEADER_SIZE +
941 MRT_BGP4MP_AS4_IPv6_HEADER_SIZE + len)) == NULL)
942 return (-1);
943
944 clock_gettime(CLOCK_REALTIME, &time);
945
946 if (ibuf_add_n32(*bp, time.tv_sec) == -1)
947 goto fail;
948 if (ibuf_add_n16(*bp, type) == -1)
949 goto fail;
950 if (ibuf_add_n16(*bp, subtype) == -1)
951 goto fail;
952
953 switch (peer->local.aid) {
954 case AID_INET:
955 if (subtype == BGP4MP_STATE_CHANGE_AS4 ||
956 subtype == BGP4MP_MESSAGE_AS4 ||
957 subtype == BGP4MP_MESSAGE_AS4_ADDPATH)
958 len += MRT_BGP4MP_ET_AS4_IPv4_HEADER_SIZE;
959 else
960 len += MRT_BGP4MP_ET_IPv4_HEADER_SIZE;
961 break;
962 case AID_INET6:
963 if (subtype == BGP4MP_STATE_CHANGE_AS4 ||
964 subtype == BGP4MP_MESSAGE_AS4 ||
965 subtype == BGP4MP_MESSAGE_AS4_ADDPATH)
966 len += MRT_BGP4MP_ET_AS4_IPv6_HEADER_SIZE;
967 else
968 len += MRT_BGP4MP_ET_IPv6_HEADER_SIZE;
969 break;
970 case 0:
971 goto fail;
972 default:
973 log_warnx("king bula found new AF in %s", __func__);
974 goto fail;
975 }
976
977 if (ibuf_add_n32(*bp, len) == -1)
978 goto fail;
979 /* millisecond field use by the _ET format */
980 if (ibuf_add_n32(*bp, time.tv_nsec / 1000) == -1)
981 goto fail;
982
983 if (subtype == BGP4MP_STATE_CHANGE_AS4 ||
984 subtype == BGP4MP_MESSAGE_AS4 ||
985 subtype == BGP4MP_MESSAGE_AS4_ADDPATH) {
986 if (!swap)
987 if (ibuf_add_n32(*bp, peer->conf.local_as) == -1)
988 goto fail;
989 if (ibuf_add_n32(*bp, peer->conf.remote_as) == -1)
990 goto fail;
991 if (swap)
992 if (ibuf_add_n32(*bp, peer->conf.local_as) == -1)
993 goto fail;
994 } else {
995 if (!swap)
996 if (ibuf_add_n16(*bp, peer->conf.local_short_as) == -1)
997 goto fail;
998 if (ibuf_add_n16(*bp, peer->short_as) == -1)
999 goto fail;
1000 if (swap)
1001 if (ibuf_add_n16(*bp, peer->conf.local_short_as) == -1)
1002 goto fail;
1003 }
1004
1005 if (ibuf_add_n16(*bp, /* ifindex */ 0) == -1)
1006 goto fail;
1007
1008 switch (peer->local.aid) {
1009 case AID_INET:
1010 if (ibuf_add_n16(*bp, AFI_IPv4) == -1)
1011 goto fail;
1012 if (!swap)
1013 if (ibuf_add(*bp, &peer->local.v4,
1014 sizeof(peer->local.v4)) == -1)
1015 goto fail;
1016 if (ibuf_add(*bp, &peer->remote.v4,
1017 sizeof(peer->remote.v4)) == -1)
1018 goto fail;
1019 if (swap)
1020 if (ibuf_add(*bp, &peer->local.v4,
1021 sizeof(peer->local.v4)) == -1)
1022 goto fail;
1023 break;
1024 case AID_INET6:
1025 if (ibuf_add_n16(*bp, AFI_IPv6) == -1)
1026 goto fail;
1027 if (!swap)
1028 if (ibuf_add(*bp, &peer->local.v6,
1029 sizeof(peer->local.v6)) == -1)
1030 goto fail;
1031 if (ibuf_add(*bp, &peer->remote.v6,
1032 sizeof(peer->remote.v6)) == -1)
1033 goto fail;
1034 if (swap)
1035 if (ibuf_add(*bp, &peer->local.v6,
1036 sizeof(peer->local.v6)) == -1)
1037 goto fail;
1038 break;
1039 }
1040
1041 return (0);
1042
1043 fail:
1044 ibuf_free(*bp);
1045 *bp = NULL;
1046 return (-1);
1047 }
1048
1049 int
mrt_dump_hdr_rde(struct ibuf ** bp,uint16_t type,uint16_t subtype,uint32_t len)1050 mrt_dump_hdr_rde(struct ibuf **bp, uint16_t type, uint16_t subtype,
1051 uint32_t len)
1052 {
1053 struct timespec time;
1054
1055 if ((*bp = ibuf_dynamic(MRT_HEADER_SIZE, MRT_HEADER_SIZE +
1056 MRT_BGP4MP_AS4_IPv6_HEADER_SIZE + MRT_BGP4MP_IPv6_ENTRY_SIZE)) ==
1057 NULL)
1058 return (-1);
1059
1060 clock_gettime(CLOCK_REALTIME, &time);
1061
1062 if (ibuf_add_n32(*bp, time.tv_sec) == -1)
1063 goto fail;
1064 if (ibuf_add_n16(*bp, type) == -1)
1065 goto fail;
1066 if (ibuf_add_n16(*bp, subtype) == -1)
1067 goto fail;
1068
1069 switch (type) {
1070 case MSG_TABLE_DUMP:
1071 switch (subtype) {
1072 case AFI_IPv4:
1073 len += MRT_DUMP_HEADER_SIZE;
1074 break;
1075 case AFI_IPv6:
1076 len += MRT_DUMP_HEADER_SIZE_V6;
1077 break;
1078 }
1079 if (ibuf_add_n32(*bp, len) == -1)
1080 goto fail;
1081 break;
1082 case MSG_PROTOCOL_BGP4MP:
1083 case MSG_TABLE_DUMP_V2:
1084 if (ibuf_add_n32(*bp, len) == -1)
1085 goto fail;
1086 break;
1087 default:
1088 log_warnx("mrt_dump_hdr_rde: unsupported type");
1089 goto fail;
1090 }
1091 return (0);
1092
1093 fail:
1094 ibuf_free(*bp);
1095 *bp = NULL;
1096 return (-1);
1097 }
1098
1099 void
mrt_write(struct mrt * mrt)1100 mrt_write(struct mrt *mrt)
1101 {
1102 if (ibuf_write(mrt->fd, mrt->wbuf) == -1) {
1103 log_warn("mrt dump aborted, mrt_write");
1104 mrt_clean(mrt);
1105 mrt_done(mrt);
1106 }
1107 }
1108
1109 void
mrt_clean(struct mrt * mrt)1110 mrt_clean(struct mrt *mrt)
1111 {
1112 close(mrt->fd);
1113 msgbuf_free(mrt->wbuf);
1114 mrt->wbuf = NULL;
1115 }
1116
1117 static struct imsgbuf *mrt_imsgbuf[2];
1118
1119 void
mrt_init(struct imsgbuf * rde,struct imsgbuf * se)1120 mrt_init(struct imsgbuf *rde, struct imsgbuf *se)
1121 {
1122 mrt_imsgbuf[RDEIDX] = rde;
1123 mrt_imsgbuf[SEIDX] = se;
1124 }
1125
1126 int
mrt_open(struct mrt * mrt,time_t now)1127 mrt_open(struct mrt *mrt, time_t now)
1128 {
1129 enum imsg_type type;
1130 int fd;
1131
1132 if (strftime(MRT2MC(mrt)->file, sizeof(MRT2MC(mrt)->file),
1133 MRT2MC(mrt)->name, localtime(&now)) == 0) {
1134 log_warnx("mrt_open: strftime conversion failed");
1135 return (-1);
1136 }
1137
1138 fd = open(MRT2MC(mrt)->file,
1139 O_WRONLY|O_NONBLOCK|O_CREAT|O_TRUNC|O_CLOEXEC, 0644);
1140 if (fd == -1) {
1141 log_warn("mrt_open %s", MRT2MC(mrt)->file);
1142 return (1);
1143 }
1144
1145 if (mrt->state == MRT_STATE_OPEN)
1146 type = IMSG_MRT_OPEN;
1147 else
1148 type = IMSG_MRT_REOPEN;
1149
1150 if (imsg_compose(mrt_imsgbuf[TYPE2IDX(mrt->type)], type, 0, 0, fd,
1151 mrt, sizeof(struct mrt)) == -1)
1152 log_warn("mrt_open");
1153
1154 return (1);
1155 }
1156
1157 time_t
mrt_timeout(struct mrt_head * mrt)1158 mrt_timeout(struct mrt_head *mrt)
1159 {
1160 struct mrt *m;
1161 time_t now;
1162 time_t timeout = -1;
1163
1164 now = time(NULL);
1165 LIST_FOREACH(m, mrt, entry) {
1166 if (m->state == MRT_STATE_RUNNING &&
1167 MRT2MC(m)->ReopenTimerInterval != 0) {
1168 if (MRT2MC(m)->ReopenTimer <= now) {
1169 mrt_open(m, now);
1170 MRT2MC(m)->ReopenTimer =
1171 now + MRT2MC(m)->ReopenTimerInterval;
1172 }
1173 if (timeout == -1 ||
1174 MRT2MC(m)->ReopenTimer - now < timeout)
1175 timeout = MRT2MC(m)->ReopenTimer - now;
1176 }
1177 }
1178 return (timeout);
1179 }
1180
1181 void
mrt_reconfigure(struct mrt_head * mrt)1182 mrt_reconfigure(struct mrt_head *mrt)
1183 {
1184 struct mrt *m, *xm;
1185 time_t now;
1186
1187 now = time(NULL);
1188 for (m = LIST_FIRST(mrt); m != NULL; m = xm) {
1189 xm = LIST_NEXT(m, entry);
1190 if (m->state == MRT_STATE_OPEN ||
1191 m->state == MRT_STATE_REOPEN) {
1192 if (mrt_open(m, now) == -1)
1193 continue;
1194 if (MRT2MC(m)->ReopenTimerInterval != 0)
1195 MRT2MC(m)->ReopenTimer =
1196 now + MRT2MC(m)->ReopenTimerInterval;
1197 m->state = MRT_STATE_RUNNING;
1198 }
1199 if (m->state == MRT_STATE_REMOVE) {
1200 if (imsg_compose(mrt_imsgbuf[TYPE2IDX(m->type)],
1201 IMSG_MRT_CLOSE, 0, 0, -1, m, sizeof(struct mrt)) ==
1202 -1)
1203 log_warn("mrt_reconfigure");
1204 LIST_REMOVE(m, entry);
1205 free(m);
1206 continue;
1207 }
1208 }
1209 }
1210
1211 void
mrt_handler(struct mrt_head * mrt)1212 mrt_handler(struct mrt_head *mrt)
1213 {
1214 struct mrt *m;
1215 time_t now;
1216
1217 now = time(NULL);
1218 LIST_FOREACH(m, mrt, entry) {
1219 if (m->state == MRT_STATE_RUNNING &&
1220 (MRT2MC(m)->ReopenTimerInterval != 0 ||
1221 m->type == MRT_TABLE_DUMP ||
1222 m->type == MRT_TABLE_DUMP_MP ||
1223 m->type == MRT_TABLE_DUMP_V2)) {
1224 if (mrt_open(m, now) == -1)
1225 continue;
1226 MRT2MC(m)->ReopenTimer =
1227 now + MRT2MC(m)->ReopenTimerInterval;
1228 }
1229 }
1230 }
1231
1232 struct mrt *
mrt_get(struct mrt_head * c,struct mrt * m)1233 mrt_get(struct mrt_head *c, struct mrt *m)
1234 {
1235 struct mrt *t;
1236
1237 LIST_FOREACH(t, c, entry) {
1238 if (t->type != m->type)
1239 continue;
1240 if (strcmp(t->rib, m->rib))
1241 continue;
1242 if (t->peer_id == m->peer_id &&
1243 t->group_id == m->group_id)
1244 return (t);
1245 }
1246 return (NULL);
1247 }
1248
1249 void
mrt_mergeconfig(struct mrt_head * xconf,struct mrt_head * nconf)1250 mrt_mergeconfig(struct mrt_head *xconf, struct mrt_head *nconf)
1251 {
1252 struct mrt *m, *xm;
1253
1254 /* both lists here are actually struct mrt_conifg nodes */
1255 LIST_FOREACH(m, nconf, entry) {
1256 if ((xm = mrt_get(xconf, m)) == NULL) {
1257 /* NEW */
1258 if ((xm = malloc(sizeof(struct mrt_config))) == NULL)
1259 fatal("mrt_mergeconfig");
1260 memcpy(xm, m, sizeof(struct mrt_config));
1261 xm->state = MRT_STATE_OPEN;
1262 LIST_INSERT_HEAD(xconf, xm, entry);
1263 } else {
1264 /* MERGE */
1265 if (strlcpy(MRT2MC(xm)->name, MRT2MC(m)->name,
1266 sizeof(MRT2MC(xm)->name)) >=
1267 sizeof(MRT2MC(xm)->name))
1268 fatalx("mrt_mergeconfig: strlcpy");
1269 MRT2MC(xm)->ReopenTimerInterval =
1270 MRT2MC(m)->ReopenTimerInterval;
1271 xm->state = MRT_STATE_REOPEN;
1272 }
1273 }
1274
1275 LIST_FOREACH(xm, xconf, entry)
1276 if (mrt_get(nconf, xm) == NULL)
1277 /* REMOVE */
1278 xm->state = MRT_STATE_REMOVE;
1279
1280 /* free config */
1281 while ((m = LIST_FIRST(nconf)) != NULL) {
1282 LIST_REMOVE(m, entry);
1283 free(m);
1284 }
1285 }
1286