]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_bmp.c
Merge pull request #10904 from mobash-rasool/fixes
[mirror_frr.git] / bgpd / bgp_bmp.c
CommitLineData
6c29258c
YO
1/* BMP support.
2 * Copyright (C) 2018 Yasuhiro Ohara
ed18356f 3 * Copyright (C) 2019 David Lamparter for NetDEF, Inc.
6c29258c 4 *
ed18356f
DL
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the Free
7 * Software Foundation; either version 2 of the License, or (at your option)
8 * any later version.
6c29258c 9 *
ed18356f
DL
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
6c29258c
YO
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; see the file COPYING; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include <zebra.h>
21
22#include "log.h"
23#include "stream.h"
24#include "sockunion.h"
25#include "command.h"
26#include "prefix.h"
27#include "thread.h"
28#include "linklist.h"
29#include "queue.h"
ed18356f 30#include "pullwr.h"
6c29258c
YO
31#include "memory.h"
32#include "network.h"
33#include "filter.h"
34#include "lib_errors.h"
35#include "stream.h"
0ba4eeec 36#include "libfrr.h"
09781197 37#include "lib/version.h"
ed18356f
DL
38#include "jhash.h"
39#include "termtable.h"
6c29258c
YO
40
41#include "bgpd/bgp_table.h"
42#include "bgpd/bgpd.h"
43#include "bgpd/bgp_route.h"
44#include "bgpd/bgp_attr.h"
45#include "bgpd/bgp_dump.h"
46#include "bgpd/bgp_errors.h"
d35a6c28 47#include "bgpd/bgp_packet.h"
6c29258c 48#include "bgpd/bgp_bmp.h"
ed18356f
DL
49#include "bgpd/bgp_fsm.h"
50#include "bgpd/bgp_updgrp.h"
51#include "bgpd/bgp_vty.h"
e0302d7e 52#include "bgpd/bgp_trace.h"
ed18356f
DL
53
54static void bmp_close(struct bmp *bmp);
55static struct bmp_bgp *bmp_bgp_find(struct bgp *bgp);
56static void bmp_targets_put(struct bmp_targets *bt);
57static struct bmp_bgp_peer *bmp_bgp_peer_find(uint64_t peerid);
58static struct bmp_bgp_peer *bmp_bgp_peer_get(struct peer *peer);
59static void bmp_active_disconnected(struct bmp_active *ba);
60static void bmp_active_put(struct bmp_active *ba);
61
bf8d3d6a 62DEFINE_MGROUP(BMP, "BMP (BGP Monitoring Protocol)");
ed18356f 63
bf8d3d6a
DL
64DEFINE_MTYPE_STATIC(BMP, BMP_CONN, "BMP connection state");
65DEFINE_MTYPE_STATIC(BMP, BMP_TARGETS, "BMP targets");
66DEFINE_MTYPE_STATIC(BMP, BMP_TARGETSNAME, "BMP targets name");
67DEFINE_MTYPE_STATIC(BMP, BMP_LISTENER, "BMP listener");
68DEFINE_MTYPE_STATIC(BMP, BMP_ACTIVE, "BMP active connection config");
69DEFINE_MTYPE_STATIC(BMP, BMP_ACLNAME, "BMP access-list name");
70DEFINE_MTYPE_STATIC(BMP, BMP_QUEUE, "BMP update queue item");
71DEFINE_MTYPE_STATIC(BMP, BMP, "BMP instance state");
72DEFINE_MTYPE_STATIC(BMP, BMP_MIRRORQ, "BMP route mirroring buffer");
73DEFINE_MTYPE_STATIC(BMP, BMP_PEER, "BMP per BGP peer data");
74DEFINE_MTYPE_STATIC(BMP, BMP_OPEN, "BMP stored BGP OPEN message");
ed18356f 75
96244aca 76DEFINE_QOBJ_TYPE(bmp_targets);
ed18356f
DL
77
78static int bmp_bgp_cmp(const struct bmp_bgp *a, const struct bmp_bgp *b)
79{
80 if (a->bgp < b->bgp)
81 return -1;
82 if (a->bgp > b->bgp)
83 return 1;
84 return 0;
85}
86
87static uint32_t bmp_bgp_hash(const struct bmp_bgp *e)
88{
89 return jhash(&e->bgp, sizeof(e->bgp), 0x55aa5a5a);
90}
6c29258c 91
960b9a53 92DECLARE_HASH(bmp_bgph, struct bmp_bgp, bbi, bmp_bgp_cmp, bmp_bgp_hash);
ed18356f
DL
93
94struct bmp_bgph_head bmp_bgph;
95
96static int bmp_bgp_peer_cmp(const struct bmp_bgp_peer *a,
97 const struct bmp_bgp_peer *b)
98{
99 if (a->peerid < b->peerid)
100 return -1;
101 if (a->peerid > b->peerid)
102 return 1;
103 return 0;
104}
105
106static uint32_t bmp_bgp_peer_hash(const struct bmp_bgp_peer *e)
107{
108 return e->peerid;
109}
6c29258c 110
ed18356f 111DECLARE_HASH(bmp_peerh, struct bmp_bgp_peer, bpi,
960b9a53 112 bmp_bgp_peer_cmp, bmp_bgp_peer_hash);
6c29258c 113
ed18356f 114struct bmp_peerh_head bmp_peerh;
6c29258c 115
960b9a53 116DECLARE_LIST(bmp_mirrorq, struct bmp_mirrorq, bmi);
6c29258c 117
ed18356f 118/* listener management */
6c29258c 119
ed18356f
DL
120static int bmp_listener_cmp(const struct bmp_listener *a,
121 const struct bmp_listener *b)
6c29258c 122{
ed18356f 123 int c;
6c29258c 124
ed18356f
DL
125 c = sockunion_cmp(&a->addr, &b->addr);
126 if (c)
127 return c;
128 if (a->port < b->port)
129 return -1;
130 if (a->port > b->port)
131 return 1;
132 return 0;
133}
6c29258c 134
960b9a53
DL
135DECLARE_SORTLIST_UNIQ(bmp_listeners, struct bmp_listener, bli,
136 bmp_listener_cmp);
ed18356f
DL
137
138static int bmp_targets_cmp(const struct bmp_targets *a,
139 const struct bmp_targets *b)
140{
141 return strcmp(a->name, b->name);
6c29258c
YO
142}
143
960b9a53 144DECLARE_SORTLIST_UNIQ(bmp_targets, struct bmp_targets, bti, bmp_targets_cmp);
ed18356f 145
960b9a53 146DECLARE_LIST(bmp_session, struct bmp, bsi);
ed18356f 147
960b9a53 148DECLARE_DLIST(bmp_qlist, struct bmp_queue_entry, bli);
ed18356f
DL
149
150static int bmp_qhash_cmp(const struct bmp_queue_entry *a,
151 const struct bmp_queue_entry *b)
6c29258c 152{
ed18356f 153 int ret;
87102aa0 154 if (a->afi == AFI_L2VPN && a->safi == SAFI_EVPN && b->afi == AFI_L2VPN
155 && b->safi == SAFI_EVPN) {
156 ret = prefix_cmp(&a->rd, &b->rd);
157 if (ret)
158 return ret;
159 } else if (a->afi == AFI_L2VPN && a->safi == SAFI_EVPN)
160 return 1;
161 else if (b->afi == AFI_L2VPN && b->safi == SAFI_EVPN)
162 return -1;
163
ed18356f
DL
164 ret = prefix_cmp(&a->p, &b->p);
165 if (ret)
166 return ret;
167 ret = memcmp(&a->peerid, &b->peerid,
168 offsetof(struct bmp_queue_entry, refcount) -
169 offsetof(struct bmp_queue_entry, peerid));
170 return ret;
6c29258c
YO
171}
172
ed18356f 173static uint32_t bmp_qhash_hkey(const struct bmp_queue_entry *e)
6c29258c 174{
ed18356f
DL
175 uint32_t key;
176
177 key = prefix_hash_key((void *)&e->p);
178 key = jhash(&e->peerid,
87102aa0 179 offsetof(struct bmp_queue_entry, refcount)
180 - offsetof(struct bmp_queue_entry, peerid),
181 key);
182 if (e->afi == AFI_L2VPN && e->safi == SAFI_EVPN)
183 key = jhash(&e->rd,
184 offsetof(struct bmp_queue_entry, rd)
185 - offsetof(struct bmp_queue_entry, refcount)
186 + PSIZE(e->rd.prefixlen),
187 key);
188
ed18356f
DL
189 return key;
190}
6c29258c 191
ed18356f 192DECLARE_HASH(bmp_qhash, struct bmp_queue_entry, bhi,
960b9a53 193 bmp_qhash_cmp, bmp_qhash_hkey);
6c29258c 194
ed18356f
DL
195static int bmp_active_cmp(const struct bmp_active *a,
196 const struct bmp_active *b)
197{
198 int c;
199
200 c = strcmp(a->hostname, b->hostname);
201 if (c)
202 return c;
203 if (a->port < b->port)
204 return -1;
205 if (a->port > b->port)
206 return 1;
6c29258c
YO
207 return 0;
208}
209
960b9a53 210DECLARE_SORTLIST_UNIQ(bmp_actives, struct bmp_active, bai, bmp_active_cmp);
ed18356f
DL
211
212static struct bmp *bmp_new(struct bmp_targets *bt, int bmp_sock)
6c29258c 213{
ed18356f
DL
214 struct bmp *new = XCALLOC(MTYPE_BMP_CONN, sizeof(struct bmp));
215 afi_t afi;
216 safi_t safi;
217
218 monotime(&new->t_up);
219 new->targets = bt;
220 new->socket = bmp_sock;
221 new->syncafi = AFI_MAX;
222
223 FOREACH_AFI_SAFI (afi, safi) {
224 new->afistate[afi][safi] = bt->afimon[afi][safi]
225 ? BMP_AFI_NEEDSYNC : BMP_AFI_INACTIVE;
226 }
227
228 bmp_session_add_tail(&bt->sessions, new);
229 return new;
6c29258c 230}
6c29258c 231
ed18356f 232static void bmp_free(struct bmp *bmp)
6c29258c 233{
ed18356f
DL
234 bmp_session_del(&bmp->targets->sessions, bmp);
235 XFREE(MTYPE_BMP_CONN, bmp);
6c29258c
YO
236}
237
238static void bmp_common_hdr(struct stream *s, uint8_t ver, uint8_t type)
239{
240 stream_putc(s, ver);
241 stream_putl(s, 0); //dummy message length. will be set later.
242 stream_putc(s, type);
243}
244
ed18356f
DL
245static void bmp_per_peer_hdr(struct stream *s, struct peer *peer,
246 uint8_t flags, const struct timeval *tv)
6c29258c 247{
6c29258c
YO
248 char peer_distinguisher[8];
249
250#define BMP_PEER_TYPE_GLOBAL_INSTANCE 0
251#define BMP_PEER_TYPE_RD_INSTANCE 1
252#define BMP_PEER_TYPE_LOCAL_INSTANCE 2
253
254#define BMP_PEER_FLAG_V (1 << 7)
255#define BMP_PEER_FLAG_L (1 << 6)
256#define BMP_PEER_FLAG_A (1 << 5)
257
258 /* Peer Type */
259 stream_putc(s, BMP_PEER_TYPE_GLOBAL_INSTANCE);
260
261 /* Peer Flags */
ed18356f
DL
262 if (peer->su.sa.sa_family == AF_INET6)
263 SET_FLAG(flags, BMP_PEER_FLAG_V);
264 else
265 UNSET_FLAG(flags, BMP_PEER_FLAG_V);
266 stream_putc(s, flags);
6c29258c
YO
267
268 /* Peer Distinguisher */
269 memset (&peer_distinguisher[0], 0, 8);
270 stream_put(s, &peer_distinguisher[0], 8);
271
272 /* Peer Address */
ed18356f
DL
273 if (peer->su.sa.sa_family == AF_INET6)
274 stream_put(s, &peer->su.sin6.sin6_addr, 16);
275 else if (peer->su.sa.sa_family == AF_INET) {
276 stream_putl(s, 0);
277 stream_putl(s, 0);
278 stream_putl(s, 0);
279 stream_put_in_addr(s, &peer->su.sin.sin_addr);
280 } else {
281 stream_putl(s, 0);
6c29258c
YO
282 stream_putl(s, 0);
283 stream_putl(s, 0);
284 stream_putl(s, 0);
6c29258c
YO
285 }
286
287 /* Peer AS */
288 stream_putl(s, peer->as);
289
290 /* Peer BGP ID */
291 stream_put_in_addr(s, &peer->remote_id);
292
293 /* Timestamp */
ed18356f
DL
294 if (tv) {
295 stream_putl(s, tv->tv_sec);
296 stream_putl(s, tv->tv_usec);
297 } else {
298 stream_putl(s, 0);
299 stream_putl(s, 0);
300 }
6c29258c
YO
301}
302
ed18356f
DL
303static void bmp_put_info_tlv(struct stream *s, uint16_t type,
304 const char *string)
6c29258c
YO
305{
306 int len = strlen (string);
307 stream_putw(s, type);
308 stream_putw(s, len);
309 stream_put(s, string, len);
310}
311
312static int bmp_send_initiation(struct bmp *bmp)
313{
314 int len;
315 struct stream *s;
316 s = stream_new(BGP_MAX_PACKET_SIZE);
317 bmp_common_hdr(s, BMP_VERSION_3, BMP_TYPE_INITIATION);
318
319#define BMP_INFO_TYPE_SYSDESCR 1
320#define BMP_INFO_TYPE_SYSNAME 2
ed18356f
DL
321 bmp_put_info_tlv(s, BMP_INFO_TYPE_SYSDESCR,
322 FRR_FULL_NAME " " FRR_VER_SHORT);
323 bmp_put_info_tlv(s, BMP_INFO_TYPE_SYSNAME, cmd_hostname_get());
6c29258c
YO
324
325 len = stream_get_endp(s);
326 stream_putl_at(s, BMP_LENGTH_POS, len); //message length is set.
327
ed18356f
DL
328 pullwr_write_stream(bmp->pullwr, s);
329 stream_free(s);
6c29258c
YO
330 return 0;
331}
332
ed18356f
DL
333static void bmp_notify_put(struct stream *s, struct bgp_notify *nfy)
334{
335 size_t len_pos;
336 uint8_t marker[16] = {
337 0xff, 0xff, 0xff, 0xff,
338 0xff, 0xff, 0xff, 0xff,
339 0xff, 0xff, 0xff, 0xff,
340 0xff, 0xff, 0xff, 0xff,
341 };
342
343 stream_put(s, marker, sizeof(marker));
344 len_pos = stream_get_endp(s);
345 stream_putw(s, 0);
346 stream_putc(s, BGP_MSG_NOTIFY);
347 stream_putc(s, nfy->code);
348 stream_putc(s, nfy->subcode);
349 stream_put(s, nfy->data, nfy->length);
350
351 stream_putw_at(s, len_pos, stream_get_endp(s) - len_pos
352 + sizeof(marker));
353}
354
355static struct stream *bmp_peerstate(struct peer *peer, bool down)
6c29258c 356{
6c29258c 357 struct stream *s;
ed18356f
DL
358 size_t len;
359 struct timeval uptime, uptime_real;
6c29258c 360
ed18356f
DL
361 uptime.tv_sec = peer->uptime;
362 uptime.tv_usec = 0;
363 monotime_to_realtime(&uptime, &uptime_real);
6c29258c 364
ed18356f 365#define BGP_BMP_MAX_PACKET_SIZE 1024
6c29258c 366 s = stream_new(BGP_MAX_PACKET_SIZE);
6c29258c 367
feb17238 368 if (peer_established(peer) && !down) {
ed18356f 369 struct bmp_bgp_peer *bbpeer;
6c29258c 370
ed18356f
DL
371 bmp_common_hdr(s, BMP_VERSION_3,
372 BMP_TYPE_PEER_UP_NOTIFICATION);
373 bmp_per_peer_hdr(s, peer, 0, &uptime_real);
6c29258c
YO
374
375 /* Local Address (16 bytes) */
376 if (peer->su_local->sa.sa_family == AF_INET6)
377 stream_put(s, &peer->su_local->sin6.sin6_addr, 16);
378 else if (peer->su_local->sa.sa_family == AF_INET) {
379 stream_putl(s, 0);
380 stream_putl(s, 0);
381 stream_putl(s, 0);
382 stream_put_in_addr(s, &peer->su_local->sin.sin_addr);
383 }
384
385 /* Local Port, Remote Port */
386 if (peer->su_local->sa.sa_family == AF_INET6)
387 stream_putw(s, peer->su_local->sin6.sin6_port);
388 else if (peer->su_local->sa.sa_family == AF_INET)
389 stream_putw(s, peer->su_local->sin.sin_port);
390 if (peer->su_remote->sa.sa_family == AF_INET6)
391 stream_putw(s, peer->su_remote->sin6.sin6_port);
392 else if (peer->su_remote->sa.sa_family == AF_INET)
393 stream_putw(s, peer->su_remote->sin.sin_port);
394
ed18356f
DL
395 static const uint8_t dummy_open[] = {
396 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
397 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
398 0x00, 0x13, 0x01,
399 };
6c29258c 400
ed18356f 401 bbpeer = bmp_bgp_peer_find(peer->qobj_node.nid);
6c29258c 402
ed18356f
DL
403 if (bbpeer && bbpeer->open_tx)
404 stream_put(s, bbpeer->open_tx, bbpeer->open_tx_len);
405 else {
406 stream_put(s, dummy_open, sizeof(dummy_open));
63efca0e
DL
407 zlog_warn("bmp: missing TX OPEN message for peer %s",
408 peer->host);
ed18356f
DL
409 }
410 if (bbpeer && bbpeer->open_rx)
411 stream_put(s, bbpeer->open_rx, bbpeer->open_rx_len);
412 else {
413 stream_put(s, dummy_open, sizeof(dummy_open));
63efca0e
DL
414 zlog_warn("bmp: missing RX OPEN message for peer %s",
415 peer->host);
ed18356f 416 }
6c29258c 417
ed18356f
DL
418 if (peer->desc)
419 bmp_put_info_tlv(s, 0, peer->desc);
420 } else {
421 uint8_t type;
422 size_t type_pos;
423
424 bmp_common_hdr(s, BMP_VERSION_3,
425 BMP_TYPE_PEER_DOWN_NOTIFICATION);
426 bmp_per_peer_hdr(s, peer, 0, &uptime_real);
427
428 type_pos = stream_get_endp(s);
429 stream_putc(s, 0); /* placeholder for down reason */
430
431 switch (peer->last_reset) {
432 case PEER_DOWN_NOTIFY_RECEIVED:
433 type = BMP_PEERDOWN_REMOTE_NOTIFY;
434 bmp_notify_put(s, &peer->notify);
435 break;
436 case PEER_DOWN_CLOSE_SESSION:
437 type = BMP_PEERDOWN_REMOTE_CLOSE;
438 break;
21e8caa2
QY
439 case PEER_DOWN_WAITING_NHT:
440 type = BMP_PEERDOWN_LOCAL_FSM;
441 stream_putw(s, BGP_FSM_TcpConnectionFails);
442 break;
443 /*
444 * TODO: Map remaining PEER_DOWN_* reasons to RFC event codes.
445 * TODO: Implement BMP_PEERDOWN_LOCAL_NOTIFY.
446 *
447 * See RFC7854 ss. 4.9
448 */
ed18356f 449 default:
21e8caa2
QY
450 type = BMP_PEERDOWN_LOCAL_FSM;
451 stream_putw(s, BMP_PEER_DOWN_NO_RELEVANT_EVENT_CODE);
ed18356f 452 break;
6c29258c 453 }
ed18356f 454 stream_putc_at(s, type_pos, type);
6c29258c
YO
455 }
456
ed18356f
DL
457 len = stream_get_endp(s);
458 stream_putl_at(s, BMP_LENGTH_POS, len); //message length is set.
459 return s;
460}
461
462
463static int bmp_send_peerup(struct bmp *bmp)
464{
465 struct peer *peer;
466 struct listnode *node;
467 struct stream *s;
468
469 /* Walk down all peers */
470 for (ALL_LIST_ELEMENTS_RO(bmp->targets->bgp->peer, node, peer)) {
471 s = bmp_peerstate(peer, false);
472 pullwr_write_stream(bmp->pullwr, s);
473 stream_free(s);
474 }
6c29258c
YO
475
476 return 0;
477}
478
ed18356f
DL
479/* XXX: kludge - filling the pullwr's buffer */
480static void bmp_send_all(struct bmp_bgp *bmpbgp, struct stream *s)
481{
482 struct bmp_targets *bt;
483 struct bmp *bmp;
484
485 frr_each(bmp_targets, &bmpbgp->targets, bt)
486 frr_each(bmp_session, &bt->sessions, bmp)
487 pullwr_write_stream(bmp->pullwr, s);
488 stream_free(s);
489}
490
491/*
492 * Route Mirroring
493 */
494
495#define BMP_MIRROR_TLV_TYPE_BGP_MESSAGE 0
496#define BMP_MIRROR_TLV_TYPE_INFO 1
497
498#define BMP_MIRROR_INFO_CODE_ERRORPDU 0
499#define BMP_MIRROR_INFO_CODE_LOSTMSGS 1
500
501static struct bmp_mirrorq *bmp_pull_mirror(struct bmp *bmp)
502{
503 struct bmp_mirrorq *bmq;
504
505 bmq = bmp->mirrorpos;
506 if (!bmq)
507 return NULL;
508
509 bmp->mirrorpos = bmp_mirrorq_next(&bmp->targets->bmpbgp->mirrorq, bmq);
510
511 bmq->refcount--;
512 if (!bmq->refcount) {
513 bmp->targets->bmpbgp->mirror_qsize -= sizeof(*bmq) + bmq->len;
514 bmp_mirrorq_del(&bmp->targets->bmpbgp->mirrorq, bmq);
515 }
516 return bmq;
517}
518
519static void bmp_mirror_cull(struct bmp_bgp *bmpbgp)
520{
521 while (bmpbgp->mirror_qsize > bmpbgp->mirror_qsizelimit) {
522 struct bmp_mirrorq *bmq, *inner;
523 struct bmp_targets *bt;
524 struct bmp *bmp;
525
526 bmq = bmp_mirrorq_first(&bmpbgp->mirrorq);
527
528 frr_each(bmp_targets, &bmpbgp->targets, bt) {
529 if (!bt->mirror)
530 continue;
531 frr_each(bmp_session, &bt->sessions, bmp) {
532 if (bmp->mirrorpos != bmq)
533 continue;
534
535 while ((inner = bmp_pull_mirror(bmp))) {
536 if (!inner->refcount)
537 XFREE(MTYPE_BMP_MIRRORQ,
538 inner);
539 }
540
541 zlog_warn("bmp[%s] lost mirror messages due to buffer size limit",
542 bmp->remote);
543 bmp->mirror_lost = true;
544 pullwr_bump(bmp->pullwr);
545 }
546 }
547 }
548}
549
d35a6c28
DL
550static int bmp_mirror_packet(struct peer *peer, uint8_t type, bgp_size_t size,
551 struct stream *packet)
6c29258c 552{
ed18356f
DL
553 struct bmp_bgp *bmpbgp = bmp_bgp_find(peer->bgp);
554 struct timeval tv;
555 struct bmp_mirrorq *qitem;
556 struct bmp_targets *bt;
6c29258c 557 struct bmp *bmp;
6c29258c 558
e0302d7e
QY
559 frrtrace(3, frr_bgp, bmp_mirror_packet, peer, type, packet);
560
ed18356f
DL
561 gettimeofday(&tv, NULL);
562
563 if (type == BGP_MSG_OPEN) {
564 struct bmp_bgp_peer *bbpeer = bmp_bgp_peer_get(peer);
565
566 XFREE(MTYPE_BMP_OPEN, bbpeer->open_rx);
567
568 bbpeer->open_rx_len = size;
569 bbpeer->open_rx = XMALLOC(MTYPE_BMP_OPEN, size);
570 memcpy(bbpeer->open_rx, packet->data, size);
571 }
572
573 if (!bmpbgp)
d35a6c28 574 return 0;
6c29258c 575
ed18356f
DL
576 qitem = XCALLOC(MTYPE_BMP_MIRRORQ, sizeof(*qitem) + size);
577 qitem->peerid = peer->qobj_node.nid;
578 qitem->tv = tv;
579 qitem->len = size;
580 memcpy(qitem->data, packet->data, size);
581
582 frr_each(bmp_targets, &bmpbgp->targets, bt) {
583 if (!bt->mirror)
584 continue;
585 frr_each(bmp_session, &bt->sessions, bmp) {
586 qitem->refcount++;
587 if (!bmp->mirrorpos)
588 bmp->mirrorpos = qitem;
589 pullwr_bump(bmp->pullwr);
590 }
591 }
592 if (qitem->refcount == 0)
593 XFREE(MTYPE_BMP_MIRRORQ, qitem);
594 else {
595 bmpbgp->mirror_qsize += sizeof(*qitem) + size;
596 bmp_mirrorq_add_tail(&bmpbgp->mirrorq, qitem);
597
598 bmp_mirror_cull(bmpbgp);
599
600 bmpbgp->mirror_qsizemax = MAX(bmpbgp->mirror_qsizemax,
601 bmpbgp->mirror_qsize);
602 }
603 return 0;
604}
605
606static void bmp_wrmirror_lost(struct bmp *bmp, struct pullwr *pullwr)
607{
608 struct stream *s;
609 struct timeval tv;
610
611 gettimeofday(&tv, NULL);
612
613 s = stream_new(BGP_MAX_PACKET_SIZE);
614
615 bmp_common_hdr(s, BMP_VERSION_3, BMP_TYPE_ROUTE_MIRRORING);
616 bmp_per_peer_hdr(s, bmp->targets->bgp->peer_self, 0, &tv);
617
618 stream_putw(s, BMP_MIRROR_TLV_TYPE_INFO);
619 stream_putw(s, 2);
620 stream_putw(s, BMP_MIRROR_INFO_CODE_LOSTMSGS);
621 stream_putl_at(s, BMP_LENGTH_POS, stream_get_endp(s));
622
623 bmp->cnt_mirror_overruns++;
624 pullwr_write_stream(bmp->pullwr, s);
625 stream_free(s);
626}
627
628static bool bmp_wrmirror(struct bmp *bmp, struct pullwr *pullwr)
629{
630 struct bmp_mirrorq *bmq;
631 struct peer *peer;
632 bool written = false;
633
634 if (bmp->mirror_lost) {
635 bmp_wrmirror_lost(bmp, pullwr);
636 bmp->mirror_lost = false;
637 return true;
638 }
639
640 bmq = bmp_pull_mirror(bmp);
641 if (!bmq)
642 return false;
643
644 peer = QOBJ_GET_TYPESAFE(bmq->peerid, peer);
645 if (!peer) {
646 zlog_info("bmp: skipping mirror message for deleted peer");
647 goto out;
648 }
649
650 struct stream *s;
6c29258c
YO
651 s = stream_new(BGP_MAX_PACKET_SIZE);
652
653 bmp_common_hdr(s, BMP_VERSION_3, BMP_TYPE_ROUTE_MIRRORING);
ed18356f 654 bmp_per_peer_hdr(s, peer, 0, &bmq->tv);
6c29258c
YO
655
656 /* BMP Mirror TLV. */
6c29258c 657 stream_putw(s, BMP_MIRROR_TLV_TYPE_BGP_MESSAGE);
ed18356f
DL
658 stream_putw(s, bmq->len);
659 stream_putl_at(s, BMP_LENGTH_POS, stream_get_endp(s) + bmq->len);
6c29258c 660
ed18356f
DL
661 bmp->cnt_mirror++;
662 pullwr_write_stream(bmp->pullwr, s);
663 pullwr_write(bmp->pullwr, bmq->data, bmq->len);
6c29258c 664
ed18356f
DL
665 stream_free(s);
666 written = true;
6c29258c 667
ed18356f
DL
668out:
669 if (!bmq->refcount)
670 XFREE(MTYPE_BMP_MIRRORQ, bmq);
671 return written;
6c29258c
YO
672}
673
ed18356f
DL
674static int bmp_outgoing_packet(struct peer *peer, uint8_t type, bgp_size_t size,
675 struct stream *packet)
6c29258c 676{
ed18356f 677 if (type == BGP_MSG_OPEN) {
e0302d7e
QY
678 frrtrace(2, frr_bgp, bmp_update_saved_open, peer, packet);
679
ed18356f 680 struct bmp_bgp_peer *bbpeer = bmp_bgp_peer_get(peer);
6c29258c 681
ed18356f 682 XFREE(MTYPE_BMP_OPEN, bbpeer->open_tx);
6c29258c 683
ed18356f
DL
684 bbpeer->open_tx_len = size;
685 bbpeer->open_tx = XMALLOC(MTYPE_BMP_OPEN, size);
686 memcpy(bbpeer->open_tx, packet->data, size);
687 }
688 return 0;
689}
6c29258c 690
60563d0e 691static int bmp_peer_status_changed(struct peer *peer)
ed18356f
DL
692{
693 struct bmp_bgp *bmpbgp = bmp_bgp_find(peer->bgp);
60563d0e 694 struct bmp_bgp_peer *bbpeer, *bbdopp;
6c29258c 695
e0302d7e
QY
696 frrtrace(1, frr_bgp, bmp_peer_status_changed, peer);
697
ed18356f
DL
698 if (!bmpbgp)
699 return 0;
6c29258c 700
60563d0e
DA
701 if (peer->status == Deleted) {
702 bbpeer = bmp_bgp_peer_find(peer->qobj_node.nid);
703 if (bbpeer) {
704 XFREE(MTYPE_BMP_OPEN, bbpeer->open_rx);
705 XFREE(MTYPE_BMP_OPEN, bbpeer->open_tx);
706 bmp_peerh_del(&bmp_peerh, bbpeer);
707 XFREE(MTYPE_BMP_PEER, bbpeer);
708 }
709 return 0;
710 }
711
df9e8ae7 712 /* Check if this peer just went to Established */
fd2e2db6 713 if ((peer->ostatus != OpenConfirm) || !(peer_established(peer)))
df9e8ae7
MS
714 return 0;
715
ed18356f 716 if (peer->doppelganger && (peer->doppelganger->status != Deleted)) {
ed18356f
DL
717 bbpeer = bmp_bgp_peer_get(peer);
718 bbdopp = bmp_bgp_peer_find(peer->doppelganger->qobj_node.nid);
719 if (bbdopp) {
720 XFREE(MTYPE_BMP_OPEN, bbpeer->open_tx);
721 XFREE(MTYPE_BMP_OPEN, bbpeer->open_rx);
6c29258c 722
ed18356f
DL
723 bbpeer->open_tx = bbdopp->open_tx;
724 bbpeer->open_tx_len = bbdopp->open_tx_len;
725 bbpeer->open_rx = bbdopp->open_rx;
726 bbpeer->open_rx_len = bbdopp->open_rx_len;
6c29258c 727
ed18356f
DL
728 bmp_peerh_del(&bmp_peerh, bbdopp);
729 XFREE(MTYPE_BMP_PEER, bbdopp);
730 }
6c29258c 731 }
ed18356f
DL
732
733 bmp_send_all(bmpbgp, bmp_peerstate(peer, false));
6c29258c
YO
734 return 0;
735}
736
ed18356f 737static int bmp_peer_backward(struct peer *peer)
6c29258c 738{
ed18356f
DL
739 struct bmp_bgp *bmpbgp = bmp_bgp_find(peer->bgp);
740 struct bmp_bgp_peer *bbpeer;
6c29258c 741
e0302d7e
QY
742 frrtrace(1, frr_bgp, bmp_peer_backward_transition, peer);
743
ed18356f
DL
744 if (!bmpbgp)
745 return 0;
6c29258c 746
ed18356f
DL
747 bbpeer = bmp_bgp_peer_find(peer->qobj_node.nid);
748 if (bbpeer) {
749 XFREE(MTYPE_BMP_OPEN, bbpeer->open_tx);
750 bbpeer->open_tx_len = 0;
751 XFREE(MTYPE_BMP_OPEN, bbpeer->open_rx);
752 bbpeer->open_rx_len = 0;
753 }
6c29258c 754
ed18356f
DL
755 bmp_send_all(bmpbgp, bmp_peerstate(peer, true));
756 return 0;
757}
6c29258c 758
ed18356f
DL
759static void bmp_eor(struct bmp *bmp, afi_t afi, safi_t safi, uint8_t flags)
760{
761 struct peer *peer;
762 struct listnode *node;
763 struct stream *s, *s2;
764 iana_afi_t pkt_afi;
765 iana_safi_t pkt_safi;
6c29258c 766
e0302d7e
QY
767 frrtrace(3, frr_bgp, bmp_eor, afi, safi, flags);
768
ed18356f 769 s = stream_new(BGP_MAX_PACKET_SIZE);
6c29258c 770
ed18356f
DL
771 /* Make BGP update packet. */
772 bgp_packet_set_marker(s, BGP_MSG_UPDATE);
6c29258c 773
ed18356f
DL
774 /* Unfeasible Routes Length */
775 stream_putw(s, 0);
6c29258c 776
ed18356f
DL
777 if (afi == AFI_IP && safi == SAFI_UNICAST) {
778 /* Total Path Attribute Length */
779 stream_putw(s, 0);
780 } else {
781 /* Convert AFI, SAFI to values for packet. */
782 bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi);
783
784 /* Total Path Attribute Length */
785 stream_putw(s, 6);
786 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
787 stream_putc(s, BGP_ATTR_MP_UNREACH_NLRI);
788 stream_putc(s, 3);
789 stream_putw(s, pkt_afi);
790 stream_putc(s, pkt_safi);
6c29258c
YO
791 }
792
ed18356f 793 bgp_packet_set_size(s);
6c29258c 794
ed18356f
DL
795 for (ALL_LIST_ELEMENTS_RO(bmp->targets->bgp->peer, node, peer)) {
796 if (!peer->afc_nego[afi][safi])
797 continue;
6c29258c 798
ed18356f 799 s2 = stream_new(BGP_MAX_PACKET_SIZE);
6c29258c 800
ed18356f
DL
801 bmp_common_hdr(s2, BMP_VERSION_3,
802 BMP_TYPE_ROUTE_MONITORING);
803 bmp_per_peer_hdr(s2, peer, flags, NULL);
6c29258c 804
ed18356f
DL
805 stream_putl_at(s2, BMP_LENGTH_POS,
806 stream_get_endp(s) + stream_get_endp(s2));
6c29258c 807
ed18356f
DL
808 bmp->cnt_update++;
809 pullwr_write_stream(bmp->pullwr, s2);
810 pullwr_write_stream(bmp->pullwr, s);
811 stream_free(s2);
812 }
813 stream_free(s);
6c29258c
YO
814}
815
87102aa0 816static struct stream *bmp_update(const struct prefix *p, struct prefix_rd *prd,
817 struct peer *peer, struct attr *attr,
818 afi_t afi, safi_t safi)
6c29258c 819{
ed18356f
DL
820 struct bpacket_attr_vec_arr vecarr;
821 struct stream *s;
822 size_t attrlen_pos = 0, mpattrlen_pos = 0;
823 bgp_size_t total_attr_len = 0;
824
825 bpacket_attr_vec_arr_reset(&vecarr);
826
827 s = stream_new(BGP_MAX_PACKET_SIZE);
828 bgp_packet_set_marker(s, BGP_MSG_UPDATE);
829
830 /* 2: withdrawn routes length */
831 stream_putw(s, 0);
832
833 /* 3: total attributes length - attrlen_pos stores the position */
834 attrlen_pos = stream_get_endp(s);
835 stream_putw(s, 0);
836
837 /* 5: Encode all the attributes, except MP_REACH_NLRI attr. */
838 total_attr_len = bgp_packet_attribute(NULL, peer, s, attr,
839 &vecarr, NULL, afi, safi, peer, NULL, NULL, 0, 0, 0);
6c29258c 840
ed18356f 841 /* space check? */
6c29258c 842
ed18356f
DL
843 /* peer_cap_enhe & add-path removed */
844 if (afi == AFI_IP && safi == SAFI_UNICAST)
845 stream_put_prefix(s, p);
846 else {
847 size_t p1 = stream_get_endp(s);
6c29258c 848
ed18356f 849 /* MPLS removed for now */
6c29258c 850
ed18356f
DL
851 mpattrlen_pos = bgp_packet_mpattr_start(s, peer, afi, safi,
852 &vecarr, attr);
87102aa0 853 bgp_packet_mpattr_prefix(s, afi, safi, p, prd, NULL, 0, 0, 0,
854 attr);
ed18356f
DL
855 bgp_packet_mpattr_end(s, mpattrlen_pos);
856 total_attr_len += stream_get_endp(s) - p1;
6c29258c
YO
857 }
858
ed18356f
DL
859 /* set the total attribute length correctly */
860 stream_putw_at(s, attrlen_pos, total_attr_len);
861 bgp_packet_set_size(s);
862 return s;
863}
6c29258c 864
87102aa0 865static struct stream *bmp_withdraw(const struct prefix *p,
866 struct prefix_rd *prd, afi_t afi,
5f040085 867 safi_t safi)
ed18356f
DL
868{
869 struct stream *s;
870 size_t attrlen_pos = 0, mp_start, mplen_pos;
871 bgp_size_t total_attr_len = 0;
872 bgp_size_t unfeasible_len;
6c29258c 873
ed18356f 874 s = stream_new(BGP_MAX_PACKET_SIZE);
6c29258c 875
ed18356f
DL
876 bgp_packet_set_marker(s, BGP_MSG_UPDATE);
877 stream_putw(s, 0);
6c29258c 878
ed18356f
DL
879 if (afi == AFI_IP && safi == SAFI_UNICAST) {
880 stream_put_prefix(s, p);
881 unfeasible_len = stream_get_endp(s) - BGP_HEADER_SIZE
882 - BGP_UNFEASIBLE_LEN;
883 stream_putw_at(s, BGP_HEADER_SIZE, unfeasible_len);
884 stream_putw(s, 0);
885 } else {
886 attrlen_pos = stream_get_endp(s);
887 /* total attr length = 0 for now. reevaluate later */
888 stream_putw(s, 0);
889 mp_start = stream_get_endp(s);
890 mplen_pos = bgp_packet_mpunreach_start(s, afi, safi);
891
87102aa0 892 bgp_packet_mpunreach_prefix(s, p, afi, safi, prd, NULL, 0, 0, 0,
893 NULL);
ed18356f
DL
894 /* Set the mp_unreach attr's length */
895 bgp_packet_mpunreach_end(s, mplen_pos);
896
897 /* Set total path attribute length. */
898 total_attr_len = stream_get_endp(s) - mp_start;
899 stream_putw_at(s, attrlen_pos, total_attr_len);
900 }
901
902 bgp_packet_set_size(s);
903 return s;
904}
905
906static void bmp_monitor(struct bmp *bmp, struct peer *peer, uint8_t flags,
87102aa0 907 const struct prefix *p, struct prefix_rd *prd,
908 struct attr *attr, afi_t afi, safi_t safi,
909 time_t uptime)
ed18356f
DL
910{
911 struct stream *hdr, *msg;
912 struct timeval tv = { .tv_sec = uptime, .tv_usec = 0 };
02cee158 913 struct timeval uptime_real;
ed18356f 914
02cee158 915 monotime_to_realtime(&tv, &uptime_real);
ed18356f 916 if (attr)
87102aa0 917 msg = bmp_update(p, prd, peer, attr, afi, safi);
ed18356f 918 else
87102aa0 919 msg = bmp_withdraw(p, prd, afi, safi);
ed18356f
DL
920
921 hdr = stream_new(BGP_MAX_PACKET_SIZE);
922 bmp_common_hdr(hdr, BMP_VERSION_3, BMP_TYPE_ROUTE_MONITORING);
02cee158 923 bmp_per_peer_hdr(hdr, peer, flags, &uptime_real);
ed18356f
DL
924
925 stream_putl_at(hdr, BMP_LENGTH_POS,
926 stream_get_endp(hdr) + stream_get_endp(msg));
927
928 bmp->cnt_update++;
929 pullwr_write_stream(bmp->pullwr, hdr);
930 pullwr_write_stream(bmp->pullwr, msg);
931 stream_free(hdr);
932 stream_free(msg);
933}
934
935static bool bmp_wrsync(struct bmp *bmp, struct pullwr *pullwr)
936{
937 afi_t afi;
938 safi_t safi;
939
940 if (bmp->syncafi == AFI_MAX) {
941 FOREACH_AFI_SAFI (afi, safi) {
942 if (bmp->afistate[afi][safi] != BMP_AFI_NEEDSYNC)
943 continue;
944
945 bmp->afistate[afi][safi] = BMP_AFI_SYNC;
946
947 bmp->syncafi = afi;
948 bmp->syncsafi = safi;
949 bmp->syncpeerid = 0;
950 memset(&bmp->syncpos, 0, sizeof(bmp->syncpos));
951 bmp->syncpos.family = afi2family(afi);
87102aa0 952 bmp->syncrdpos = NULL;
ed18356f
DL
953 zlog_info("bmp[%s] %s %s sending table",
954 bmp->remote,
955 afi2str(bmp->syncafi),
956 safi2str(bmp->syncsafi));
957 /* break does not work here, 2 loops... */
958 goto afibreak;
6c29258c 959 }
ed18356f
DL
960 if (bmp->syncafi == AFI_MAX)
961 return false;
962 }
6c29258c 963
ed18356f
DL
964afibreak:
965 afi = bmp->syncafi;
966 safi = bmp->syncsafi;
967
968 if (!bmp->targets->afimon[afi][safi]) {
969 /* shouldn't happen */
970 bmp->afistate[afi][safi] = BMP_AFI_INACTIVE;
971 bmp->syncafi = AFI_MAX;
972 bmp->syncsafi = SAFI_MAX;
973 return true;
974 }
975
976 struct bgp_table *table = bmp->targets->bgp->rib[afi][safi];
9bcb3eef 977 struct bgp_dest *bn;
ed18356f
DL
978 struct bgp_path_info *bpi = NULL, *bpiter;
979 struct bgp_adj_in *adjin = NULL, *adjiter;
980
87102aa0 981 if (afi == AFI_L2VPN && safi == SAFI_EVPN) {
982 /* initialize syncrdpos to the first
983 * mid-layer table entry
984 */
7b3a3805 985 if (!bmp->syncrdpos) {
87102aa0 986 bmp->syncrdpos = bgp_table_top(table);
7b3a3805
DS
987 if (!bmp->syncrdpos)
988 goto eor;
989 }
87102aa0 990
991 /* look for a valid mid-layer table */
992 do {
993 table = bgp_dest_get_bgp_table_info(bmp->syncrdpos);
994 if (table) {
995 break;
996 }
997 bmp->syncrdpos = bgp_route_next(bmp->syncrdpos);
998 } while (bmp->syncrdpos);
999
1000 /* mid-layer table completed */
1001 if (!bmp->syncrdpos)
1002 goto eor;
1003 }
1004
ed18356f
DL
1005 bn = bgp_node_lookup(table, &bmp->syncpos);
1006 do {
1007 if (!bn) {
1008 bn = bgp_table_get_next(table, &bmp->syncpos);
1009 if (!bn) {
87102aa0 1010 if (afi == AFI_L2VPN && safi == SAFI_EVPN) {
1011 /* reset bottom-layer pointer */
1012 memset(&bmp->syncpos, 0,
1013 sizeof(bmp->syncpos));
1014 bmp->syncpos.family = afi2family(afi);
1015 /* check whethere there is a valid
1016 * next mid-layer table, otherwise
1017 * declare table completed (eor)
1018 */
1019 for (bmp->syncrdpos = bgp_route_next(
1020 bmp->syncrdpos);
1021 bmp->syncrdpos;
1022 bmp->syncrdpos = bgp_route_next(
1023 bmp->syncrdpos))
1024 if (bgp_dest_get_bgp_table_info(
1025 bmp->syncrdpos))
1026 return true;
1027 }
1028 eor:
ed18356f
DL
1029 zlog_info("bmp[%s] %s %s table completed (EoR)",
1030 bmp->remote, afi2str(afi),
1031 safi2str(safi));
1032 bmp_eor(bmp, afi, safi, BMP_PEER_FLAG_L);
1033 bmp_eor(bmp, afi, safi, 0);
1034
1035 bmp->afistate[afi][safi] = BMP_AFI_LIVE;
1036 bmp->syncafi = AFI_MAX;
1037 bmp->syncsafi = SAFI_MAX;
1038 return true;
1039 }
1040 bmp->syncpeerid = 0;
9bcb3eef 1041 prefix_copy(&bmp->syncpos, bgp_dest_get_prefix(bn));
6c29258c
YO
1042 }
1043
ed18356f 1044 if (bmp->targets->afimon[afi][safi] & BMP_MON_POSTPOLICY) {
87102aa0 1045 for (bpiter = bgp_dest_get_bgp_path_info(bn); bpiter;
1046 bpiter = bpiter->next) {
ed18356f
DL
1047 if (!CHECK_FLAG(bpiter->flags, BGP_PATH_VALID))
1048 continue;
1049 if (bpiter->peer->qobj_node.nid
1050 <= bmp->syncpeerid)
1051 continue;
1052 if (bpi && bpiter->peer->qobj_node.nid
1053 > bpi->peer->qobj_node.nid)
1054 continue;
1055 bpi = bpiter;
1056 }
1057 }
1058 if (bmp->targets->afimon[afi][safi] & BMP_MON_PREPOLICY) {
1059 for (adjiter = bn->adj_in; adjiter;
1060 adjiter = adjiter->next) {
1061 if (adjiter->peer->qobj_node.nid
1062 <= bmp->syncpeerid)
1063 continue;
1064 if (adjin && adjiter->peer->qobj_node.nid
1065 > adjin->peer->qobj_node.nid)
1066 continue;
1067 adjin = adjiter;
1068 }
1069 }
1070 if (bpi || adjin)
1071 break;
1072
1073 bn = NULL;
1074 } while (1);
1075
1076 if (adjin && bpi
1077 && adjin->peer->qobj_node.nid < bpi->peer->qobj_node.nid) {
1078 bpi = NULL;
1079 bmp->syncpeerid = adjin->peer->qobj_node.nid;
1080 } else if (adjin && bpi
1081 && adjin->peer->qobj_node.nid > bpi->peer->qobj_node.nid) {
1082 adjin = NULL;
1083 bmp->syncpeerid = bpi->peer->qobj_node.nid;
1084 } else if (bpi) {
1085 bmp->syncpeerid = bpi->peer->qobj_node.nid;
1086 } else if (adjin) {
1087 bmp->syncpeerid = adjin->peer->qobj_node.nid;
1088 }
6c29258c 1089
9bcb3eef 1090 const struct prefix *bn_p = bgp_dest_get_prefix(bn);
87102aa0 1091 struct prefix_rd *prd = NULL;
1092 if (afi == AFI_L2VPN && safi == SAFI_EVPN)
1093 prd = (struct prefix_rd *)bgp_dest_get_prefix(bmp->syncrdpos);
b54892e0 1094
ed18356f 1095 if (bpi)
87102aa0 1096 bmp_monitor(bmp, bpi->peer, BMP_PEER_FLAG_L, bn_p, prd,
1097 bpi->attr, afi, safi, bpi->uptime);
ed18356f 1098 if (adjin)
87102aa0 1099 bmp_monitor(bmp, adjin->peer, 0, bn_p, prd, adjin->attr, afi,
1100 safi, adjin->uptime);
6c29258c 1101
ed18356f 1102 return true;
6c29258c
YO
1103}
1104
ed18356f 1105static struct bmp_queue_entry *bmp_pull(struct bmp *bmp)
6c29258c 1106{
ed18356f
DL
1107 struct bmp_queue_entry *bqe;
1108
1109 bqe = bmp->queuepos;
1110 if (!bqe)
1111 return NULL;
1112
1113 bmp->queuepos = bmp_qlist_next(&bmp->targets->updlist, bqe);
1114
1115 bqe->refcount--;
1116 if (!bqe->refcount) {
1117 bmp_qhash_del(&bmp->targets->updhash, bqe);
1118 bmp_qlist_del(&bmp->targets->updlist, bqe);
1119 }
1120 return bqe;
1121}
1122
1123static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr)
1124{
1125 struct bmp_queue_entry *bqe;
1126 struct peer *peer;
9bcb3eef 1127 struct bgp_dest *bn;
ed18356f
DL
1128 bool written = false;
1129
1130 bqe = bmp_pull(bmp);
1131 if (!bqe)
1132 return false;
1133
1134 afi_t afi = bqe->afi;
1135 safi_t safi = bqe->safi;
1136
1137 switch (bmp->afistate[afi][safi]) {
1138 case BMP_AFI_INACTIVE:
1139 case BMP_AFI_NEEDSYNC:
1140 goto out;
1141 case BMP_AFI_SYNC:
1142 if (prefix_cmp(&bqe->p, &bmp->syncpos) <= 0)
1143 /* currently syncing but have already passed this
1144 * prefix => send it. */
1145 break;
1146
1147 /* currently syncing & haven't reached this prefix yet
1148 * => it'll be sent as part of the table sync, no need here */
1149 goto out;
1150 case BMP_AFI_LIVE:
1151 break;
1152 }
1153
1154 peer = QOBJ_GET_TYPESAFE(bqe->peerid, peer);
1155 if (!peer) {
1156 zlog_info("bmp: skipping queued item for deleted peer");
1157 goto out;
1158 }
feb17238 1159 if (!peer_established(peer))
ed18356f
DL
1160 goto out;
1161
1162 bn = bgp_node_lookup(bmp->targets->bgp->rib[afi][safi], &bqe->p);
87102aa0 1163 struct prefix_rd *prd = NULL;
1164 if (bqe->afi == AFI_L2VPN && bqe->safi == SAFI_EVPN)
1165 prd = &bqe->rd;
ed18356f
DL
1166
1167 if (bmp->targets->afimon[afi][safi] & BMP_MON_POSTPOLICY) {
1168 struct bgp_path_info *bpi;
1169
87102aa0 1170 for (bpi = bn ? bgp_dest_get_bgp_path_info(bn) : NULL; bpi;
1171 bpi = bpi->next) {
ed18356f
DL
1172 if (!CHECK_FLAG(bpi->flags, BGP_PATH_VALID))
1173 continue;
1174 if (bpi->peer == peer)
1175 break;
1176 }
1177
87102aa0 1178 bmp_monitor(bmp, peer, BMP_PEER_FLAG_L, &bqe->p, prd,
ed18356f
DL
1179 bpi ? bpi->attr : NULL, afi, safi,
1180 bpi ? bpi->uptime : monotime(NULL));
1181 written = true;
1182 }
1183
1184 if (bmp->targets->afimon[afi][safi] & BMP_MON_PREPOLICY) {
1185 struct bgp_adj_in *adjin;
1186
1187 for (adjin = bn ? bn->adj_in : NULL; adjin;
1188 adjin = adjin->next) {
1189 if (adjin->peer == peer)
1190 break;
1191 }
87102aa0 1192 bmp_monitor(bmp, peer, BMP_PEER_FLAG_L, &bqe->p, prd,
ed18356f
DL
1193 adjin ? adjin->attr : NULL, afi, safi,
1194 adjin ? adjin->uptime : monotime(NULL));
1195 written = true;
1196 }
1197
1198out:
1199 if (!bqe->refcount)
1200 XFREE(MTYPE_BMP_QUEUE, bqe);
1201 return written;
1202}
1203
1204static void bmp_wrfill(struct bmp *bmp, struct pullwr *pullwr)
1205{
1206 switch(bmp->state) {
1207 case BMP_PeerUp:
1208 bmp_send_peerup(bmp);
1209 bmp->state = BMP_Run;
1210 break;
1211
1212 case BMP_Run:
1213 if (bmp_wrmirror(bmp, pullwr))
1214 break;
1215 if (bmp_wrqueue(bmp, pullwr))
1216 break;
1217 if (bmp_wrsync(bmp, pullwr))
1218 break;
1219 break;
1220 }
1221}
1222
1223static void bmp_wrerr(struct bmp *bmp, struct pullwr *pullwr, bool eof)
1224{
1225 if (eof)
1226 zlog_info("bmp[%s] disconnected", bmp->remote);
1227 else
1228 flog_warn(EC_LIB_SYSTEM_CALL, "bmp[%s] connection error: %s",
1229 bmp->remote, strerror(errno));
1230
1231 bmp_close(bmp);
1232 bmp_free(bmp);
1233}
1234
9bcb3eef
DS
1235static void bmp_process_one(struct bmp_targets *bt, struct bgp *bgp, afi_t afi,
1236 safi_t safi, struct bgp_dest *bn, struct peer *peer)
ed18356f
DL
1237{
1238 struct bmp *bmp;
1239 struct bmp_queue_entry *bqe, bqeref;
1240 size_t refcount;
ed18356f
DL
1241
1242 refcount = bmp_session_count(&bt->sessions);
1243 if (refcount == 0)
1244 return;
1245
1246 memset(&bqeref, 0, sizeof(bqeref));
9bcb3eef 1247 prefix_copy(&bqeref.p, bgp_dest_get_prefix(bn));
ed18356f
DL
1248 bqeref.peerid = peer->qobj_node.nid;
1249 bqeref.afi = afi;
1250 bqeref.safi = safi;
1251
87102aa0 1252 if (afi == AFI_L2VPN && safi == SAFI_EVPN && bn->pdest)
1253 prefix_copy(&bqeref.rd,
1254 (struct prefix_rd *)bgp_dest_get_prefix(bn->pdest));
1255
ed18356f
DL
1256 bqe = bmp_qhash_find(&bt->updhash, &bqeref);
1257 if (bqe) {
1258 if (bqe->refcount >= refcount)
1259 /* nothing to do here */
1260 return;
1261
1262 bmp_qlist_del(&bt->updlist, bqe);
1263 } else {
1264 bqe = XMALLOC(MTYPE_BMP_QUEUE, sizeof(*bqe));
1265 memcpy(bqe, &bqeref, sizeof(*bqe));
1266
1267 bmp_qhash_add(&bt->updhash, bqe);
1268 }
1269
1270 bqe->refcount = refcount;
1271 bmp_qlist_add_tail(&bt->updlist, bqe);
1272
1273 frr_each (bmp_session, &bt->sessions, bmp)
1274 if (!bmp->queuepos)
1275 bmp->queuepos = bqe;
1276}
1277
1278static int bmp_process(struct bgp *bgp, afi_t afi, safi_t safi,
9bcb3eef 1279 struct bgp_dest *bn, struct peer *peer, bool withdraw)
ed18356f
DL
1280{
1281 struct bmp_bgp *bmpbgp = bmp_bgp_find(peer->bgp);
1282 struct bmp_targets *bt;
1283 struct bmp *bmp;
1284
e0302d7e
QY
1285 if (frrtrace_enabled(frr_bgp, bmp_process)) {
1286 char pfxprint[PREFIX2STR_BUFFER];
1287
1288 prefix2str(&bn->p, pfxprint, sizeof(pfxprint));
1289 frrtrace(5, frr_bgp, bmp_process, peer, pfxprint, afi, safi,
1290 withdraw);
1291 }
1292
ed18356f
DL
1293 if (!bmpbgp)
1294 return 0;
1295
1296 frr_each(bmp_targets, &bmpbgp->targets, bt) {
1297 if (!bt->afimon[afi][safi])
1298 continue;
1299
1300 bmp_process_one(bt, bgp, afi, safi, bn, peer);
1301
1302 frr_each(bmp_session, &bt->sessions, bmp) {
1303 pullwr_bump(bmp->pullwr);
1304 }
1305 }
1306 return 0;
1307}
1308
1309static void bmp_stat_put_u32(struct stream *s, size_t *cnt, uint16_t type,
1310 uint32_t value)
1311{
1312 stream_putw(s, type);
1313 stream_putw(s, 4);
1314 stream_putl(s, value);
1315 (*cnt)++;
1316}
1317
cc9f21da 1318static void bmp_stats(struct thread *thread)
ed18356f
DL
1319{
1320 struct bmp_targets *bt = THREAD_ARG(thread);
1321 struct stream *s;
1322 struct peer *peer;
1323 struct listnode *node;
1324 struct timeval tv;
1325
1326 if (bt->stat_msec)
1327 thread_add_timer_msec(bm->master, bmp_stats, bt, bt->stat_msec,
1328 &bt->t_stats);
1329
1330 gettimeofday(&tv, NULL);
1331
1332 /* Walk down all peers */
1333 for (ALL_LIST_ELEMENTS_RO(bt->bgp->peer, node, peer)) {
1334 size_t count = 0, count_pos, len;
1335
feb17238 1336 if (!peer_established(peer))
ed18356f
DL
1337 continue;
1338
1339 s = stream_new(BGP_MAX_PACKET_SIZE);
1340 bmp_common_hdr(s, BMP_VERSION_3, BMP_TYPE_STATISTICS_REPORT);
1341 bmp_per_peer_hdr(s, peer, 0, &tv);
1342
1343 count_pos = stream_get_endp(s);
1344 stream_putl(s, 0);
1345
1346 bmp_stat_put_u32(s, &count, BMP_STATS_PFX_REJECTED,
1347 peer->stat_pfx_filter);
1348 bmp_stat_put_u32(s, &count, BMP_STATS_UPD_LOOP_ASPATH,
1349 peer->stat_pfx_aspath_loop);
1350 bmp_stat_put_u32(s, &count, BMP_STATS_UPD_LOOP_ORIGINATOR,
1351 peer->stat_pfx_originator_loop);
1352 bmp_stat_put_u32(s, &count, BMP_STATS_UPD_LOOP_CLUSTER,
1353 peer->stat_pfx_cluster_loop);
1354 bmp_stat_put_u32(s, &count, BMP_STATS_PFX_DUP_WITHDRAW,
1355 peer->stat_pfx_dup_withdraw);
1356 bmp_stat_put_u32(s, &count, BMP_STATS_UPD_7606_WITHDRAW,
1357 peer->stat_upd_7606);
1358 bmp_stat_put_u32(s, &count, BMP_STATS_FRR_NH_INVALID,
1359 peer->stat_pfx_nh_invalid);
1360
1361 stream_putl_at(s, count_pos, count);
1362
1363 len = stream_get_endp(s);
1364 stream_putl_at(s, BMP_LENGTH_POS, len);
1365
1366 bmp_send_all(bt->bmpbgp, s);
1367 }
ed18356f
DL
1368}
1369
8252b477 1370/* read from the BMP socket to detect session termination */
cc9f21da 1371static void bmp_read(struct thread *t)
8252b477
AL
1372{
1373 struct bmp *bmp = THREAD_ARG(t);
1374 char buf[1024];
1375 ssize_t n;
1376
1377 bmp->t_read = NULL;
1378
1379 n = read(bmp->socket, buf, sizeof(buf));
1380 if (n >= 1) {
1381 zlog_info("bmp[%s]: unexpectedly received %zu bytes", bmp->remote, n);
1382 } else if (n == 0) {
1383 /* the TCP session was terminated by the far end */
1384 bmp_wrerr(bmp, NULL, true);
cc9f21da 1385 return;
8252b477
AL
1386 } else if (!(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)) {
1387 /* the TCP session experienced a fatal error, likely a timeout */
1388 bmp_wrerr(bmp, NULL, false);
cc9f21da 1389 return;
8252b477
AL
1390 }
1391
1392 thread_add_read(bm->master, bmp_read, bmp, bmp->socket, &bmp->t_read);
8252b477
AL
1393}
1394
ed18356f
DL
1395static struct bmp *bmp_open(struct bmp_targets *bt, int bmp_sock)
1396{
1397 union sockunion su, *sumem;
1398 struct prefix p;
1399 int on = 1;
1400 struct access_list *acl = NULL;
1401 enum filter_type ret;
1402 char buf[SU_ADDRSTRLEN];
1403 struct bmp *bmp;
1404
1405 sumem = sockunion_getpeername(bmp_sock);
1406 if (!sumem) {
1407 close(bmp_sock);
1408 return NULL;
1409 }
1410 memcpy(&su, sumem, sizeof(su));
1411 sockunion_free(sumem);
1412
1413 set_nonblocking(bmp_sock);
1414 set_cloexec(bmp_sock);
ed18356f 1415
0154d8ce
DS
1416 if (!sockunion2hostprefix(&su, &p)) {
1417 close(bmp_sock);
1418 return NULL;
1419 }
ed18356f
DL
1420
1421 acl = NULL;
1422 switch (p.family) {
1423 case AF_INET:
1424 acl = access_list_lookup(AFI_IP, bt->acl_name);
1425 break;
1426 case AF_INET6:
1427 acl = access_list_lookup(AFI_IP6, bt->acl6_name);
1428 break;
1429 default:
1430 break;
1431 }
1432
1433 ret = FILTER_PERMIT;
1434 if (acl) {
1435 ret = access_list_apply(acl, &p);
1436 }
1437
1438 sockunion2str(&su, buf, SU_ADDRSTRLEN);
1439 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ":%u",
1440 su.sa.sa_family == AF_INET
1441 ? ntohs(su.sin.sin_port)
1442 : ntohs(su.sin6.sin6_port));
1443
1444 if (ret == FILTER_DENY) {
1445 bt->cnt_aclrefused++;
1446 zlog_info("bmp[%s] connection refused by access-list", buf);
1447 close(bmp_sock);
1448 return NULL;
1449 }
1450 bt->cnt_accept++;
1451
d38c6bb1
DS
1452 if (setsockopt(bmp_sock, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) < 0)
1453 flog_err(EC_LIB_SOCKET, "bmp: %d can't setsockopt SO_KEEPALIVE: %s(%d)",
1454 bmp_sock, safe_strerror(errno), errno);
1455 if (setsockopt(bmp_sock, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0)
1456 flog_err(EC_LIB_SOCKET, "bmp: %d can't setsockopt TCP_NODELAY: %s(%d)",
1457 bmp_sock, safe_strerror(errno), errno);
ed18356f
DL
1458
1459 zlog_info("bmp[%s] connection established", buf);
1460
1461 /* Allocate new BMP structure and set up default values. */
1462 bmp = bmp_new(bt, bmp_sock);
1463 strlcpy(bmp->remote, buf, sizeof(bmp->remote));
1464
1465 bmp->state = BMP_PeerUp;
1466 bmp->pullwr = pullwr_new(bm->master, bmp_sock, bmp, bmp_wrfill,
1467 bmp_wrerr);
8252b477 1468 thread_add_read(bm->master, bmp_read, bmp, bmp_sock, &bmp->t_read);
ed18356f
DL
1469 bmp_send_initiation(bmp);
1470
1471 return bmp;
1472}
1473
1474/* Accept BMP connection. */
cc9f21da 1475static void bmp_accept(struct thread *thread)
ed18356f
DL
1476{
1477 union sockunion su;
1478 struct bmp_listener *bl = THREAD_ARG(thread);
1479 int bmp_sock;
1480
1481 /* We continue hearing BMP socket. */
1482 thread_add_read(bm->master, bmp_accept, bl, bl->sock, &bl->t_accept);
1483
1484 memset(&su, 0, sizeof(union sockunion));
1485
1486 /* We can handle IPv4 or IPv6 socket. */
1487 bmp_sock = sockunion_accept(bl->sock, &su);
1488 if (bmp_sock < 0) {
63efca0e 1489 zlog_info("bmp: accept_sock failed: %s", safe_strerror(errno));
cc9f21da 1490 return;
ed18356f
DL
1491 }
1492 bmp_open(bl->targets, bmp_sock);
ed18356f
DL
1493}
1494
1495static void bmp_close(struct bmp *bmp)
1496{
1497 struct bmp_queue_entry *bqe;
1498 struct bmp_mirrorq *bmq;
1499
8252b477
AL
1500 THREAD_OFF(bmp->t_read);
1501
ed18356f
DL
1502 if (bmp->active)
1503 bmp_active_disconnected(bmp->active);
1504
1505 while ((bmq = bmp_pull_mirror(bmp)))
1506 if (!bmq->refcount)
1507 XFREE(MTYPE_BMP_MIRRORQ, bmq);
1508 while ((bqe = bmp_pull(bmp)))
1509 if (!bqe->refcount)
1510 XFREE(MTYPE_BMP_QUEUE, bqe);
1511
1512 THREAD_OFF(bmp->t_read);
1513 pullwr_del(bmp->pullwr);
1514 close(bmp->socket);
1515}
1516
1517static struct bmp_bgp *bmp_bgp_find(struct bgp *bgp)
1518{
1519 struct bmp_bgp dummy = { .bgp = bgp };
1520 return bmp_bgph_find(&bmp_bgph, &dummy);
1521}
1522
1523static struct bmp_bgp *bmp_bgp_get(struct bgp *bgp)
1524{
1525 struct bmp_bgp *bmpbgp;
1526
1527 bmpbgp = bmp_bgp_find(bgp);
1528 if (bmpbgp)
1529 return bmpbgp;
1530
1531 bmpbgp = XCALLOC(MTYPE_BMP, sizeof(*bmpbgp));
1532 bmpbgp->bgp = bgp;
1533 bmpbgp->mirror_qsizelimit = ~0UL;
1534 bmp_mirrorq_init(&bmpbgp->mirrorq);
1535 bmp_bgph_add(&bmp_bgph, bmpbgp);
1536
1537 return bmpbgp;
1538}
1539
1540static void bmp_bgp_put(struct bmp_bgp *bmpbgp)
1541{
1542 struct bmp_targets *bt;
1543
1544 bmp_bgph_del(&bmp_bgph, bmpbgp);
1545
1546 frr_each_safe(bmp_targets, &bmpbgp->targets, bt)
1547 bmp_targets_put(bt);
1548
1549 bmp_mirrorq_fini(&bmpbgp->mirrorq);
1550 XFREE(MTYPE_BMP, bmpbgp);
1551}
1552
1553static int bmp_bgp_del(struct bgp *bgp)
1554{
1555 struct bmp_bgp *bmpbgp = bmp_bgp_find(bgp);
1556
1557 if (bmpbgp)
1558 bmp_bgp_put(bmpbgp);
1559 return 0;
1560}
1561
1562static struct bmp_bgp_peer *bmp_bgp_peer_find(uint64_t peerid)
1563{
1564 struct bmp_bgp_peer dummy = { .peerid = peerid };
1565 return bmp_peerh_find(&bmp_peerh, &dummy);
1566}
1567
1568static struct bmp_bgp_peer *bmp_bgp_peer_get(struct peer *peer)
1569{
1570 struct bmp_bgp_peer *bbpeer;
1571
1572 bbpeer = bmp_bgp_peer_find(peer->qobj_node.nid);
1573 if (bbpeer)
1574 return bbpeer;
1575
1576 bbpeer = XCALLOC(MTYPE_BMP_PEER, sizeof(*bbpeer));
1577 bbpeer->peerid = peer->qobj_node.nid;
1578 bmp_peerh_add(&bmp_peerh, bbpeer);
1579
1580 return bbpeer;
1581}
1582
1583static struct bmp_targets *bmp_targets_find1(struct bgp *bgp, const char *name)
1584{
1585 struct bmp_bgp *bmpbgp = bmp_bgp_find(bgp);
1586 struct bmp_targets dummy;
1587
1588 if (!bmpbgp)
1589 return NULL;
1590 dummy.name = (char *)name;
1591 return bmp_targets_find(&bmpbgp->targets, &dummy);
1592}
1593
1594static struct bmp_targets *bmp_targets_get(struct bgp *bgp, const char *name)
1595{
1596 struct bmp_targets *bt;
1597
1598 bt = bmp_targets_find1(bgp, name);
1599 if (bt)
1600 return bt;
1601
1602 bt = XCALLOC(MTYPE_BMP_TARGETS, sizeof(*bt));
1603 bt->name = XSTRDUP(MTYPE_BMP_TARGETSNAME, name);
1604 bt->bgp = bgp;
1605 bt->bmpbgp = bmp_bgp_get(bgp);
1606 bmp_session_init(&bt->sessions);
1607 bmp_qhash_init(&bt->updhash);
1608 bmp_qlist_init(&bt->updlist);
1609 bmp_actives_init(&bt->actives);
1610 bmp_listeners_init(&bt->listeners);
1611
1612 QOBJ_REG(bt, bmp_targets);
1613 bmp_targets_add(&bt->bmpbgp->targets, bt);
1614 return bt;
1615}
1616
1617static void bmp_targets_put(struct bmp_targets *bt)
1618{
1619 struct bmp *bmp;
1620 struct bmp_active *ba;
1621
4008aa1a
DA
1622 THREAD_OFF(bt->t_stats);
1623
ed18356f
DL
1624 frr_each_safe (bmp_actives, &bt->actives, ba)
1625 bmp_active_put(ba);
1626
1627 frr_each_safe(bmp_session, &bt->sessions, bmp) {
1628 bmp_close(bmp);
1629 bmp_free(bmp);
1630 }
1631
1632 bmp_targets_del(&bt->bmpbgp->targets, bt);
1633 QOBJ_UNREG(bt);
1634
1635 bmp_listeners_fini(&bt->listeners);
1636 bmp_actives_fini(&bt->actives);
1637 bmp_qhash_fini(&bt->updhash);
1638 bmp_qlist_fini(&bt->updlist);
1639
1640 XFREE(MTYPE_BMP_ACLNAME, bt->acl_name);
1641 XFREE(MTYPE_BMP_ACLNAME, bt->acl6_name);
1642 bmp_session_fini(&bt->sessions);
1643
1644 XFREE(MTYPE_BMP_TARGETSNAME, bt->name);
1645 XFREE(MTYPE_BMP_TARGETS, bt);
1646}
1647
1648static struct bmp_listener *bmp_listener_find(struct bmp_targets *bt,
1649 const union sockunion *su,
1650 int port)
1651{
1652 struct bmp_listener dummy;
1653 dummy.addr = *su;
1654 dummy.port = port;
1655 return bmp_listeners_find(&bt->listeners, &dummy);
1656}
1657
1658static struct bmp_listener *bmp_listener_get(struct bmp_targets *bt,
1659 const union sockunion *su,
1660 int port)
1661{
1662 struct bmp_listener *bl = bmp_listener_find(bt, su, port);
1663
1664 if (bl)
1665 return bl;
1666
1667 bl = XCALLOC(MTYPE_BMP_LISTENER, sizeof(*bl));
1668 bl->targets = bt;
1669 bl->addr = *su;
1670 bl->port = port;
1671 bl->sock = -1;
1672
1673 bmp_listeners_add(&bt->listeners, bl);
1674 return bl;
1675}
1676
1677static void bmp_listener_put(struct bmp_listener *bl)
1678{
1679 bmp_listeners_del(&bl->targets->listeners, bl);
1680 XFREE(MTYPE_BMP_LISTENER, bl);
1681}
1682
1683static void bmp_listener_start(struct bmp_listener *bl)
1684{
1685 int sock, ret;
1686
1687 sock = socket(bl->addr.sa.sa_family, SOCK_STREAM, 0);
1688 if (sock < 0)
1689 return;
1690
1691 sockopt_reuseaddr(sock);
1692 sockopt_reuseport(sock);
1693 sockopt_v6only(bl->addr.sa.sa_family, sock);
1694 set_cloexec(sock);
1695
1696 ret = sockunion_bind(sock, &bl->addr, bl->port, &bl->addr);
1697 if (ret < 0)
1698 goto out_sock;
1699
1700 ret = listen(sock, 3);
1701 if (ret < 0)
1702 goto out_sock;
1703
1704 bl->sock = sock;
1705 thread_add_read(bm->master, bmp_accept, bl, sock, &bl->t_accept);
1706 return;
1707out_sock:
1708 close(sock);
1709}
1710
1711static void bmp_listener_stop(struct bmp_listener *bl)
1712{
1713 THREAD_OFF(bl->t_accept);
1714
1715 if (bl->sock != -1)
1716 close(bl->sock);
1717 bl->sock = -1;
1718}
1719
1720static struct bmp_active *bmp_active_find(struct bmp_targets *bt,
1721 const char *hostname, int port)
1722{
1723 struct bmp_active dummy;
1724 dummy.hostname = (char *)hostname;
1725 dummy.port = port;
1726 return bmp_actives_find(&bt->actives, &dummy);
1727}
1728
1729static struct bmp_active *bmp_active_get(struct bmp_targets *bt,
1730 const char *hostname, int port)
1731{
1732 struct bmp_active *ba;
1733
1734 ba = bmp_active_find(bt, hostname, port);
1735 if (ba)
1736 return ba;
1737
1738 ba = XCALLOC(MTYPE_BMP_ACTIVE, sizeof(*ba));
1739 ba->targets = bt;
1740 ba->hostname = XSTRDUP(MTYPE_TMP, hostname);
1741 ba->port = port;
1742 ba->minretry = BMP_DFLT_MINRETRY;
1743 ba->maxretry = BMP_DFLT_MAXRETRY;
1744 ba->socket = -1;
1745
1746 bmp_actives_add(&bt->actives, ba);
1747 return ba;
1748}
1749
1750static void bmp_active_put(struct bmp_active *ba)
1751{
1752 THREAD_OFF(ba->t_timer);
1753 THREAD_OFF(ba->t_read);
1754 THREAD_OFF(ba->t_write);
1755
1756 bmp_actives_del(&ba->targets->actives, ba);
1757
1758 if (ba->bmp) {
1759 ba->bmp->active = NULL;
1760 bmp_close(ba->bmp);
1761 bmp_free(ba->bmp);
1762 }
1763 if (ba->socket != -1)
1764 close(ba->socket);
1765
1766 XFREE(MTYPE_TMP, ba->hostname);
1767 XFREE(MTYPE_BMP_ACTIVE, ba);
1768}
1769
1770static void bmp_active_setup(struct bmp_active *ba);
1771
1772static void bmp_active_connect(struct bmp_active *ba)
1773{
1774 enum connect_result res;
1775 char buf[SU_ADDRSTRLEN];
1776
1777 for (; ba->addrpos < ba->addrtotal; ba->addrpos++) {
1778 ba->socket = sockunion_socket(&ba->addrs[ba->addrpos]);
1779 if (ba->socket < 0) {
1780 zlog_warn("bmp[%s]: failed to create socket",
1781 ba->hostname);
1782 continue;
1783 }
c258527b 1784
ed18356f
DL
1785 set_nonblocking(ba->socket);
1786 res = sockunion_connect(ba->socket, &ba->addrs[ba->addrpos],
1787 htons(ba->port), 0);
1788 switch (res) {
1789 case connect_error:
1790 sockunion2str(&ba->addrs[ba->addrpos], buf,
1791 sizeof(buf));
1792 zlog_warn("bmp[%s]: failed to connect to %s:%d",
1793 ba->hostname, buf, ba->port);
1794 close(ba->socket);
1795 ba->socket = -1;
1796 continue;
1797 case connect_success:
1798 break;
1799 case connect_in_progress:
1800 bmp_active_setup(ba);
1801 return;
1802 }
1803 }
1804
1805 /* exhausted all addresses */
1806 ba->curretry += ba->curretry / 2;
1807 bmp_active_setup(ba);
1808}
1809
3286ca07
DL
1810static void bmp_active_resolved(struct resolver_query *resq, const char *errstr,
1811 int numaddrs, union sockunion *addr)
ed18356f
DL
1812{
1813 struct bmp_active *ba = container_of(resq, struct bmp_active, resq);
1814 unsigned i;
1815
1816 if (numaddrs <= 0) {
3286ca07
DL
1817 zlog_warn("bmp[%s]: hostname resolution failed: %s",
1818 ba->hostname, errstr);
1819 ba->last_err = errstr;
125dc952 1820 ba->curretry += ba->curretry / 2;
a3d04c32 1821 ba->addrpos = 0;
125dc952
DL
1822 ba->addrtotal = 0;
1823 bmp_active_setup(ba);
1824 return;
a3d04c32 1825 }
ed18356f 1826
125dc952
DL
1827 if (numaddrs > (int)array_size(ba->addrs))
1828 numaddrs = array_size(ba->addrs);
1829
1830 ba->addrpos = 0;
1831 ba->addrtotal = numaddrs;
1832 for (i = 0; i < ba->addrtotal; i++)
1833 memcpy(&ba->addrs[i], &addr[i], sizeof(ba->addrs[0]));
1834
ed18356f
DL
1835 bmp_active_connect(ba);
1836}
1837
cc9f21da 1838static void bmp_active_thread(struct thread *t)
ed18356f
DL
1839{
1840 struct bmp_active *ba = THREAD_ARG(t);
1841 socklen_t slen;
1842 int status, ret;
1843 char buf[SU_ADDRSTRLEN];
c742573b 1844 vrf_id_t vrf_id;
ed18356f
DL
1845
1846 /* all 3 end up here, though only timer or read+write are active
1847 * at a time */
1848 THREAD_OFF(ba->t_timer);
1849 THREAD_OFF(ba->t_read);
1850 THREAD_OFF(ba->t_write);
1851
3286ca07
DL
1852 ba->last_err = NULL;
1853
ed18356f 1854 if (ba->socket == -1) {
c742573b
PG
1855 /* get vrf_id */
1856 if (!ba->targets || !ba->targets->bgp)
1857 vrf_id = VRF_DEFAULT;
1858 else
1859 vrf_id = ba->targets->bgp->vrf_id;
1860 resolver_resolve(&ba->resq, AF_UNSPEC, vrf_id, ba->hostname,
ed18356f 1861 bmp_active_resolved);
cc9f21da 1862 return;
ed18356f
DL
1863 }
1864
1865 slen = sizeof(status);
1866 ret = getsockopt(ba->socket, SOL_SOCKET, SO_ERROR, (void *)&status,
1867 &slen);
1868
1869 sockunion2str(&ba->addrs[ba->addrpos], buf, sizeof(buf));
1870 if (ret < 0 || status != 0) {
3286ca07
DL
1871 ba->last_err = strerror(status);
1872 zlog_warn("bmp[%s]: failed to connect to %s:%d: %s",
1873 ba->hostname, buf, ba->port, ba->last_err);
ed18356f
DL
1874 goto out_next;
1875 }
1876
1877 zlog_warn("bmp[%s]: outbound connection to %s:%d",
1878 ba->hostname, buf, ba->port);
1879
1880 ba->bmp = bmp_open(ba->targets, ba->socket);
1881 if (!ba->bmp)
1882 goto out_next;
1883
1884 ba->bmp->active = ba;
1885 ba->socket = -1;
1886 ba->curretry = ba->minretry;
cc9f21da 1887 return;
ed18356f
DL
1888
1889out_next:
1890 close(ba->socket);
1891 ba->socket = -1;
1892 ba->addrpos++;
1893 bmp_active_connect(ba);
ed18356f
DL
1894}
1895
1896static void bmp_active_disconnected(struct bmp_active *ba)
1897{
1898 ba->bmp = NULL;
1899 bmp_active_setup(ba);
1900}
1901
1902static void bmp_active_setup(struct bmp_active *ba)
1903{
1904 THREAD_OFF(ba->t_timer);
1905 THREAD_OFF(ba->t_read);
1906 THREAD_OFF(ba->t_write);
1907
1908 if (ba->bmp)
1909 return;
1910 if (ba->resq.callback)
1911 return;
1912
1913 if (ba->curretry > ba->maxretry)
1914 ba->curretry = ba->maxretry;
1915
1916 if (ba->socket == -1)
1917 thread_add_timer_msec(bm->master, bmp_active_thread, ba,
1918 ba->curretry, &ba->t_timer);
1919 else {
1920 thread_add_read(bm->master, bmp_active_thread, ba, ba->socket,
1921 &ba->t_read);
1922 thread_add_write(bm->master, bmp_active_thread, ba, ba->socket,
1923 &ba->t_write);
1924 }
1925}
1926
62b346ee 1927static struct cmd_node bmp_node = {
f4b8291f 1928 .name = "bmp",
62b346ee 1929 .node = BMP_NODE,
24389580 1930 .parent_node = BGP_NODE,
62b346ee
DL
1931 .prompt = "%s(config-bgp-bmp)# "
1932};
ed18356f 1933
bbd747df
DA
1934static void bmp_targets_autocomplete(vector comps, struct cmd_token *token)
1935{
1936 struct bgp *bgp;
1937 struct bmp_targets *target;
1938 struct listnode *node;
1939
1940 for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp)) {
1941 struct bmp_bgp *bmpbgp = bmp_bgp_find(bgp);
1942
1943 if (!bmpbgp)
1944 continue;
1945
1946 frr_each_safe (bmp_targets, &bmpbgp->targets, target)
1947 vector_set(comps,
1948 XSTRDUP(MTYPE_COMPLETION, target->name));
1949 }
1950}
1951
1952static const struct cmd_variable_handler bmp_targets_var_handlers[] = {
1953 {.tokenname = "BMPTARGETS", .completions = bmp_targets_autocomplete},
1954 {.completions = NULL}};
1955
ed18356f
DL
1956#define BMP_STR "BGP Monitoring Protocol\n"
1957
1958#ifndef VTYSH_EXTRACT_PL
33a9e196 1959#include "bgpd/bgp_bmp_clippy.c"
ed18356f
DL
1960#endif
1961
1962DEFPY_NOSH(bmp_targets_main,
1963 bmp_targets_cmd,
1964 "bmp targets BMPTARGETS",
1965 BMP_STR
1966 "Create BMP target group\n"
1967 "Name of the BMP target group\n")
1968{
1969 VTY_DECLVAR_CONTEXT(bgp, bgp);
1970 struct bmp_targets *bt;
1971
1972 bt = bmp_targets_get(bgp, bmptargets);
1973
1974 VTY_PUSH_CONTEXT_SUB(BMP_NODE, bt);
1975 return CMD_SUCCESS;
1976}
1977
1978DEFPY(no_bmp_targets_main,
1979 no_bmp_targets_cmd,
1980 "no bmp targets BMPTARGETS",
1981 NO_STR
1982 BMP_STR
1983 "Delete BMP target group\n"
1984 "Name of the BMP target group\n")
1985{
1986 VTY_DECLVAR_CONTEXT(bgp, bgp);
1987 struct bmp_targets *bt;
1988
1989 bt = bmp_targets_find1(bgp, bmptargets);
1990 if (!bt) {
1991 vty_out(vty, "%% BMP target group not found\n");
1992 return CMD_WARNING;
1993 }
1994 bmp_targets_put(bt);
1995 return CMD_SUCCESS;
1996}
1997
1998DEFPY(bmp_listener_main,
1999 bmp_listener_cmd,
2000 "bmp listener <X:X::X:X|A.B.C.D> port (1-65535)",
2001 BMP_STR
2002 "Listen for inbound BMP connections\n"
2003 "IPv6 address to listen on\n"
2004 "IPv4 address to listen on\n"
2005 "TCP Port number\n"
2006 "TCP Port number\n")
2007{
2008 VTY_DECLVAR_CONTEXT_SUB(bmp_targets, bt);
2009 struct bmp_listener *bl;
2010
2011 bl = bmp_listener_get(bt, listener, port);
2012 if (bl->sock == -1)
2013 bmp_listener_start(bl);
2014
2015 return CMD_SUCCESS;
2016}
2017
2018DEFPY(no_bmp_listener_main,
2019 no_bmp_listener_cmd,
2020 "no bmp listener <X:X::X:X|A.B.C.D> port (1-65535)",
2021 NO_STR
2022 BMP_STR
2023 "Create BMP listener\n"
2024 "IPv6 address to listen on\n"
2025 "IPv4 address to listen on\n"
2026 "TCP Port number\n"
2027 "TCP Port number\n")
2028{
2029 VTY_DECLVAR_CONTEXT_SUB(bmp_targets, bt);
2030 struct bmp_listener *bl;
2031
2032 bl = bmp_listener_find(bt, listener, port);
2033 if (!bl) {
2034 vty_out(vty, "%% BMP listener not found\n");
2035 return CMD_WARNING;
2036 }
2037 bmp_listener_stop(bl);
2038 bmp_listener_put(bl);
2039 return CMD_SUCCESS;
2040}
2041
2042DEFPY(bmp_connect,
2043 bmp_connect_cmd,
3efd0893 2044 "[no] bmp connect HOSTNAME port (1-65535) {min-retry (100-86400000)|max-retry (100-86400000)}",
ed18356f
DL
2045 NO_STR
2046 BMP_STR
2047 "Actively establish connection to monitoring station\n"
2048 "Monitoring station hostname or address\n"
2049 "TCP port\n"
2050 "TCP port\n"
2051 "Minimum connection retry interval\n"
2052 "Minimum connection retry interval (milliseconds)\n"
2053 "Maximum connection retry interval\n"
2054 "Maximum connection retry interval (milliseconds)\n")
2055{
2056 VTY_DECLVAR_CONTEXT_SUB(bmp_targets, bt);
2057 struct bmp_active *ba;
2058
2059 if (no) {
2060 ba = bmp_active_find(bt, hostname, port);
2061 if (!ba) {
2062 vty_out(vty, "%% No such active connection found\n");
2063 return CMD_WARNING;
2064 }
2065 bmp_active_put(ba);
2066 return CMD_SUCCESS;
2067 }
2068
2069 ba = bmp_active_get(bt, hostname, port);
2070 if (min_retry_str)
2071 ba->minretry = min_retry;
2072 if (max_retry_str)
2073 ba->maxretry = max_retry;
2074 ba->curretry = ba->minretry;
2075 bmp_active_setup(ba);
2076
2077 return CMD_SUCCESS;
2078}
2079
2080DEFPY(bmp_acl,
2081 bmp_acl_cmd,
5c757689 2082 "[no] <ip|ipv6>$af access-list ACCESSLIST_NAME$access_list",
ed18356f
DL
2083 NO_STR
2084 IP_STR
2085 IPV6_STR
2086 "Access list to restrict BMP sessions\n"
2087 "Access list name\n")
2088{
2089 VTY_DECLVAR_CONTEXT_SUB(bmp_targets, bt);
2090 char **what;
2091
2092 if (no)
2093 access_list = NULL;
2094 if (!strcmp(af, "ipv6"))
2095 what = &bt->acl6_name;
2096 else
2097 what = &bt->acl_name;
2098
2099 XFREE(MTYPE_BMP_ACLNAME, *what);
2100 if (access_list)
2101 *what = XSTRDUP(MTYPE_BMP_ACLNAME, access_list);
2102
2103 return CMD_SUCCESS;
2104}
2105
2106DEFPY(bmp_stats_cfg,
2107 bmp_stats_cmd,
2108 "[no] bmp stats [interval (100-86400000)]",
2109 NO_STR
2110 BMP_STR
2111 "Send BMP statistics messages\n"
2112 "Specify BMP stats interval\n"
2113 "Interval (milliseconds) to send BMP Stats in\n")
2114{
2115 VTY_DECLVAR_CONTEXT_SUB(bmp_targets, bt);
2116
2117 THREAD_OFF(bt->t_stats);
2118 if (no)
2119 bt->stat_msec = 0;
2120 else if (interval_str)
2121 bt->stat_msec = interval;
2122 else
2123 bt->stat_msec = BMP_STAT_DEFAULT_TIMER;
2124
2125 if (bt->stat_msec)
2126 thread_add_timer_msec(bm->master, bmp_stats, bt, bt->stat_msec,
2127 &bt->t_stats);
2128 return CMD_SUCCESS;
2129}
2130
2131DEFPY(bmp_monitor_cfg,
2132 bmp_monitor_cmd,
87102aa0 2133 "[no] bmp monitor <ipv4|ipv6|l2vpn> <unicast|multicast|evpn> <pre-policy|post-policy>$policy",
ed18356f
DL
2134 NO_STR
2135 BMP_STR
2136 "Send BMP route monitoring messages\n"
87102aa0 2137 "Address Family\nAddress Family\nAddress Family\n"
2138 "Address Family\nAddress Family\nAddress Family\n"
ed18356f
DL
2139 "Send state before policy and filter processing\n"
2140 "Send state with policy and filters applied\n")
2141{
2142 int index = 0;
2143 uint8_t flag, prev;
2144 afi_t afi;
2145 safi_t safi;
2146
2147 VTY_DECLVAR_CONTEXT_SUB(bmp_targets, bt);
2148 struct bmp *bmp;
2149
2150 argv_find_and_parse_afi(argv, argc, &index, &afi);
2151 argv_find_and_parse_safi(argv, argc, &index, &safi);
2152
2153 if (policy[1] == 'r')
2154 flag = BMP_MON_PREPOLICY;
2155 else
2156 flag = BMP_MON_POSTPOLICY;
2157
2158 prev = bt->afimon[afi][safi];
2159 if (no)
2160 bt->afimon[afi][safi] &= ~flag;
2161 else
2162 bt->afimon[afi][safi] |= flag;
2163
2164 if (prev == bt->afimon[afi][safi])
2165 return CMD_SUCCESS;
2166
2167 frr_each (bmp_session, &bt->sessions, bmp) {
2168 if (bmp->syncafi == afi && bmp->syncsafi == safi) {
2169 bmp->syncafi = AFI_MAX;
2170 bmp->syncsafi = SAFI_MAX;
2171 }
2172
2173 if (!bt->afimon[afi][safi]) {
2174 bmp->afistate[afi][safi] = BMP_AFI_INACTIVE;
2175 continue;
2176 }
2177
2178 bmp->afistate[afi][safi] = BMP_AFI_NEEDSYNC;
2179 }
2180
2181 return CMD_SUCCESS;
2182}
2183
2184DEFPY(bmp_mirror_cfg,
2185 bmp_mirror_cmd,
2186 "[no] bmp mirror",
2187 NO_STR
2188 BMP_STR
2189 "Send BMP route mirroring messages\n")
2190{
2191 VTY_DECLVAR_CONTEXT_SUB(bmp_targets, bt);
2192 struct bmp *bmp;
2193
2194 if (bt->mirror == !no)
2195 return CMD_SUCCESS;
2196
2197 bt->mirror = !no;
2198 if (bt->mirror)
2199 return CMD_SUCCESS;
2200
2201 frr_each (bmp_session, &bt->sessions, bmp) {
2202 struct bmp_mirrorq *bmq;
2203
2204 while ((bmq = bmp_pull_mirror(bmp)))
2205 if (!bmq->refcount)
2206 XFREE(MTYPE_BMP_MIRRORQ, bmq);
2207 }
2208 return CMD_SUCCESS;
2209}
2210
2211DEFPY(bmp_mirror_limit_cfg,
2212 bmp_mirror_limit_cmd,
2213 "bmp mirror buffer-limit (0-4294967294)",
2214 BMP_STR
2215 "Route Mirroring settings\n"
2216 "Configure maximum memory used for buffered mirroring messages\n"
2217 "Limit in bytes\n")
2218{
2219 VTY_DECLVAR_CONTEXT(bgp, bgp);
2220 struct bmp_bgp *bmpbgp;
2221
2222 bmpbgp = bmp_bgp_get(bgp);
2223 bmpbgp->mirror_qsizelimit = buffer_limit;
2224
2225 return CMD_SUCCESS;
2226}
2227
2228DEFPY(no_bmp_mirror_limit_cfg,
2229 no_bmp_mirror_limit_cmd,
2230 "no bmp mirror buffer-limit [(0-4294967294)]",
2231 NO_STR
2232 BMP_STR
2233 "Route Mirroring settings\n"
2234 "Configure maximum memory used for buffered mirroring messages\n"
2235 "Limit in bytes\n")
2236{
2237 VTY_DECLVAR_CONTEXT(bgp, bgp);
2238 struct bmp_bgp *bmpbgp;
2239
2240 bmpbgp = bmp_bgp_get(bgp);
2241 bmpbgp->mirror_qsizelimit = ~0UL;
2242
2243 return CMD_SUCCESS;
2244}
2245
2246
2247DEFPY(show_bmp,
2248 show_bmp_cmd,
2249 "show bmp",
2250 SHOW_STR
2251 BMP_STR)
2252{
2253 struct bmp_bgp *bmpbgp;
2254 struct bmp_targets *bt;
2255 struct bmp_listener *bl;
150470da 2256 struct bmp_active *ba;
ed18356f
DL
2257 struct bmp *bmp;
2258 struct ttable *tt;
2259 char buf[SU_ADDRSTRLEN];
150470da
DL
2260 char uptime[BGP_UPTIME_LEN];
2261 char *out;
ed18356f
DL
2262
2263 frr_each(bmp_bgph, &bmp_bgph, bmpbgp) {
2264 vty_out(vty, "BMP state for BGP %s:\n\n",
2265 bmpbgp->bgp->name_pretty);
2266 vty_out(vty, " Route Mirroring %9zu bytes (%zu messages) pending\n",
2267 bmpbgp->mirror_qsize,
2268 bmp_mirrorq_count(&bmpbgp->mirrorq));
2269 vty_out(vty, " %9zu bytes maximum buffer used\n",
2270 bmpbgp->mirror_qsizemax);
2271 if (bmpbgp->mirror_qsizelimit != ~0UL)
2272 vty_out(vty, " %9zu bytes buffer size limit\n",
2273 bmpbgp->mirror_qsizelimit);
2274 vty_out(vty, "\n");
2275
2276 frr_each(bmp_targets, &bmpbgp->targets, bt) {
2277 vty_out(vty, " Targets \"%s\":\n", bt->name);
2278 vty_out(vty, " Route Mirroring %sabled\n",
2279 bt->mirror ? "en" : "dis");
2280
2281 afi_t afi;
2282 safi_t safi;
2283
2284 FOREACH_AFI_SAFI (afi, safi) {
2285 const char *str = NULL;
2286
2287 switch (bt->afimon[afi][safi]) {
2288 case BMP_MON_PREPOLICY:
2289 str = "pre-policy";
2290 break;
2291 case BMP_MON_POSTPOLICY:
2292 str = "post-policy";
2293 break;
2294 case BMP_MON_PREPOLICY | BMP_MON_POSTPOLICY:
2295 str = "pre-policy and post-policy";
2296 break;
2297 }
2298 if (!str)
2299 continue;
2300 vty_out(vty, " Route Monitoring %s %s %s\n",
2301 afi2str(afi), safi2str(safi), str);
2302 }
2303
2304 vty_out(vty, " Listeners:\n");
2305 frr_each (bmp_listeners, &bt->listeners, bl)
2306 vty_out(vty, " %s:%d\n",
2307 sockunion2str(&bl->addr, buf,
2308 SU_ADDRSTRLEN), bl->port);
2309
150470da
DL
2310 vty_out(vty, "\n Outbound connections:\n");
2311 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
2312 ttable_add_row(tt, "remote|state||timer");
2313 ttable_rowseps(tt, 0, BOTTOM, true, '-');
2314 frr_each (bmp_actives, &bt->actives, ba) {
2315 const char *state_str = "?";
2316
2317 if (ba->bmp) {
2318 peer_uptime(ba->bmp->t_up.tv_sec,
2319 uptime, sizeof(uptime),
2320 false, NULL);
2321 ttable_add_row(tt, "%s:%d|Up|%s|%s",
2322 ba->hostname, ba->port,
2323 ba->bmp->remote, uptime);
2324 continue;
2325 }
2326
2327 uptime[0] = '\0';
2328
2329 if (ba->t_timer) {
2330 long trem = thread_timer_remain_second(
2331 ba->t_timer);
2332
2333 peer_uptime(monotime(NULL) - trem,
2334 uptime, sizeof(uptime),
2335 false, NULL);
2336 state_str = "RetryWait";
2337 } else if (ba->t_read) {
2338 state_str = "Connecting";
2339 } else if (ba->resq.callback) {
2340 state_str = "Resolving";
2341 }
2342
2343 ttable_add_row(tt, "%s:%d|%s|%s|%s",
2344 ba->hostname, ba->port,
2345 state_str,
2346 ba->last_err ? ba->last_err : "",
2347 uptime);
2348 continue;
2349 }
2350 out = ttable_dump(tt, "\n");
2351 vty_out(vty, "%s", out);
2352 XFREE(MTYPE_TMP, out);
2353 ttable_del(tt);
2354
ed18356f
DL
2355 vty_out(vty, "\n %zu connected clients:\n",
2356 bmp_session_count(&bt->sessions));
2357 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
2358 ttable_add_row(tt, "remote|uptime|MonSent|MirrSent|MirrLost|ByteSent|ByteQ|ByteQKernel");
2359 ttable_rowseps(tt, 0, BOTTOM, true, '-');
2360
2361 frr_each (bmp_session, &bt->sessions, bmp) {
2362 uint64_t total;
2363 size_t q, kq;
2364
2365 pullwr_stats(bmp->pullwr, &total, &q, &kq);
2366
9e89da8c
DL
2367 peer_uptime(bmp->t_up.tv_sec, uptime,
2368 sizeof(uptime), false, NULL);
2369
2370 ttable_add_row(tt, "%s|%s|%Lu|%Lu|%Lu|%Lu|%zu|%zu",
2371 bmp->remote, uptime,
ed18356f
DL
2372 bmp->cnt_update,
2373 bmp->cnt_mirror,
2374 bmp->cnt_mirror_overruns,
2375 total, q, kq);
2376 }
150470da 2377 out = ttable_dump(tt, "\n");
ed18356f
DL
2378 vty_out(vty, "%s", out);
2379 XFREE(MTYPE_TMP, out);
2380 ttable_del(tt);
2381 vty_out(vty, "\n");
2382 }
2383 }
2384
2385 return CMD_SUCCESS;
2386}
2387
2388static int bmp_config_write(struct bgp *bgp, struct vty *vty)
2389{
2390 struct bmp_bgp *bmpbgp = bmp_bgp_find(bgp);
2391 struct bmp_targets *bt;
2392 struct bmp_listener *bl;
2393 struct bmp_active *ba;
2394 char buf[SU_ADDRSTRLEN];
2395 afi_t afi;
2396 safi_t safi;
2397
2398 if (!bmpbgp)
2399 return 0;
2400
2401 if (bmpbgp->mirror_qsizelimit != ~0UL)
2402 vty_out(vty, " !\n bmp mirror buffer-limit %zu\n",
2403 bmpbgp->mirror_qsizelimit);
2404
2405 frr_each(bmp_targets, &bmpbgp->targets, bt) {
2406 vty_out(vty, " !\n bmp targets %s\n", bt->name);
2407
2408 if (bt->acl6_name)
2409 vty_out(vty, " ipv6 access-list %s\n", bt->acl6_name);
2410 if (bt->acl_name)
2411 vty_out(vty, " ip access-list %s\n", bt->acl_name);
2412
2413 if (bt->stat_msec)
2414 vty_out(vty, " bmp stats interval %d\n",
2415 bt->stat_msec);
2416
2417 if (bt->mirror)
2418 vty_out(vty, " bmp mirror\n");
2419
2420 FOREACH_AFI_SAFI (afi, safi) {
2421 const char *afi_str = (afi == AFI_IP) ? "ipv4" : "ipv6";
2422
2423 if (bt->afimon[afi][safi] & BMP_MON_PREPOLICY)
2424 vty_out(vty, " bmp monitor %s %s pre-policy\n",
2425 afi_str, safi2str(safi));
2426 if (bt->afimon[afi][safi] & BMP_MON_POSTPOLICY)
2427 vty_out(vty, " bmp monitor %s %s post-policy\n",
2428 afi_str, safi2str(safi));
2429 }
2430 frr_each (bmp_listeners, &bt->listeners, bl)
2431 vty_out(vty, " \n bmp listener %s port %d\n",
2432 sockunion2str(&bl->addr, buf, SU_ADDRSTRLEN),
2433 bl->port);
2434
2435 frr_each (bmp_actives, &bt->actives, ba)
2436 vty_out(vty, " bmp connect %s port %u min-retry %u max-retry %u\n",
2437 ba->hostname, ba->port, ba->minretry, ba->maxretry);
07679ad9
IR
2438
2439 vty_out(vty, " exit\n");
ed18356f
DL
2440 }
2441
2442 return 0;
2443}
2444
2445static int bgp_bmp_init(struct thread_master *tm)
2446{
612c2c15 2447 install_node(&bmp_node);
ed18356f 2448 install_default(BMP_NODE);
bbd747df
DA
2449
2450 cmd_variable_handler_register(bmp_targets_var_handlers);
2451
ed18356f
DL
2452 install_element(BGP_NODE, &bmp_targets_cmd);
2453 install_element(BGP_NODE, &no_bmp_targets_cmd);
2454
2455 install_element(BMP_NODE, &bmp_listener_cmd);
2456 install_element(BMP_NODE, &no_bmp_listener_cmd);
2457 install_element(BMP_NODE, &bmp_connect_cmd);
2458 install_element(BMP_NODE, &bmp_acl_cmd);
2459 install_element(BMP_NODE, &bmp_stats_cmd);
2460 install_element(BMP_NODE, &bmp_monitor_cmd);
2461 install_element(BMP_NODE, &bmp_mirror_cmd);
2462
2463 install_element(BGP_NODE, &bmp_mirror_limit_cmd);
2464 install_element(BGP_NODE, &no_bmp_mirror_limit_cmd);
2465
2466 install_element(VIEW_NODE, &show_bmp_cmd);
2467
2468 resolver_init(tm);
0ba4eeec 2469 return 0;
6c29258c
YO
2470}
2471
0ba4eeec
DL
2472static int bgp_bmp_module_init(void)
2473{
2474 hook_register(bgp_packet_dump, bmp_mirror_packet);
ed18356f 2475 hook_register(bgp_packet_send, bmp_outgoing_packet);
60563d0e 2476 hook_register(peer_status_changed, bmp_peer_status_changed);
ed18356f
DL
2477 hook_register(peer_backward_transition, bmp_peer_backward);
2478 hook_register(bgp_process, bmp_process);
2479 hook_register(bgp_inst_config_write, bmp_config_write);
2480 hook_register(bgp_inst_delete, bmp_bgp_del);
0ba4eeec
DL
2481 hook_register(frr_late_init, bgp_bmp_init);
2482 return 0;
2483}
6c29258c 2484
0ba4eeec
DL
2485FRR_MODULE_SETUP(.name = "bgpd_bmp", .version = FRR_VERSION,
2486 .description = "bgpd BMP module",
80413c20
DL
2487 .init = bgp_bmp_module_init,
2488);