xref: /openbsd-src/usr.sbin/bgpd/mrt.c (revision 0d4ceb41004f299c91661fe76cfd13f053a31300)
1*0d4ceb41Sclaudio /*	$OpenBSD: mrt.c,v 1.123 2024/12/16 16:10:10 claudio Exp $ */
2a16c0992Shenning 
3a16c0992Shenning /*
4e854144bSclaudio  * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org>
5a16c0992Shenning  *
6a16c0992Shenning  * Permission to use, copy, modify, and distribute this software for any
7a16c0992Shenning  * purpose with or without fee is hereby granted, provided that the above
8a16c0992Shenning  * copyright notice and this permission notice appear in all copies.
9a16c0992Shenning  *
10a16c0992Shenning  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11a16c0992Shenning  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12a16c0992Shenning  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13a16c0992Shenning  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14a16c0992Shenning  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15a16c0992Shenning  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16a16c0992Shenning  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17a16c0992Shenning  */
18a16c0992Shenning 
19a16c0992Shenning #include <sys/types.h>
20a16c0992Shenning #include <sys/queue.h>
21a16c0992Shenning 
22a16c0992Shenning #include <errno.h>
23a16c0992Shenning #include <fcntl.h>
24fa46eaeaSguenther #include <limits.h>
25a16c0992Shenning #include <stdlib.h>
26a16c0992Shenning #include <string.h>
27a16c0992Shenning #include <time.h>
28a16c0992Shenning #include <unistd.h>
29a16c0992Shenning 
30a16c0992Shenning #include "bgpd.h"
31a16c0992Shenning #include "rde.h"
32df24a79cSclaudio #include "session.h"
33a16c0992Shenning 
34a16c0992Shenning #include "mrt.h"
355e3f6f95Sbenno #include "log.h"
36a16c0992Shenning 
37e3ef2697Sclaudio static int	mrt_attr_dump(struct ibuf *, struct rde_aspath *,
38e3ef2697Sclaudio 		    struct rde_community *, struct bgpd_addr *, int);
39e3ef2697Sclaudio static int	mrt_dump_entry_mp(struct mrt *, struct prefix *, uint16_t,
4097448f4fSclaudio 		    struct rde_peer*);
41e3ef2697Sclaudio static int	mrt_dump_entry(struct mrt *, struct prefix *, uint16_t,
42e3ef2697Sclaudio 		    struct rde_peer*);
43e3ef2697Sclaudio static int	mrt_dump_entry_v2(struct mrt *, struct rib_entry *, uint32_t);
44e3ef2697Sclaudio static int	mrt_dump_peer(struct ibuf *, struct rde_peer *);
45e3ef2697Sclaudio static int	mrt_dump_hdr_se(struct ibuf **, struct peer *, uint16_t,
46e3ef2697Sclaudio 		    uint16_t, uint32_t, int);
47e3ef2697Sclaudio static int	mrt_dump_hdr_rde(struct ibuf **, uint16_t type, uint16_t,
48e3ef2697Sclaudio 		    uint32_t);
49e3ef2697Sclaudio static int	mrt_open(struct mrt *, time_t);
50a16c0992Shenning 
51199afbfaSflorian #define RDEIDX		0
52199afbfaSflorian #define SEIDX		1
53199afbfaSflorian #define TYPE2IDX(x)	((x == MRT_TABLE_DUMP ||			\
54199afbfaSflorian 			    x == MRT_TABLE_DUMP_MP ||			\
55199afbfaSflorian 			    x == MRT_TABLE_DUMP_V2) ? RDEIDX : SEIDX	\
56199afbfaSflorian 			)
57199afbfaSflorian 
5839386878Sclaudio static uint8_t
59eaff30a2Sclaudio mrt_update_msg_guess_aid(struct ibuf *pkg)
60a16c0992Shenning {
61eaff30a2Sclaudio 	struct ibuf buf;
6239386878Sclaudio 	uint16_t wlen, alen, len, afi;
63eaff30a2Sclaudio 	uint8_t type, flags, aid, safi;
6436afba5eSclaudio 
65eaff30a2Sclaudio 	ibuf_from_ibuf(&buf, pkg);
6636afba5eSclaudio 
67eaff30a2Sclaudio 	if (ibuf_skip(&buf, MSGSIZE_HEADER) == -1 ||
68eaff30a2Sclaudio 	    ibuf_get_n16(&buf, &wlen) == -1)
6936afba5eSclaudio 		goto bad;
7036afba5eSclaudio 
7136afba5eSclaudio 	if (wlen > 0) {
723a50f0a9Sjmc 		/* UPDATE has withdraw routes, therefore IPv4 */
7336afba5eSclaudio 		return AID_INET;
7436afba5eSclaudio 	}
7536afba5eSclaudio 
76eaff30a2Sclaudio 	if (ibuf_get_n16(&buf, &alen) == -1)
77eaff30a2Sclaudio 		goto bad;
7836afba5eSclaudio 
79eaff30a2Sclaudio 	if (alen < ibuf_size(&buf)) {
803a50f0a9Sjmc 		/* UPDATE has NLRI prefixes, therefore IPv4 */
8136afba5eSclaudio 		return AID_INET;
8236afba5eSclaudio 	}
8336afba5eSclaudio 
8436afba5eSclaudio 	if (wlen == 0 && alen == 0) {
8536afba5eSclaudio 		/* UPDATE is an IPv4 EoR marker */
8636afba5eSclaudio 		return AID_INET;
8736afba5eSclaudio 	}
8836afba5eSclaudio 
8936afba5eSclaudio 	/* bad attribute length */
90eaff30a2Sclaudio 	if (alen > ibuf_size(&buf))
9136afba5eSclaudio 		goto bad;
9236afba5eSclaudio 
9336afba5eSclaudio 	/* try to extract AFI/SAFI from the MP attributes */
94eaff30a2Sclaudio 	while (ibuf_size(&buf) > 0) {
95eaff30a2Sclaudio 		if (ibuf_get_n8(&buf, &flags) == -1 ||
96eaff30a2Sclaudio 		    ibuf_get_n8(&buf, &type) == -1)
9736afba5eSclaudio 			goto bad;
98eaff30a2Sclaudio 		if (flags & ATTR_EXTLEN) {
99eaff30a2Sclaudio 			if (ibuf_get_n16(&buf, &len) == -1)
10036afba5eSclaudio 				goto bad;
10136afba5eSclaudio 		} else {
102eaff30a2Sclaudio 			uint8_t tmp;
103eaff30a2Sclaudio 			if (ibuf_get_n8(&buf, &tmp) == -1)
104eaff30a2Sclaudio 				goto bad;
105eaff30a2Sclaudio 			len = tmp;
10636afba5eSclaudio 		}
107eaff30a2Sclaudio 		if (len > ibuf_size(&buf))
10836afba5eSclaudio 			goto bad;
10936afba5eSclaudio 
11036afba5eSclaudio 		if (type == ATTR_MP_REACH_NLRI ||
11136afba5eSclaudio 		    type == ATTR_MP_UNREACH_NLRI) {
112eaff30a2Sclaudio 			if (ibuf_get_n16(&buf, &afi) == -1 ||
113eaff30a2Sclaudio 			    ibuf_get_n8(&buf, &safi) == -1)
11436afba5eSclaudio 				goto bad;
115eaff30a2Sclaudio 			if (afi2aid(afi, safi, &aid) == -1)
11636afba5eSclaudio 				goto bad;
11736afba5eSclaudio 			return aid;
11836afba5eSclaudio 		}
119eaff30a2Sclaudio 		if (ibuf_skip(&buf, len) == -1)
120eaff30a2Sclaudio 			goto bad;
12136afba5eSclaudio 	}
12236afba5eSclaudio 
12336afba5eSclaudio bad:
12436afba5eSclaudio 	return AID_UNSPEC;
12536afba5eSclaudio }
12636afba5eSclaudio 
12739386878Sclaudio static uint16_t
128eaff30a2Sclaudio mrt_bgp_msg_subtype(struct mrt *mrt, struct ibuf *pkg, struct peer *peer,
129eaff30a2Sclaudio     enum msg_type msgtype, int in)
13036afba5eSclaudio {
13139386878Sclaudio 	uint16_t subtype = BGP4MP_MESSAGE;
13239386878Sclaudio 	uint8_t aid, mask;
13360ff1b21Sclaudio 
13460ff1b21Sclaudio 	if (peer->capa.neg.as4byte)
13560ff1b21Sclaudio 		subtype = BGP4MP_MESSAGE_AS4;
136a16c0992Shenning 
137*0d4ceb41Sclaudio 	if (msgtype != MSG_UPDATE)
13836afba5eSclaudio 		return subtype;
13936afba5eSclaudio 
14036afba5eSclaudio 	/*
14136afba5eSclaudio 	 * RFC8050 adjust types for add-path enabled sessions.
14236afba5eSclaudio 	 * It is necessary to extract the AID from UPDATES to decide
14336afba5eSclaudio 	 * if the add-path types are needed or not. The ADDPATH
14436afba5eSclaudio 	 * subtypes only matter for BGP UPDATES.
14536afba5eSclaudio 	 */
14636afba5eSclaudio 
14736afba5eSclaudio 	mask = in ? CAPA_AP_RECV : CAPA_AP_SEND;
14836afba5eSclaudio 	/* only guess if add-path could be active */
14936afba5eSclaudio 	if (peer->capa.neg.add_path[0] & mask) {
150eaff30a2Sclaudio 		aid = mrt_update_msg_guess_aid(pkg);
15136afba5eSclaudio 		if (aid != AID_UNSPEC &&
15236afba5eSclaudio 		    (peer->capa.neg.add_path[aid] & mask)) {
15336afba5eSclaudio 			if (peer->capa.neg.as4byte)
15436afba5eSclaudio 				subtype = BGP4MP_MESSAGE_AS4_ADDPATH;
15536afba5eSclaudio 			else
15636afba5eSclaudio 				subtype = BGP4MP_MESSAGE_ADDPATH;
15736afba5eSclaudio 		}
15836afba5eSclaudio 	}
15936afba5eSclaudio 
16036afba5eSclaudio 	return subtype;
16136afba5eSclaudio }
16236afba5eSclaudio 
16336afba5eSclaudio void
164eaff30a2Sclaudio mrt_dump_bgp_msg(struct mrt *mrt, struct ibuf *pkg, struct peer *peer,
165eaff30a2Sclaudio     enum msg_type msgtype)
16636afba5eSclaudio {
16736afba5eSclaudio 	struct ibuf	*buf;
16836afba5eSclaudio 	int		 in = 0;
16939386878Sclaudio 	uint16_t	 subtype = BGP4MP_MESSAGE;
17036afba5eSclaudio 
171e1d31db5Sclaudio 	/* get the direction of the message to swap address and AS fields */
172e1d31db5Sclaudio 	if (mrt->type == MRT_ALL_IN || mrt->type == MRT_UPDATE_IN)
17336afba5eSclaudio 		in = 1;
17436afba5eSclaudio 
175eaff30a2Sclaudio 	subtype = mrt_bgp_msg_subtype(mrt, pkg, peer, msgtype, in);
176e1d31db5Sclaudio 
177933383cdSclaudio 	if (mrt_dump_hdr_se(&buf, peer, MSG_PROTOCOL_BGP4MP_ET, subtype,
178eaff30a2Sclaudio 	    ibuf_size(pkg), in) == -1)
179e3ef2697Sclaudio 		goto fail;
180a16c0992Shenning 
181eaff30a2Sclaudio 	if (ibuf_add_ibuf(buf, pkg) == -1)
182e3ef2697Sclaudio 		goto fail;
183a16c0992Shenning 
18405453d67Sclaudio 	ibuf_close(mrt->wbuf, buf);
185e3ef2697Sclaudio 	return;
186e3ef2697Sclaudio 
187e3ef2697Sclaudio fail:
188e3ef2697Sclaudio 	log_warn("%s: ibuf error", __func__);
189e3ef2697Sclaudio 	ibuf_free(buf);
190a16c0992Shenning }
191a16c0992Shenning 
192355a6982Sclaudio void
19339386878Sclaudio mrt_dump_state(struct mrt *mrt, uint16_t old_state, uint16_t new_state,
194355a6982Sclaudio     struct peer *peer)
1952a51171bSclaudio {
196e39620e5Snicm 	struct ibuf	*buf;
19739386878Sclaudio 	uint16_t	 subtype = BGP4MP_STATE_CHANGE;
1982a51171bSclaudio 
19960ff1b21Sclaudio 	if (peer->capa.neg.as4byte)
20060ff1b21Sclaudio 		subtype = BGP4MP_STATE_CHANGE_AS4;
20160ff1b21Sclaudio 
202933383cdSclaudio 	if (mrt_dump_hdr_se(&buf, peer, MSG_PROTOCOL_BGP4MP_ET, subtype,
203355a6982Sclaudio 	    2 * sizeof(short), 0) == -1)
204e3ef2697Sclaudio 		goto fail;
2052a51171bSclaudio 
206e3ef2697Sclaudio 	if (ibuf_add_n16(buf, old_state) == -1)
207e3ef2697Sclaudio 		goto fail;
208e3ef2697Sclaudio 	if (ibuf_add_n16(buf, new_state) == -1)
209e3ef2697Sclaudio 		goto fail;
2102a51171bSclaudio 
21105453d67Sclaudio 	ibuf_close(mrt->wbuf, buf);
212355a6982Sclaudio 	return;
2132a51171bSclaudio 
214355a6982Sclaudio fail:
215e3ef2697Sclaudio 	log_warn("%s: ibuf error", __func__);
216e39620e5Snicm 	ibuf_free(buf);
2177f9525e9Sclaudio }
2187f9525e9Sclaudio 
219e3ef2697Sclaudio static int
22053372d18Sclaudio mrt_attr_dump(struct ibuf *buf, struct rde_aspath *a, struct rde_community *c,
22153372d18Sclaudio     struct bgpd_addr *nexthop, int v2)
2227f9525e9Sclaudio {
2237f9525e9Sclaudio 	struct attr	*oa;
224355a6982Sclaudio 	u_char		*pdata;
22539386878Sclaudio 	uint32_t	 tmp;
226355a6982Sclaudio 	int		 neednewpath = 0;
22739386878Sclaudio 	uint16_t	 plen, afi;
22839386878Sclaudio 	uint8_t		 l, safi;
2297f9525e9Sclaudio 
2307f9525e9Sclaudio 	/* origin */
231355a6982Sclaudio 	if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_ORIGIN,
232355a6982Sclaudio 	    &a->origin, 1) == -1)
2337f9525e9Sclaudio 		return (-1);
2347f9525e9Sclaudio 
2357f9525e9Sclaudio 	/* aspath */
2363e168e58Sclaudio 	plen = aspath_length(a->aspath);
2373e168e58Sclaudio 	pdata = aspath_dump(a->aspath);
2383e168e58Sclaudio 
239566a7707Sclaudio 	if (!v2)
240355a6982Sclaudio 		pdata = aspath_deflate(pdata, &plen, &neednewpath);
241a5190e44Sclaudio 	if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_ASPATH, pdata,
242a5190e44Sclaudio 	    plen) == -1) {
2433e168e58Sclaudio 		if (!v2)
244a5190e44Sclaudio 			free(pdata);
2457f9525e9Sclaudio 		return (-1);
246a5190e44Sclaudio 	}
2473e168e58Sclaudio 	if (!v2)
248355a6982Sclaudio 		free(pdata);
2497f9525e9Sclaudio 
250a5190e44Sclaudio 	if (nexthop && nexthop->aid == AID_INET) {
2517f9525e9Sclaudio 		/* nexthop, already network byte order */
252355a6982Sclaudio 		if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_NEXTHOP,
253355a6982Sclaudio 		    &nexthop->v4.s_addr, 4) ==	-1)
2547f9525e9Sclaudio 			return (-1);
255dfafe578Sclaudio 	}
2567f9525e9Sclaudio 
2577f9525e9Sclaudio 	/* MED, non transitive */
2587f9525e9Sclaudio 	if (a->med != 0) {
259355a6982Sclaudio 		tmp = htonl(a->med);
260355a6982Sclaudio 		if (attr_writebuf(buf, ATTR_OPTIONAL, ATTR_MED, &tmp, 4) == -1)
2617f9525e9Sclaudio 			return (-1);
2627f9525e9Sclaudio 	}
2637f9525e9Sclaudio 
264566a7707Sclaudio 	/* local preference */
265355a6982Sclaudio 	tmp = htonl(a->lpref);
266355a6982Sclaudio 	if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_LOCALPREF, &tmp, 4) == -1)
2677f9525e9Sclaudio 		return (-1);
2687f9525e9Sclaudio 
26953372d18Sclaudio 	/* communities */
27066b1afa0Sclaudio 	if (community_writebuf(c, ATTR_COMMUNITIES, 0, buf) == -1 ||
27166b1afa0Sclaudio 	    community_writebuf(c, ATTR_EXT_COMMUNITIES, 0, buf) == -1 ||
27266b1afa0Sclaudio 	    community_writebuf(c, ATTR_LARGE_COMMUNITIES, 0, buf) == -1)
27353372d18Sclaudio 		return (-1);
27453372d18Sclaudio 
2757f9525e9Sclaudio 	/* dump all other path attributes without modification */
27655e823c7Sclaudio 	for (l = 0; l < a->others_len; l++) {
27755e823c7Sclaudio 		if ((oa = a->others[l]) == NULL)
27855e823c7Sclaudio 			break;
279355a6982Sclaudio 		if (attr_writebuf(buf, oa->flags, oa->type,
280355a6982Sclaudio 		    oa->data, oa->len) == -1)
2817f9525e9Sclaudio 			return (-1);
2827f9525e9Sclaudio 	}
2837f9525e9Sclaudio 
284a5190e44Sclaudio 	if (nexthop && nexthop->aid != AID_INET) {
285566a7707Sclaudio 		struct ibuf *nhbuf;
286566a7707Sclaudio 
287566a7707Sclaudio 		if ((nhbuf = ibuf_dynamic(0, UCHAR_MAX)) == NULL)
288a5190e44Sclaudio 			return (-1);
289566a7707Sclaudio 		if (!v2) {
290566a7707Sclaudio 			if (aid2afi(nexthop->aid, &afi, &safi))
291e3ef2697Sclaudio 				goto fail;
292e3ef2697Sclaudio 			if (ibuf_add_n16(nhbuf, afi) == -1)
293e3ef2697Sclaudio 				goto fail;
294e3ef2697Sclaudio 			if (ibuf_add_n8(nhbuf, safi) == -1)
295e3ef2697Sclaudio 				goto fail;
296566a7707Sclaudio 		}
297566a7707Sclaudio 		switch (nexthop->aid) {
298566a7707Sclaudio 		case AID_INET6:
299e3ef2697Sclaudio 			if (ibuf_add_n8(nhbuf, sizeof(struct in6_addr)) == -1)
300e3ef2697Sclaudio 				goto fail;
301566a7707Sclaudio 			if (ibuf_add(nhbuf, &nexthop->v6,
302d5f6e828Sclaudio 			    sizeof(struct in6_addr)) == -1)
303d5f6e828Sclaudio 				goto fail;
304566a7707Sclaudio 			break;
305566a7707Sclaudio 		case AID_VPN_IPv4:
306e3ef2697Sclaudio 			if (ibuf_add_n8(nhbuf, sizeof(uint64_t) +
307e3ef2697Sclaudio 			    sizeof(struct in_addr)) == -1)
308e3ef2697Sclaudio 				goto fail;
309e3ef2697Sclaudio 			if (ibuf_add_n64(nhbuf, 0) == -1) /* set RD to 0 */
310e3ef2697Sclaudio 				goto fail;
311e3ef2697Sclaudio 			if (ibuf_add(nhbuf, &nexthop->v4,
312e3ef2697Sclaudio 			    sizeof(nexthop->v4)) == -1)
313e3ef2697Sclaudio 				goto fail;
314566a7707Sclaudio 			break;
315290f96faSdenis 		case AID_VPN_IPv6:
316e3ef2697Sclaudio 			if (ibuf_add_n8(nhbuf, sizeof(uint64_t) +
317d5f6e828Sclaudio 			    sizeof(struct in6_addr)) == -1)
318d5f6e828Sclaudio 				goto fail;
319e3ef2697Sclaudio 			if (ibuf_add_n64(nhbuf, 0) == -1) /* set RD to 0 */
320e3ef2697Sclaudio 				goto fail;
321e3ef2697Sclaudio 			if (ibuf_add(nhbuf, &nexthop->v6,
322e3ef2697Sclaudio 			    sizeof(nexthop->v6)) == -1)
323e3ef2697Sclaudio 				goto fail;
324290f96faSdenis 			break;
325566a7707Sclaudio 		}
326566a7707Sclaudio 		if (!v2)
327e3ef2697Sclaudio 			if (ibuf_add_n8(nhbuf, 0) == -1)
328e3ef2697Sclaudio 				goto fail;
329a5190e44Sclaudio 		if (attr_writebuf(buf, ATTR_OPTIONAL, ATTR_MP_REACH_NLRI,
330e3ef2697Sclaudio 		    ibuf_data(nhbuf), ibuf_size(nhbuf)) == -1) {
331566a7707Sclaudio fail:
332566a7707Sclaudio 			ibuf_free(nhbuf);
333a5190e44Sclaudio 			return (-1);
334a5190e44Sclaudio 		}
335566a7707Sclaudio 		ibuf_free(nhbuf);
336566a7707Sclaudio 	}
337a5190e44Sclaudio 
338355a6982Sclaudio 	if (neednewpath) {
339355a6982Sclaudio 		pdata = aspath_prepend(a->aspath, rde_local_as(), 0, &plen);
340355a6982Sclaudio 		if (plen != 0)
341355a6982Sclaudio 			if (attr_writebuf(buf, ATTR_OPTIONAL|ATTR_TRANSITIVE,
342a5190e44Sclaudio 			    ATTR_AS4_PATH, pdata, plen) == -1) {
343a5190e44Sclaudio 				free(pdata);
344355a6982Sclaudio 				return (-1);
345a5190e44Sclaudio 			}
346355a6982Sclaudio 		free(pdata);
347355a6982Sclaudio 	}
348355a6982Sclaudio 
349355a6982Sclaudio 	return (0);
3507f9525e9Sclaudio }
3517f9525e9Sclaudio 
352e3ef2697Sclaudio static int
35339386878Sclaudio mrt_dump_entry_mp(struct mrt *mrt, struct prefix *p, uint16_t snum,
354dfafe578Sclaudio     struct rde_peer *peer)
355dfafe578Sclaudio {
356e39620e5Snicm 	struct ibuf	*buf, *hbuf = NULL, *h2buf = NULL;
3572b6d2161Sclaudio 	struct nexthop	*n;
358de422abdSclaudio 	struct bgpd_addr nexthop, *nh;
35939386878Sclaudio 	uint16_t	 len;
36039386878Sclaudio 	uint8_t		 aid;
361dfafe578Sclaudio 
362e39620e5Snicm 	if ((buf = ibuf_dynamic(0, MAX_PKTSIZE)) == NULL) {
363027c37bdSkrw 		log_warn("mrt_dump_entry_mp: ibuf_dynamic");
364355a6982Sclaudio 		return (-1);
365355a6982Sclaudio 	}
366dfafe578Sclaudio 
36753372d18Sclaudio 	if (mrt_attr_dump(buf, prefix_aspath(p), prefix_communities(p),
368e3ef2697Sclaudio 	    NULL, 0) == -1)
369355a6982Sclaudio 		goto fail;
370e39620e5Snicm 	len = ibuf_size(buf);
371355a6982Sclaudio 
372e39620e5Snicm 	if ((h2buf = ibuf_dynamic(MRT_BGP4MP_IPv4_HEADER_SIZE +
373355a6982Sclaudio 	    MRT_BGP4MP_IPv4_ENTRY_SIZE, MRT_BGP4MP_IPv6_HEADER_SIZE +
374e3ef2697Sclaudio 	    MRT_BGP4MP_IPv6_ENTRY_SIZE + MRT_BGP4MP_MAX_PREFIXLEN)) == NULL)
375355a6982Sclaudio 		goto fail;
376355a6982Sclaudio 
377e3ef2697Sclaudio 	if (ibuf_add_n16(h2buf, peer->conf.local_short_as) == -1)
378e3ef2697Sclaudio 		goto fail;
379e3ef2697Sclaudio 	if (ibuf_add_n16(h2buf, peer->short_as) == -1)
380e3ef2697Sclaudio 		goto fail;
381e3ef2697Sclaudio 	if (ibuf_add_n16(h2buf, /* ifindex */ 0) == -1)
382e3ef2697Sclaudio 		goto fail;
383355a6982Sclaudio 
384355a6982Sclaudio 	/* XXX is this for peer self? */
385f8509b38Sclaudio 	aid = peer->remote_addr.aid == AID_UNSPEC ? p->pt->aid :
386d6c2e4e8Sclaudio 	    peer->remote_addr.aid;
387d6c2e4e8Sclaudio 	switch (aid) {
388d6c2e4e8Sclaudio 	case AID_INET:
389d5f6e828Sclaudio 	case AID_VPN_IPv4:
390e3ef2697Sclaudio 		if (ibuf_add_n16(h2buf, AFI_IPv4) == -1)
391e3ef2697Sclaudio 			goto fail;
392e3ef2697Sclaudio 		if (ibuf_add(h2buf, &peer->local_v4_addr.v4,
393e3ef2697Sclaudio 		    sizeof(peer->local_v4_addr.v4)) == -1 ||
394e3ef2697Sclaudio 		    ibuf_add(h2buf, &peer->remote_addr.v4,
395e3ef2697Sclaudio 		    sizeof(peer->remote_addr.v4)) == -1)
396e3ef2697Sclaudio 			goto fail;
397dfafe578Sclaudio 		break;
398d6c2e4e8Sclaudio 	case AID_INET6:
399d5f6e828Sclaudio 	case AID_VPN_IPv6:
400e3ef2697Sclaudio 		if (ibuf_add_n16(h2buf, AFI_IPv6) == -1)
401355a6982Sclaudio 			goto fail;
402e3ef2697Sclaudio 		if (ibuf_add(h2buf, &peer->local_v6_addr.v6,
403e3ef2697Sclaudio 		    sizeof(peer->local_v6_addr.v6)) == -1 ||
404e3ef2697Sclaudio 		    ibuf_add(h2buf, &peer->remote_addr.v6,
405e3ef2697Sclaudio 		    sizeof(peer->remote_addr.v6)) == -1)
406e3ef2697Sclaudio 			goto fail;
407dfafe578Sclaudio 		break;
408355a6982Sclaudio 	default:
409d5f6e828Sclaudio 		log_warnx("king bula found new AF %d in %s", aid, __func__);
410355a6982Sclaudio 		goto fail;
411dfafe578Sclaudio 	}
412dfafe578Sclaudio 
413e3ef2697Sclaudio 	if (ibuf_add_n16(h2buf, 0) == -1)		/* view */
414e3ef2697Sclaudio 		goto fail;
415e3ef2697Sclaudio 	if (ibuf_add_n16(h2buf, 1) == -1)		/* status */
416e3ef2697Sclaudio 		goto fail;
41703e83acfSclaudio 	/* originated timestamp */
418e3ef2697Sclaudio 	if (ibuf_add_n32(h2buf, time(NULL) - (getmonotime() -
419e3ef2697Sclaudio 	    p->lastchange)) == -1)
420e3ef2697Sclaudio 		goto fail;
421dfafe578Sclaudio 
4223447165fSclaudio 	n = prefix_nexthop(p);
4232b6d2161Sclaudio 	if (n == NULL) {
424eafe309eSclaudio 		memset(&nexthop, 0, sizeof(struct bgpd_addr));
425de422abdSclaudio 		nexthop.aid = p->pt->aid;
426dfafe578Sclaudio 		nh = &nexthop;
427dfafe578Sclaudio 	} else
4282b6d2161Sclaudio 		nh = &n->exit_nexthop;
429dfafe578Sclaudio 
430de422abdSclaudio 	switch (p->pt->aid) {
431d6c2e4e8Sclaudio 	case AID_INET:
432e3ef2697Sclaudio 		if (ibuf_add_n16(h2buf, AFI_IPv4) == -1)	/* afi */
433e3ef2697Sclaudio 			goto fail;
434e3ef2697Sclaudio 		if (ibuf_add_n8(h2buf, SAFI_UNICAST) == -1)	/* safi */
435e3ef2697Sclaudio 			goto fail;
436e3ef2697Sclaudio 		if (ibuf_add_n8(h2buf, 4) == -1)		/* nhlen */
437e3ef2697Sclaudio 			goto fail;
438e3ef2697Sclaudio 		if (ibuf_add(h2buf, &nh->v4, sizeof(nh->v4)) == -1)
439e3ef2697Sclaudio 			goto fail;
440dfafe578Sclaudio 		break;
441d6c2e4e8Sclaudio 	case AID_INET6:
442e3ef2697Sclaudio 		if (ibuf_add_n16(h2buf, AFI_IPv6) == -1)	/* afi */
443355a6982Sclaudio 			goto fail;
444e3ef2697Sclaudio 		if (ibuf_add_n8(h2buf, SAFI_UNICAST) == -1)	/* safi */
445e3ef2697Sclaudio 			goto fail;
446e3ef2697Sclaudio 		if (ibuf_add_n8(h2buf, 16) == -1)		/* nhlen */
447e3ef2697Sclaudio 			goto fail;
448e3ef2697Sclaudio 		if (ibuf_add(h2buf, &nh->v6, sizeof(nh->v6)) == -1)
449e3ef2697Sclaudio 			goto fail;
450dfafe578Sclaudio 		break;
451d5f6e828Sclaudio 	case AID_VPN_IPv4:
452e3ef2697Sclaudio 		if (ibuf_add_n16(h2buf, AFI_IPv4) == -1)	/* afi */
453e3ef2697Sclaudio 			goto fail;
454e3ef2697Sclaudio 		if (ibuf_add_n8(h2buf, SAFI_MPLSVPN) == -1)	/* safi */
455e3ef2697Sclaudio 			goto fail;
456e3ef2697Sclaudio 		if (ibuf_add_n8(h2buf, sizeof(uint64_t) +
457e3ef2697Sclaudio 		    sizeof(struct in_addr)) == -1)
458e3ef2697Sclaudio 			goto fail;
459e3ef2697Sclaudio 		if (ibuf_add_n64(h2buf, 0) == -1)	/* set RD to 0 */
460e3ef2697Sclaudio 			goto fail;
461e3ef2697Sclaudio 		if (ibuf_add(h2buf, &nh->v4, sizeof(nh->v4)) == -1)
462e3ef2697Sclaudio 			goto fail;
463d5f6e828Sclaudio 		break;
464d5f6e828Sclaudio 	case AID_VPN_IPv6:
465e3ef2697Sclaudio 		if (ibuf_add_n16(h2buf, AFI_IPv6) == -1)	/* afi */
466d5f6e828Sclaudio 			goto fail;
467e3ef2697Sclaudio 		if (ibuf_add_n8(h2buf, SAFI_MPLSVPN) == -1)	/* safi */
468e3ef2697Sclaudio 			goto fail;
469e3ef2697Sclaudio 		if (ibuf_add_n8(h2buf, sizeof(uint64_t) +
470e3ef2697Sclaudio 		    sizeof(struct in6_addr)) == -1)
471e3ef2697Sclaudio 			goto fail;
472e3ef2697Sclaudio 		if (ibuf_add_n64(h2buf, 0) == -1)	/* set RD to 0 */
473e3ef2697Sclaudio 			goto fail;
474e3ef2697Sclaudio 		if (ibuf_add(h2buf, &nh->v6, sizeof(nh->v6)) == -1)
475e3ef2697Sclaudio 			goto fail;
476d5f6e828Sclaudio 		break;
477211fe81cSclaudio 	case AID_FLOWSPECv4:
478211fe81cSclaudio 	case AID_FLOWSPECv6:
479e3ef2697Sclaudio 		if (p->pt->aid == AID_FLOWSPECv4) {
480e3ef2697Sclaudio 			if (ibuf_add_n16(h2buf, AFI_IPv4) == -1) /* afi */
481e3ef2697Sclaudio 				goto fail;
482e3ef2697Sclaudio 		} else {
483e3ef2697Sclaudio 			if (ibuf_add_n16(h2buf, AFI_IPv6) == -1) /* afi */
484e3ef2697Sclaudio 				goto fail;
485e3ef2697Sclaudio 		}
486e3ef2697Sclaudio 		if (ibuf_add_n8(h2buf, SAFI_FLOWSPEC) == -1)	/* safi */
487e3ef2697Sclaudio 			goto fail;
488e3ef2697Sclaudio 		if (ibuf_add_n8(h2buf, 0) == -1)		/* nhlen */
489e3ef2697Sclaudio 			goto fail;
490211fe81cSclaudio 		break;
491355a6982Sclaudio 	default:
492d5f6e828Sclaudio 		log_warnx("king bula found new AF in %s", __func__);
493355a6982Sclaudio 		goto fail;
494dfafe578Sclaudio 	}
495dfafe578Sclaudio 
496e3ef2697Sclaudio 	if (pt_writebuf(h2buf, p->pt, 0, 0, 0) == -1)
497355a6982Sclaudio 		goto fail;
498dfafe578Sclaudio 
499e3ef2697Sclaudio 	if (ibuf_add_n16(h2buf, len) == -1)
500e3ef2697Sclaudio 		goto fail;
501e39620e5Snicm 	len += ibuf_size(h2buf);
502dfafe578Sclaudio 
503355a6982Sclaudio 	if (mrt_dump_hdr_rde(&hbuf, MSG_PROTOCOL_BGP4MP, BGP4MP_ENTRY,
504355a6982Sclaudio 	    len) == -1)
505355a6982Sclaudio 		goto fail;
506dfafe578Sclaudio 
50705453d67Sclaudio 	ibuf_close(mrt->wbuf, hbuf);
50805453d67Sclaudio 	ibuf_close(mrt->wbuf, h2buf);
50905453d67Sclaudio 	ibuf_close(mrt->wbuf, buf);
510dfafe578Sclaudio 
511dfafe578Sclaudio 	return (len + MRT_HEADER_SIZE);
512355a6982Sclaudio 
513355a6982Sclaudio fail:
514e3ef2697Sclaudio 	log_warn("%s: ibuf error", __func__);
515e39620e5Snicm 	ibuf_free(hbuf);
516e39620e5Snicm 	ibuf_free(h2buf);
517e39620e5Snicm 	ibuf_free(buf);
518355a6982Sclaudio 	return (-1);
519dfafe578Sclaudio }
520dfafe578Sclaudio 
521e3ef2697Sclaudio static int
52239386878Sclaudio mrt_dump_entry(struct mrt *mrt, struct prefix *p, uint16_t snum,
523dfafe578Sclaudio     struct rde_peer *peer)
524a16c0992Shenning {
525e3ef2697Sclaudio 	struct ibuf	*buf, *hbuf = NULL;
5262b6d2161Sclaudio 	struct nexthop	*nexthop;
527af6b2e43Sclaudio 	struct bgpd_addr addr, *nh;
528355a6982Sclaudio 	size_t		 len;
52939386878Sclaudio 	uint16_t	 subtype;
53039386878Sclaudio 	uint8_t		 dummy;
531a16c0992Shenning 
532f8509b38Sclaudio 	if (p->pt->aid != peer->remote_addr.aid &&
533f8509b38Sclaudio 	    p->pt->aid != AID_INET && p->pt->aid != AID_INET6)
534a5190e44Sclaudio 		/* only able to dump pure IPv4/IPv6 */
535dfafe578Sclaudio 		return (0);
536dfafe578Sclaudio 
537e39620e5Snicm 	if ((buf = ibuf_dynamic(0, MAX_PKTSIZE)) == NULL) {
538027c37bdSkrw 		log_warn("mrt_dump_entry: ibuf_dynamic");
5392a51171bSclaudio 		return (-1);
5402a51171bSclaudio 	}
541a16c0992Shenning 
5423447165fSclaudio 	nexthop = prefix_nexthop(p);
5432b6d2161Sclaudio 	if (nexthop == NULL) {
544eafe309eSclaudio 		memset(&addr, 0, sizeof(struct bgpd_addr));
545f8509b38Sclaudio 		addr.aid = p->pt->aid;
546af6b2e43Sclaudio 		nh = &addr;
547af6b2e43Sclaudio 	} else
5482b6d2161Sclaudio 		nh = &nexthop->exit_nexthop;
54953372d18Sclaudio 	if (mrt_attr_dump(buf, prefix_aspath(p), prefix_communities(p),
550e3ef2697Sclaudio 	    nh, 0) == -1)
551e3ef2697Sclaudio 		goto fail;
552e3ef2697Sclaudio 
553e39620e5Snicm 	len = ibuf_size(buf);
554f8509b38Sclaudio 	aid2afi(p->pt->aid, &subtype, &dummy);
555e3ef2697Sclaudio 	if (mrt_dump_hdr_rde(&hbuf, MSG_TABLE_DUMP, subtype, len) == -1)
556e3ef2697Sclaudio 		goto fail;
557355a6982Sclaudio 
558e3ef2697Sclaudio 	if (ibuf_add_n16(hbuf, 0) == -1)
559e3ef2697Sclaudio 		goto fail;
560e3ef2697Sclaudio 	if (ibuf_add_n16(hbuf, snum) == -1)
561e3ef2697Sclaudio 		goto fail;
562355a6982Sclaudio 
563f8509b38Sclaudio 	pt_getaddr(p->pt, &addr);
564f8509b38Sclaudio 	switch (p->pt->aid) {
565a5190e44Sclaudio 	case AID_INET:
566e3ef2697Sclaudio 		if (ibuf_add(hbuf, &addr.v4, sizeof(addr.v4)) == -1)
567e3ef2697Sclaudio 			goto fail;
568a5190e44Sclaudio 		break;
569a5190e44Sclaudio 	case AID_INET6:
570e3ef2697Sclaudio 		if (ibuf_add(hbuf, &addr.v6, sizeof(addr.v6)) == -1)
571a5190e44Sclaudio 			goto fail;
572a5190e44Sclaudio 		break;
573a5190e44Sclaudio 	}
574e3ef2697Sclaudio 	if (ibuf_add_n8(hbuf, p->pt->prefixlen) == -1)
575e3ef2697Sclaudio 		goto fail;
576355a6982Sclaudio 
577e3ef2697Sclaudio 	if (ibuf_add_n8(hbuf, 1) == -1)		/* state */
578e3ef2697Sclaudio 		goto fail;
57903e83acfSclaudio 	/* originated timestamp */
580e3ef2697Sclaudio 	if (ibuf_add_n32(hbuf, time(NULL) - (getmonotime() -
581e3ef2697Sclaudio 	    p->lastchange)) == -1)
582e3ef2697Sclaudio 		goto fail;
583f8509b38Sclaudio 	switch (p->pt->aid) {
584a5190e44Sclaudio 	case AID_INET:
585e3ef2697Sclaudio 		if (ibuf_add(hbuf, &peer->remote_addr.v4,
586e3ef2697Sclaudio 		    sizeof(peer->remote_addr.v4)) == -1)
587e3ef2697Sclaudio 			goto fail;
588a5190e44Sclaudio 		break;
589a5190e44Sclaudio 	case AID_INET6:
590a5190e44Sclaudio 		if (ibuf_add(hbuf, &peer->remote_addr.v6,
591e3ef2697Sclaudio 		    sizeof(peer->remote_addr.v6)) == -1)
592a5190e44Sclaudio 			goto fail;
593a5190e44Sclaudio 		break;
594a5190e44Sclaudio 	}
595e3ef2697Sclaudio 	if (ibuf_add_n16(hbuf, peer->short_as) == -1)
596e3ef2697Sclaudio 		goto fail;
597e3ef2697Sclaudio 	if (ibuf_add_n16(hbuf, len) == -1)
598e3ef2697Sclaudio 		goto fail;
599355a6982Sclaudio 
60005453d67Sclaudio 	ibuf_close(mrt->wbuf, hbuf);
60105453d67Sclaudio 	ibuf_close(mrt->wbuf, buf);
602a16c0992Shenning 
603df24a79cSclaudio 	return (len + MRT_HEADER_SIZE);
604355a6982Sclaudio 
605355a6982Sclaudio fail:
606e3ef2697Sclaudio 	log_warn("%s: ibuf error", __func__);
607e39620e5Snicm 	ibuf_free(hbuf);
608e39620e5Snicm 	ibuf_free(buf);
609355a6982Sclaudio 	return (-1);
610a16c0992Shenning }
611a16c0992Shenning 
61236afba5eSclaudio static int
61336afba5eSclaudio mrt_dump_entry_v2_rib(struct rib_entry *re, struct ibuf **nb, struct ibuf **apb,
61436afba5eSclaudio     uint16_t *np, uint16_t *app)
615566a7707Sclaudio {
616566a7707Sclaudio 	struct bgpd_addr addr;
617e3ef2697Sclaudio 	struct ibuf *buf = NULL, **bp;
618e3ef2697Sclaudio 	struct ibuf *tbuf = NULL;
61936afba5eSclaudio 	struct prefix *p;
62036afba5eSclaudio 	int addpath;
621566a7707Sclaudio 
62236afba5eSclaudio 	*np = 0;
62336afba5eSclaudio 	*app = 0;
624566a7707Sclaudio 
625df08e9a0Sclaudio 	TAILQ_FOREACH(p, &re->prefix_h, entry.list.rib) {
6262b6d2161Sclaudio 		struct nexthop		*nexthop;
627566a7707Sclaudio 		struct bgpd_addr	*nh;
628566a7707Sclaudio 
62936afba5eSclaudio 		addpath = peer_has_add_path(prefix_peer(p), re->prefix->aid,
63036afba5eSclaudio 		    CAPA_AP_RECV);
63136afba5eSclaudio 
63236afba5eSclaudio 		if (addpath) {
63336afba5eSclaudio 			bp = apb;
63436afba5eSclaudio 			*app += 1;
63536afba5eSclaudio 		} else {
63636afba5eSclaudio 			bp = nb;
63736afba5eSclaudio 			*np += 1;
63836afba5eSclaudio 		}
63936afba5eSclaudio 		if ((buf = *bp) == NULL) {
640e3ef2697Sclaudio 			if ((buf = ibuf_dynamic(0, UINT_MAX)) == NULL)
64136afba5eSclaudio 				goto fail;
64236afba5eSclaudio 			*bp = buf;
64336afba5eSclaudio 		}
64436afba5eSclaudio 
6453447165fSclaudio 		nexthop = prefix_nexthop(p);
6462b6d2161Sclaudio 		if (nexthop == NULL) {
647eafe309eSclaudio 			memset(&addr, 0, sizeof(struct bgpd_addr));
6482b6d2161Sclaudio 			addr.aid = re->prefix->aid;
649566a7707Sclaudio 			nh = &addr;
650566a7707Sclaudio 		} else
6512b6d2161Sclaudio 			nh = &nexthop->exit_nexthop;
652566a7707Sclaudio 
653e3ef2697Sclaudio 		if (ibuf_add_n16(buf, prefix_peer(p)->mrt_idx) == -1)
654e3ef2697Sclaudio 			goto fail;
65503e83acfSclaudio 		/* originated timestamp */
656e3ef2697Sclaudio 		if (ibuf_add_n32(buf, time(NULL) - (getmonotime() -
657e3ef2697Sclaudio 		    p->lastchange)) == -1)
658e3ef2697Sclaudio 			goto fail;
659566a7707Sclaudio 
66036afba5eSclaudio 		/* RFC8050: path-id if add-path is used */
66136afba5eSclaudio 		if (addpath)
662e3ef2697Sclaudio 			if (ibuf_add_n32(buf, p->path_id) == -1)
663e3ef2697Sclaudio 				goto fail;
66436afba5eSclaudio 
665e3ef2697Sclaudio 		if ((tbuf = ibuf_dynamic(0, MAX_PKTSIZE)) == NULL)
666d5f6e828Sclaudio 			goto fail;
66753372d18Sclaudio 		if (mrt_attr_dump(tbuf, prefix_aspath(p), prefix_communities(p),
668e3ef2697Sclaudio 		    nh, 1) == -1)
669d5f6e828Sclaudio 			goto fail;
670e3ef2697Sclaudio 		if (ibuf_add_n16(buf, ibuf_size(tbuf)) == -1)
671d5f6e828Sclaudio 			goto fail;
672fa353a8fSclaudio 		if (ibuf_add_ibuf(buf, tbuf) == -1)
673e3ef2697Sclaudio 			goto fail;
674566a7707Sclaudio 		ibuf_free(tbuf);
675e3ef2697Sclaudio 		tbuf = NULL;
676566a7707Sclaudio 	}
677566a7707Sclaudio 
67836afba5eSclaudio 	return 0;
67936afba5eSclaudio 
68036afba5eSclaudio fail:
681e3ef2697Sclaudio 	ibuf_free(tbuf);
68236afba5eSclaudio 	return -1;
683566a7707Sclaudio }
684566a7707Sclaudio 
685e3ef2697Sclaudio static int
68639386878Sclaudio mrt_dump_entry_v2(struct mrt *mrt, struct rib_entry *re, uint32_t snum)
68736afba5eSclaudio {
688273a836cSclaudio 	struct ibuf	*hbuf = NULL, *nbuf = NULL, *apbuf = NULL, *pbuf;
68936afba5eSclaudio 	size_t		 hlen, len;
69039386878Sclaudio 	uint16_t	 subtype, apsubtype, nump, apnump, afi;
69139386878Sclaudio 	uint8_t		 safi;
69236afba5eSclaudio 
693273a836cSclaudio 	if ((pbuf = ibuf_dynamic(0, UINT_MAX)) == NULL) {
694273a836cSclaudio 		log_warn("%s: ibuf_dynamic", __func__);
69536afba5eSclaudio 		return -1;
69636afba5eSclaudio 	}
69736afba5eSclaudio 
69836afba5eSclaudio 	switch (re->prefix->aid) {
69936afba5eSclaudio 	case AID_INET:
70036afba5eSclaudio 		subtype = MRT_DUMP_V2_RIB_IPV4_UNICAST;
70136afba5eSclaudio 		apsubtype = MRT_DUMP_V2_RIB_IPV4_UNICAST_ADDPATH;
70236afba5eSclaudio 		break;
70336afba5eSclaudio 	case AID_INET6:
70436afba5eSclaudio 		subtype = MRT_DUMP_V2_RIB_IPV6_UNICAST;
70536afba5eSclaudio 		apsubtype = MRT_DUMP_V2_RIB_IPV6_UNICAST_ADDPATH;
70636afba5eSclaudio 		break;
70736afba5eSclaudio 	default:
70836afba5eSclaudio 		/*
70936afba5eSclaudio 		 * XXX The RFC defined the format for this type differently
71036afba5eSclaudio 		 * and it is prohibitly expensive to implement that format.
71136afba5eSclaudio 		 * Instead do what gobgp does and encode it like the other
71236afba5eSclaudio 		 * types.
71336afba5eSclaudio 		 */
71436afba5eSclaudio 		subtype = MRT_DUMP_V2_RIB_GENERIC;
71536afba5eSclaudio 		apsubtype = MRT_DUMP_V2_RIB_GENERIC_ADDPATH;
71636afba5eSclaudio 		aid2afi(re->prefix->aid, &afi, &safi);
71736afba5eSclaudio 
718273a836cSclaudio 		/* first add 3-bytes AFI/SAFI */
719e3ef2697Sclaudio 		if (ibuf_add_n16(pbuf, afi) == -1)
720e3ef2697Sclaudio 			goto fail;
721e3ef2697Sclaudio 		if (ibuf_add_n8(pbuf, safi) == -1)
722e3ef2697Sclaudio 			goto fail;
72336afba5eSclaudio 		break;
72436afba5eSclaudio 	}
725273a836cSclaudio 
726e3ef2697Sclaudio 	if (pt_writebuf(pbuf, re->prefix, 0, 0, 0) == -1)
727273a836cSclaudio 		goto fail;
728273a836cSclaudio 
729273a836cSclaudio 	hlen = sizeof(snum) + sizeof(nump) + ibuf_size(pbuf);
73036afba5eSclaudio 
73136afba5eSclaudio 	if (mrt_dump_entry_v2_rib(re, &nbuf, &apbuf, &nump, &apnump))
73236afba5eSclaudio 		goto fail;
73336afba5eSclaudio 
73436afba5eSclaudio 	if (nump > 0) {
73536afba5eSclaudio 		len = ibuf_size(nbuf) + hlen;
73636afba5eSclaudio 		if (mrt_dump_hdr_rde(&hbuf, MSG_TABLE_DUMP_V2, subtype,
73736afba5eSclaudio 		    len) == -1)
73836afba5eSclaudio 			goto fail;
73936afba5eSclaudio 
740e3ef2697Sclaudio 		if (ibuf_add_n32(hbuf, snum) == -1)
74136afba5eSclaudio 			goto fail;
742fa353a8fSclaudio 		if (ibuf_add_ibuf(hbuf, pbuf) == -1)
743e3ef2697Sclaudio 			goto fail;
744e3ef2697Sclaudio 		if (ibuf_add_n16(hbuf, nump) == -1)
745e3ef2697Sclaudio 			goto fail;
74636afba5eSclaudio 
74705453d67Sclaudio 		ibuf_close(mrt->wbuf, hbuf);
74805453d67Sclaudio 		ibuf_close(mrt->wbuf, nbuf);
74936afba5eSclaudio 		hbuf = NULL;
75036afba5eSclaudio 		nbuf = NULL;
75136afba5eSclaudio 	}
75236afba5eSclaudio 
75336afba5eSclaudio 	if (apnump > 0) {
75436afba5eSclaudio 		len = ibuf_size(apbuf) + hlen;
75536afba5eSclaudio 		if (mrt_dump_hdr_rde(&hbuf, MSG_TABLE_DUMP_V2, apsubtype,
75636afba5eSclaudio 		    len) == -1)
75736afba5eSclaudio 			goto fail;
75836afba5eSclaudio 
759e3ef2697Sclaudio 		if (ibuf_add_n32(hbuf, snum) == -1)
76036afba5eSclaudio 			goto fail;
761fa353a8fSclaudio 		if (ibuf_add_ibuf(hbuf, pbuf) == -1)
762e3ef2697Sclaudio 			goto fail;
763e3ef2697Sclaudio 		if (ibuf_add_n16(hbuf, apnump) == -1)
764e3ef2697Sclaudio 			goto fail;
76536afba5eSclaudio 
76605453d67Sclaudio 		ibuf_close(mrt->wbuf, hbuf);
76705453d67Sclaudio 		ibuf_close(mrt->wbuf, apbuf);
76836afba5eSclaudio 		hbuf = NULL;
76936afba5eSclaudio 		apbuf = NULL;
77036afba5eSclaudio 	}
771566a7707Sclaudio 
772273a836cSclaudio 	ibuf_free(pbuf);
773566a7707Sclaudio 	return (0);
774566a7707Sclaudio fail:
775e3ef2697Sclaudio 	log_warn("%s: ibuf error", __func__);
77636afba5eSclaudio 	ibuf_free(apbuf);
77736afba5eSclaudio 	ibuf_free(nbuf);
778566a7707Sclaudio 	ibuf_free(hbuf);
779273a836cSclaudio 	ibuf_free(pbuf);
780566a7707Sclaudio 	return (-1);
781566a7707Sclaudio }
782566a7707Sclaudio 
783dcbb4522Sclaudio struct cb_arg {
784dcbb4522Sclaudio 	struct ibuf	*buf;
785dcbb4522Sclaudio 	int		 nump;
786dcbb4522Sclaudio };
787dcbb4522Sclaudio 
788dcbb4522Sclaudio static void
789dcbb4522Sclaudio mrt_dump_v2_hdr_peer(struct rde_peer *peer, void *arg)
790566a7707Sclaudio {
791dcbb4522Sclaudio 	struct cb_arg *a = arg;
792dcbb4522Sclaudio 
793dcbb4522Sclaudio 	if (a->nump == -1)
794dcbb4522Sclaudio 		return;
795dcbb4522Sclaudio 	peer->mrt_idx = a->nump;
796dcbb4522Sclaudio 	if (mrt_dump_peer(a->buf, peer) == -1) {
797dcbb4522Sclaudio 		a->nump = -1;
798dcbb4522Sclaudio 		return;
799dcbb4522Sclaudio 	}
800dcbb4522Sclaudio 	a->nump++;
801dcbb4522Sclaudio }
802dcbb4522Sclaudio 
803dcbb4522Sclaudio int
804dcbb4522Sclaudio mrt_dump_v2_hdr(struct mrt *mrt, struct bgpd_config *conf)
805dcbb4522Sclaudio {
806566a7707Sclaudio 	struct ibuf	*buf, *hbuf = NULL;
807566a7707Sclaudio 	size_t		 len, off;
80839386878Sclaudio 	uint16_t	 nlen, nump;
809dcbb4522Sclaudio 	struct cb_arg	 arg;
810566a7707Sclaudio 
811566a7707Sclaudio 	if ((buf = ibuf_dynamic(0, UINT_MAX)) == NULL) {
81275f8cafaSbenno 		log_warn("%s: ibuf_dynamic", __func__);
813566a7707Sclaudio 		return (-1);
814566a7707Sclaudio 	}
815566a7707Sclaudio 
816bcd6516bSclaudio 	if (ibuf_add_n32(buf, conf->bgpid) == -1)
817e3ef2697Sclaudio 		goto fail;
818566a7707Sclaudio 	nlen = strlen(mrt->rib);
819566a7707Sclaudio 	if (nlen > 0)
820566a7707Sclaudio 		nlen += 1;
821e3ef2697Sclaudio 	if (ibuf_add_n16(buf, nlen) == -1)
822566a7707Sclaudio 		goto fail;
823e3ef2697Sclaudio 	if (ibuf_add(buf, mrt->rib, nlen) == -1)
824e3ef2697Sclaudio 		goto fail;
825566a7707Sclaudio 
826566a7707Sclaudio 	off = ibuf_size(buf);
827e3ef2697Sclaudio 	if (ibuf_add_zero(buf, sizeof(nump)) == -1)
828566a7707Sclaudio 		goto fail;
829dcbb4522Sclaudio 	arg.nump = 0;
830dcbb4522Sclaudio 	arg.buf = buf;
831dcbb4522Sclaudio 	peer_foreach(mrt_dump_v2_hdr_peer, &arg);
832dcbb4522Sclaudio 	if (arg.nump == -1)
833566a7707Sclaudio 		goto fail;
834dcbb4522Sclaudio 
835e3ef2697Sclaudio 	if (ibuf_set_n16(buf, off, arg.nump) == -1)
83666b1afa0Sclaudio 		goto fail;
837566a7707Sclaudio 
838566a7707Sclaudio 	len = ibuf_size(buf);
839566a7707Sclaudio 	if (mrt_dump_hdr_rde(&hbuf, MSG_TABLE_DUMP_V2,
840566a7707Sclaudio 	    MRT_DUMP_V2_PEER_INDEX_TABLE, len) == -1)
841566a7707Sclaudio 		goto fail;
842566a7707Sclaudio 
84305453d67Sclaudio 	ibuf_close(mrt->wbuf, hbuf);
84405453d67Sclaudio 	ibuf_close(mrt->wbuf, buf);
845566a7707Sclaudio 
846566a7707Sclaudio 	return (0);
847566a7707Sclaudio fail:
848e3ef2697Sclaudio 	log_warn("%s: ibuf error", __func__);
849566a7707Sclaudio 	ibuf_free(hbuf);
850566a7707Sclaudio 	ibuf_free(buf);
851566a7707Sclaudio 	return (-1);
852566a7707Sclaudio }
853566a7707Sclaudio 
854e3ef2697Sclaudio static int
855566a7707Sclaudio mrt_dump_peer(struct ibuf *buf, struct rde_peer *peer)
856566a7707Sclaudio {
85739386878Sclaudio 	uint8_t	type = 0;
858566a7707Sclaudio 
859566a7707Sclaudio 	if (peer->capa.as4byte)
860566a7707Sclaudio 		type |= MRT_DUMP_V2_PEER_BIT_A;
861566a7707Sclaudio 	if (peer->remote_addr.aid == AID_INET6)
862566a7707Sclaudio 		type |= MRT_DUMP_V2_PEER_BIT_I;
863566a7707Sclaudio 
864e3ef2697Sclaudio 	if (ibuf_add_n8(buf, type) == -1)
865e3ef2697Sclaudio 		goto fail;
866e3ef2697Sclaudio 	if (ibuf_add_n32(buf, peer->remote_bgpid) == -1)
867e3ef2697Sclaudio 		goto fail;
868566a7707Sclaudio 
869566a7707Sclaudio 	switch (peer->remote_addr.aid) {
870566a7707Sclaudio 	case AID_INET:
871e3ef2697Sclaudio 		if (ibuf_add(buf, &peer->remote_addr.v4,
872e3ef2697Sclaudio 		    sizeof(peer->remote_addr.v4)) == -1)
873e3ef2697Sclaudio 			goto fail;
874566a7707Sclaudio 		break;
875566a7707Sclaudio 	case AID_INET6:
876566a7707Sclaudio 		if (ibuf_add(buf, &peer->remote_addr.v6,
877e3ef2697Sclaudio 		    sizeof(peer->remote_addr.v6)) == -1)
878566a7707Sclaudio 			goto fail;
879566a7707Sclaudio 		break;
88053372d18Sclaudio 	case AID_UNSPEC: /* XXX special handling for peerself? */
881e3ef2697Sclaudio 		if (ibuf_add_n32(buf, 0) == -1)
882e3ef2697Sclaudio 			goto fail;
883566a7707Sclaudio 		break;
884566a7707Sclaudio 	default:
885d5f6e828Sclaudio 		log_warnx("king bula found new AF in %s", __func__);
886566a7707Sclaudio 		goto fail;
887566a7707Sclaudio 	}
888566a7707Sclaudio 
889e3ef2697Sclaudio 	if (peer->capa.as4byte) {
890e3ef2697Sclaudio 		if (ibuf_add_n32(buf, peer->conf.remote_as) == -1)
891e3ef2697Sclaudio 			goto fail;
892e3ef2697Sclaudio 	} else {
893e3ef2697Sclaudio 		if (ibuf_add_n16(buf, peer->short_as) == -1)
894e3ef2697Sclaudio 			goto fail;
895e3ef2697Sclaudio 	}
896566a7707Sclaudio 	return (0);
897566a7707Sclaudio fail:
898e3ef2697Sclaudio 	log_warn("%s: ibuf error", __func__);
899566a7707Sclaudio 	return (-1);
900566a7707Sclaudio }
901566a7707Sclaudio 
902a16c0992Shenning void
90386f6dc6eSclaudio mrt_dump_upcall(struct rib_entry *re, void *ptr)
904a16c0992Shenning {
9053ac41105Sclaudio 	struct mrt		*mrtbuf = ptr;
906a16c0992Shenning 	struct prefix		*p;
907a16c0992Shenning 
908566a7707Sclaudio 	if (mrtbuf->type == MRT_TABLE_DUMP_V2) {
909566a7707Sclaudio 		mrt_dump_entry_v2(mrtbuf, re, mrtbuf->seqnum++);
910566a7707Sclaudio 		return;
911566a7707Sclaudio 	}
912566a7707Sclaudio 
913a16c0992Shenning 	/*
914a16c0992Shenning 	 * dump all prefixes even the inactive ones. That is the way zebra
915a16c0992Shenning 	 * dumps the table so we do the same. If only the active route should
916a16c0992Shenning 	 * be dumped p should be set to p = pt->active.
917a16c0992Shenning 	 */
918df08e9a0Sclaudio 	TAILQ_FOREACH(p, &re->prefix_h, entry.list.rib) {
919dfafe578Sclaudio 		if (mrtbuf->type == MRT_TABLE_DUMP)
920308f58e8Sclaudio 			mrt_dump_entry(mrtbuf, p, mrtbuf->seqnum++,
9212b6d2161Sclaudio 			    prefix_peer(p));
922dfafe578Sclaudio 		else
923308f58e8Sclaudio 			mrt_dump_entry_mp(mrtbuf, p, mrtbuf->seqnum++,
9242b6d2161Sclaudio 			    prefix_peer(p));
925a16c0992Shenning 	}
9260662b1acSclaudio }
927a16c0992Shenning 
928308f58e8Sclaudio void
929bb8b30dfSclaudio mrt_done(struct mrt *mrtbuf)
930308f58e8Sclaudio {
931db27a85bSclaudio 	mrtbuf->state = MRT_STATE_REMOVE;
932308f58e8Sclaudio }
933308f58e8Sclaudio 
934e3ef2697Sclaudio static int
93539386878Sclaudio mrt_dump_hdr_se(struct ibuf ** bp, struct peer *peer, uint16_t type,
93639386878Sclaudio     uint16_t subtype, uint32_t len, int swap)
937355a6982Sclaudio {
938933383cdSclaudio 	struct timespec	time;
939355a6982Sclaudio 
940933383cdSclaudio 	if ((*bp = ibuf_dynamic(MRT_ET_HEADER_SIZE, MRT_ET_HEADER_SIZE +
941e3ef2697Sclaudio 	    MRT_BGP4MP_AS4_IPv6_HEADER_SIZE + len)) == NULL)
942355a6982Sclaudio 		return (-1);
943355a6982Sclaudio 
944933383cdSclaudio 	clock_gettime(CLOCK_REALTIME, &time);
945355a6982Sclaudio 
946e3ef2697Sclaudio 	if (ibuf_add_n32(*bp, time.tv_sec) == -1)
947e3ef2697Sclaudio 		goto fail;
948e3ef2697Sclaudio 	if (ibuf_add_n16(*bp, type) == -1)
949e3ef2697Sclaudio 		goto fail;
950e3ef2697Sclaudio 	if (ibuf_add_n16(*bp, subtype) == -1)
951e3ef2697Sclaudio 		goto fail;
952355a6982Sclaudio 
953a27d9e33Sclaudio 	switch (peer->local.aid) {
954a27d9e33Sclaudio 	case AID_INET:
955355a6982Sclaudio 		if (subtype == BGP4MP_STATE_CHANGE_AS4 ||
95636afba5eSclaudio 		    subtype == BGP4MP_MESSAGE_AS4 ||
95736afba5eSclaudio 		    subtype == BGP4MP_MESSAGE_AS4_ADDPATH)
958933383cdSclaudio 			len += MRT_BGP4MP_ET_AS4_IPv4_HEADER_SIZE;
959355a6982Sclaudio 		else
960933383cdSclaudio 			len += MRT_BGP4MP_ET_IPv4_HEADER_SIZE;
961355a6982Sclaudio 		break;
962a27d9e33Sclaudio 	case AID_INET6:
963355a6982Sclaudio 		if (subtype == BGP4MP_STATE_CHANGE_AS4 ||
96436afba5eSclaudio 		    subtype == BGP4MP_MESSAGE_AS4 ||
96536afba5eSclaudio 		    subtype == BGP4MP_MESSAGE_AS4_ADDPATH)
966933383cdSclaudio 			len += MRT_BGP4MP_ET_AS4_IPv6_HEADER_SIZE;
967355a6982Sclaudio 		else
968933383cdSclaudio 			len += MRT_BGP4MP_ET_IPv6_HEADER_SIZE;
969355a6982Sclaudio 		break;
970355a6982Sclaudio 	case 0:
971355a6982Sclaudio 		goto fail;
972355a6982Sclaudio 	default:
973d5f6e828Sclaudio 		log_warnx("king bula found new AF in %s", __func__);
974355a6982Sclaudio 		goto fail;
975355a6982Sclaudio 	}
976355a6982Sclaudio 
977e3ef2697Sclaudio 	if (ibuf_add_n32(*bp, len) == -1)
978e3ef2697Sclaudio 		goto fail;
9793a50f0a9Sjmc 	/* millisecond field use by the _ET format */
980e3ef2697Sclaudio 	if (ibuf_add_n32(*bp, time.tv_nsec / 1000) == -1)
981e3ef2697Sclaudio 		goto fail;
982355a6982Sclaudio 
983355a6982Sclaudio 	if (subtype == BGP4MP_STATE_CHANGE_AS4 ||
98436afba5eSclaudio 	    subtype == BGP4MP_MESSAGE_AS4 ||
98536afba5eSclaudio 	    subtype == BGP4MP_MESSAGE_AS4_ADDPATH) {
986355a6982Sclaudio 		if (!swap)
987e3ef2697Sclaudio 			if (ibuf_add_n32(*bp, peer->conf.local_as) == -1)
988e3ef2697Sclaudio 				goto fail;
989e3ef2697Sclaudio 		if (ibuf_add_n32(*bp, peer->conf.remote_as) == -1)
990e3ef2697Sclaudio 			goto fail;
991355a6982Sclaudio 		if (swap)
992e3ef2697Sclaudio 			if (ibuf_add_n32(*bp, peer->conf.local_as) == -1)
993e3ef2697Sclaudio 				goto fail;
994355a6982Sclaudio 	} else {
995355a6982Sclaudio 		if (!swap)
996e3ef2697Sclaudio 			if (ibuf_add_n16(*bp, peer->conf.local_short_as) == -1)
997e3ef2697Sclaudio 				goto fail;
998e3ef2697Sclaudio 		if (ibuf_add_n16(*bp, peer->short_as) == -1)
999e3ef2697Sclaudio 			goto fail;
1000355a6982Sclaudio 		if (swap)
1001e3ef2697Sclaudio 			if (ibuf_add_n16(*bp, peer->conf.local_short_as) == -1)
1002e3ef2697Sclaudio 				goto fail;
1003355a6982Sclaudio 	}
1004355a6982Sclaudio 
1005e3ef2697Sclaudio 	if (ibuf_add_n16(*bp, /* ifindex */ 0) == -1)
1006e3ef2697Sclaudio 		goto fail;
1007355a6982Sclaudio 
1008a27d9e33Sclaudio 	switch (peer->local.aid) {
1009a27d9e33Sclaudio 	case AID_INET:
1010e3ef2697Sclaudio 		if (ibuf_add_n16(*bp, AFI_IPv4) == -1)
1011e3ef2697Sclaudio 			goto fail;
1012355a6982Sclaudio 		if (!swap)
1013e3ef2697Sclaudio 			if (ibuf_add(*bp, &peer->local.v4,
1014e3ef2697Sclaudio 			    sizeof(peer->local.v4)) == -1)
1015e3ef2697Sclaudio 				goto fail;
1016e3ef2697Sclaudio 		if (ibuf_add(*bp, &peer->remote.v4,
1017e3ef2697Sclaudio 		    sizeof(peer->remote.v4)) == -1)
1018e3ef2697Sclaudio 			goto fail;
1019355a6982Sclaudio 		if (swap)
1020e3ef2697Sclaudio 			if (ibuf_add(*bp, &peer->local.v4,
1021e3ef2697Sclaudio 			    sizeof(peer->local.v4)) == -1)
1022e3ef2697Sclaudio 				goto fail;
1023355a6982Sclaudio 		break;
1024a27d9e33Sclaudio 	case AID_INET6:
1025e3ef2697Sclaudio 		if (ibuf_add_n16(*bp, AFI_IPv6) == -1)
1026e3ef2697Sclaudio 			goto fail;
1027355a6982Sclaudio 		if (!swap)
1028a27d9e33Sclaudio 			if (ibuf_add(*bp, &peer->local.v6,
1029e3ef2697Sclaudio 			    sizeof(peer->local.v6)) == -1)
1030355a6982Sclaudio 				goto fail;
1031a27d9e33Sclaudio 		if (ibuf_add(*bp, &peer->remote.v6,
1032e3ef2697Sclaudio 		    sizeof(peer->remote.v6)) == -1)
1033355a6982Sclaudio 			goto fail;
1034355a6982Sclaudio 		if (swap)
1035a27d9e33Sclaudio 			if (ibuf_add(*bp, &peer->local.v6,
1036e3ef2697Sclaudio 			    sizeof(peer->local.v6)) == -1)
1037355a6982Sclaudio 				goto fail;
1038355a6982Sclaudio 		break;
1039355a6982Sclaudio 	}
1040355a6982Sclaudio 
1041355a6982Sclaudio 	return (0);
1042355a6982Sclaudio 
1043355a6982Sclaudio fail:
1044e39620e5Snicm 	ibuf_free(*bp);
1045e3ef2697Sclaudio 	*bp = NULL;
1046355a6982Sclaudio 	return (-1);
1047355a6982Sclaudio }
1048355a6982Sclaudio 
104997448f4fSclaudio int
105039386878Sclaudio mrt_dump_hdr_rde(struct ibuf **bp, uint16_t type, uint16_t subtype,
105139386878Sclaudio     uint32_t len)
1052a16c0992Shenning {
105358e7a839Sclaudio 	struct timespec	time;
1054a16c0992Shenning 
1055e39620e5Snicm 	if ((*bp = ibuf_dynamic(MRT_HEADER_SIZE, MRT_HEADER_SIZE +
1056355a6982Sclaudio 	    MRT_BGP4MP_AS4_IPv6_HEADER_SIZE + MRT_BGP4MP_IPv6_ENTRY_SIZE)) ==
1057e3ef2697Sclaudio 	    NULL)
1058355a6982Sclaudio 		return (-1);
1059355a6982Sclaudio 
106058e7a839Sclaudio 	clock_gettime(CLOCK_REALTIME, &time);
106158e7a839Sclaudio 
1062e3ef2697Sclaudio 	if (ibuf_add_n32(*bp, time.tv_sec) == -1)
1063e3ef2697Sclaudio 		goto fail;
1064e3ef2697Sclaudio 	if (ibuf_add_n16(*bp, type) == -1)
1065e3ef2697Sclaudio 		goto fail;
1066e3ef2697Sclaudio 	if (ibuf_add_n16(*bp, subtype) == -1)
1067e3ef2697Sclaudio 		goto fail;
1068a16c0992Shenning 
1069355a6982Sclaudio 	switch (type) {
1070355a6982Sclaudio 	case MSG_TABLE_DUMP:
1071a5190e44Sclaudio 		switch (subtype) {
1072a5190e44Sclaudio 		case AFI_IPv4:
1073a5190e44Sclaudio 			len += MRT_DUMP_HEADER_SIZE;
1074a5190e44Sclaudio 			break;
1075a5190e44Sclaudio 		case AFI_IPv6:
1076a5190e44Sclaudio 			len += MRT_DUMP_HEADER_SIZE_V6;
1077a5190e44Sclaudio 			break;
1078a5190e44Sclaudio 		}
1079e3ef2697Sclaudio 		if (ibuf_add_n32(*bp, len) == -1)
1080e3ef2697Sclaudio 			goto fail;
1081355a6982Sclaudio 		break;
1082355a6982Sclaudio 	case MSG_PROTOCOL_BGP4MP:
1083566a7707Sclaudio 	case MSG_TABLE_DUMP_V2:
1084e3ef2697Sclaudio 		if (ibuf_add_n32(*bp, len) == -1)
1085e3ef2697Sclaudio 			goto fail;
1086355a6982Sclaudio 		break;
1087355a6982Sclaudio 	default:
1088355a6982Sclaudio 		log_warnx("mrt_dump_hdr_rde: unsupported type");
1089355a6982Sclaudio 		goto fail;
1090355a6982Sclaudio 	}
10912a51171bSclaudio 	return (0);
1092355a6982Sclaudio 
1093355a6982Sclaudio fail:
1094e39620e5Snicm 	ibuf_free(*bp);
1095d5f6e828Sclaudio 	*bp = NULL;
1096355a6982Sclaudio 	return (-1);
10972a51171bSclaudio }
10982a51171bSclaudio 
10999c654a33Sclaudio void
11003ac41105Sclaudio mrt_write(struct mrt *mrt)
11013ac41105Sclaudio {
110205453d67Sclaudio 	if (ibuf_write(mrt->fd, mrt->wbuf) == -1) {
11039c654a33Sclaudio 		log_warn("mrt dump aborted, mrt_write");
11043ac41105Sclaudio 		mrt_clean(mrt);
11056236702dSclaudio 		mrt_done(mrt);
11063ac41105Sclaudio 	}
11073ac41105Sclaudio }
11083ac41105Sclaudio 
11093ac41105Sclaudio void
11103ac41105Sclaudio mrt_clean(struct mrt *mrt)
11113ac41105Sclaudio {
1112bb561412Sclaudio 	close(mrt->fd);
111305453d67Sclaudio 	msgbuf_free(mrt->wbuf);
111405453d67Sclaudio 	mrt->wbuf = NULL;
11153ac41105Sclaudio }
11163ac41105Sclaudio 
11172a51171bSclaudio static struct imsgbuf	*mrt_imsgbuf[2];
11182a51171bSclaudio 
11192a51171bSclaudio void
11202a51171bSclaudio mrt_init(struct imsgbuf *rde, struct imsgbuf *se)
11212a51171bSclaudio {
1122199afbfaSflorian 	mrt_imsgbuf[RDEIDX] = rde;
1123199afbfaSflorian 	mrt_imsgbuf[SEIDX] = se;
1124a16c0992Shenning }
1125a16c0992Shenning 
11263ac41105Sclaudio int
11273ac41105Sclaudio mrt_open(struct mrt *mrt, time_t now)
1128a16c0992Shenning {
11293ac41105Sclaudio 	enum imsg_type	type;
1130199afbfaSflorian 	int		fd;
1131a16c0992Shenning 
11323ac41105Sclaudio 	if (strftime(MRT2MC(mrt)->file, sizeof(MRT2MC(mrt)->file),
11333ac41105Sclaudio 	    MRT2MC(mrt)->name, localtime(&now)) == 0) {
1134553e6efdShenning 		log_warnx("mrt_open: strftime conversion failed");
11353ac41105Sclaudio 		return (-1);
1136a16c0992Shenning 	}
1137a16c0992Shenning 
11386025568dSclaudio 	fd = open(MRT2MC(mrt)->file,
11393ac77e71Sclaudio 	    O_WRONLY|O_NONBLOCK|O_CREAT|O_TRUNC|O_CLOEXEC, 0644);
11406025568dSclaudio 	if (fd == -1) {
11413ac41105Sclaudio 		log_warn("mrt_open %s", MRT2MC(mrt)->file);
11422a51171bSclaudio 		return (1);
11432a51171bSclaudio 	}
1144a16c0992Shenning 
1145db27a85bSclaudio 	if (mrt->state == MRT_STATE_OPEN)
11463ac41105Sclaudio 		type = IMSG_MRT_OPEN;
11473ac41105Sclaudio 	else
11483ac41105Sclaudio 		type = IMSG_MRT_REOPEN;
11492a51171bSclaudio 
1150199afbfaSflorian 	if (imsg_compose(mrt_imsgbuf[TYPE2IDX(mrt->type)], type, 0, 0, fd,
11513ac41105Sclaudio 	    mrt, sizeof(struct mrt)) == -1)
11520ee2353cSclaudio 		log_warn("mrt_open");
11532a51171bSclaudio 
11542a51171bSclaudio 	return (1);
11552a51171bSclaudio }
11562a51171bSclaudio 
1157b673e165Sclaudio time_t
11583ac41105Sclaudio mrt_timeout(struct mrt_head *mrt)
1159a16c0992Shenning {
11602a51171bSclaudio 	struct mrt	*m;
11613ac41105Sclaudio 	time_t		 now;
1162b673e165Sclaudio 	time_t		 timeout = -1;
11632a51171bSclaudio 
11643ac41105Sclaudio 	now = time(NULL);
11653ac41105Sclaudio 	LIST_FOREACH(m, mrt, entry) {
1166db27a85bSclaudio 		if (m->state == MRT_STATE_RUNNING &&
11673ac41105Sclaudio 		    MRT2MC(m)->ReopenTimerInterval != 0) {
11683ac41105Sclaudio 			if (MRT2MC(m)->ReopenTimer <= now) {
11693ac41105Sclaudio 				mrt_open(m, now);
11703ac41105Sclaudio 				MRT2MC(m)->ReopenTimer =
11713ac41105Sclaudio 				    now + MRT2MC(m)->ReopenTimerInterval;
11723ac41105Sclaudio 			}
1173b673e165Sclaudio 			if (timeout == -1 ||
1174b673e165Sclaudio 			    MRT2MC(m)->ReopenTimer - now < timeout)
11753ac41105Sclaudio 				timeout = MRT2MC(m)->ReopenTimer - now;
11763ac41105Sclaudio 		}
11773ac41105Sclaudio 	}
1178b673e165Sclaudio 	return (timeout);
11792a51171bSclaudio }
11802a51171bSclaudio 
11813ac41105Sclaudio void
11823ac41105Sclaudio mrt_reconfigure(struct mrt_head *mrt)
1183a16c0992Shenning {
11842a51171bSclaudio 	struct mrt	*m, *xm;
1185a16c0992Shenning 	time_t		 now;
1186a16c0992Shenning 
1187a16c0992Shenning 	now = time(NULL);
11883ac41105Sclaudio 	for (m = LIST_FIRST(mrt); m != NULL; m = xm) {
11893ac41105Sclaudio 		xm = LIST_NEXT(m, entry);
1190db27a85bSclaudio 		if (m->state == MRT_STATE_OPEN ||
1191db27a85bSclaudio 		    m->state == MRT_STATE_REOPEN) {
11923ac41105Sclaudio 			if (mrt_open(m, now) == -1)
11933ac41105Sclaudio 				continue;
11943ac41105Sclaudio 			if (MRT2MC(m)->ReopenTimerInterval != 0)
11953ac41105Sclaudio 				MRT2MC(m)->ReopenTimer =
11963ac41105Sclaudio 				    now + MRT2MC(m)->ReopenTimerInterval;
1197db27a85bSclaudio 			m->state = MRT_STATE_RUNNING;
11983ac41105Sclaudio 		}
1199db27a85bSclaudio 		if (m->state == MRT_STATE_REMOVE) {
1200199afbfaSflorian 			if (imsg_compose(mrt_imsgbuf[TYPE2IDX(m->type)],
1201199afbfaSflorian 			    IMSG_MRT_CLOSE, 0, 0, -1, m, sizeof(struct mrt)) ==
1202199afbfaSflorian 			    -1)
1203199afbfaSflorian 				log_warn("mrt_reconfigure");
12043ac41105Sclaudio 			LIST_REMOVE(m, entry);
12052a51171bSclaudio 			free(m);
12062a51171bSclaudio 			continue;
12072a51171bSclaudio 		}
12082a51171bSclaudio 	}
12095c551c94Sclaudio }
12105c551c94Sclaudio 
12113ac41105Sclaudio void
12122a51171bSclaudio mrt_handler(struct mrt_head *mrt)
1213a16c0992Shenning {
12142a51171bSclaudio 	struct mrt	*m;
1215a16c0992Shenning 	time_t		 now;
1216a16c0992Shenning 
1217a16c0992Shenning 	now = time(NULL);
12183ac41105Sclaudio 	LIST_FOREACH(m, mrt, entry) {
1219db27a85bSclaudio 		if (m->state == MRT_STATE_RUNNING &&
12203ac41105Sclaudio 		    (MRT2MC(m)->ReopenTimerInterval != 0 ||
1221566a7707Sclaudio 		     m->type == MRT_TABLE_DUMP ||
1222566a7707Sclaudio 		     m->type == MRT_TABLE_DUMP_MP ||
1223566a7707Sclaudio 		     m->type == MRT_TABLE_DUMP_V2)) {
12243ac41105Sclaudio 			if (mrt_open(m, now) == -1)
12253ac41105Sclaudio 				continue;
12263ac41105Sclaudio 			MRT2MC(m)->ReopenTimer =
12273ac41105Sclaudio 			    now + MRT2MC(m)->ReopenTimerInterval;
12282a51171bSclaudio 		}
12292a51171bSclaudio 	}
1230a16c0992Shenning }
1231a16c0992Shenning 
12323ac41105Sclaudio struct mrt *
12333ac41105Sclaudio mrt_get(struct mrt_head *c, struct mrt *m)
1234a16c0992Shenning {
12352a51171bSclaudio 	struct mrt	*t;
12362a51171bSclaudio 
12373ac41105Sclaudio 	LIST_FOREACH(t, c, entry) {
12383ac41105Sclaudio 		if (t->type != m->type)
12392a51171bSclaudio 			continue;
124016b4414fSclaudio 		if (strcmp(t->rib, m->rib))
124116b4414fSclaudio 			continue;
12423ac41105Sclaudio 		if (t->peer_id == m->peer_id &&
12433ac41105Sclaudio 		    t->group_id == m->group_id)
12443ac41105Sclaudio 			return (t);
12452a51171bSclaudio 	}
1246a16c0992Shenning 	return (NULL);
1247a16c0992Shenning }
1248a16c0992Shenning 
1249e8d21d8aSclaudio void
12502a51171bSclaudio mrt_mergeconfig(struct mrt_head *xconf, struct mrt_head *nconf)
1251a16c0992Shenning {
12522a51171bSclaudio 	struct mrt	*m, *xm;
1253a16c0992Shenning 
125491941cb9Sclaudio 	/* both lists here are actually struct mrt_conifg nodes */
12553ac41105Sclaudio 	LIST_FOREACH(m, nconf, entry) {
12563ac41105Sclaudio 		if ((xm = mrt_get(xconf, m)) == NULL) {
1257a16c0992Shenning 			/* NEW */
12583f056e34Smmcc 			if ((xm = malloc(sizeof(struct mrt_config))) == NULL)
1259f87a5020Shenning 				fatal("mrt_mergeconfig");
12603ac41105Sclaudio 			memcpy(xm, m, sizeof(struct mrt_config));
1261db27a85bSclaudio 			xm->state = MRT_STATE_OPEN;
12623ac41105Sclaudio 			LIST_INSERT_HEAD(xconf, xm, entry);
1263a16c0992Shenning 		} else {
1264a16c0992Shenning 			/* MERGE */
126508658d8dSclaudio 			if (strlcpy(MRT2MC(xm)->name, MRT2MC(m)->name,
12663ac41105Sclaudio 			    sizeof(MRT2MC(xm)->name)) >=
12673ac41105Sclaudio 			    sizeof(MRT2MC(xm)->name))
1268f87a5020Shenning 				fatalx("mrt_mergeconfig: strlcpy");
12693ac41105Sclaudio 			MRT2MC(xm)->ReopenTimerInterval =
12703ac41105Sclaudio 			    MRT2MC(m)->ReopenTimerInterval;
1271db27a85bSclaudio 			xm->state = MRT_STATE_REOPEN;
12723ac41105Sclaudio 		}
1273a16c0992Shenning 	}
12742a51171bSclaudio 
12753ac41105Sclaudio 	LIST_FOREACH(xm, xconf, entry)
12763ac41105Sclaudio 		if (mrt_get(nconf, xm) == NULL)
1277a16c0992Shenning 			/* REMOVE */
1278db27a85bSclaudio 			xm->state = MRT_STATE_REMOVE;
1279a16c0992Shenning 
1280a16c0992Shenning 	/* free config */
1281bd3ebedfSclaudio 	while ((m = LIST_FIRST(nconf)) != NULL) {
12823ac41105Sclaudio 		LIST_REMOVE(m, entry);
1283a16c0992Shenning 		free(m);
1284a16c0992Shenning 	}
1285a16c0992Shenning }
1286