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