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