]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_updgrp.c
Merge pull request #12795 from pguibert6WIND/vpnv6_nexthop_encoding
[mirror_frr.git] / bgpd / bgp_updgrp.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
3f9c7369
DS
2/**
3 * bgp_updgrp.c: BGP update group structures
4 *
5 * @copyright Copyright (C) 2014 Cumulus Networks, Inc.
6 *
7 * @author Avneesh Sachdev <avneesh@sproute.net>
8 * @author Rajesh Varadarajan <rajesh@sproute.net>
9 * @author Pradosh Mohapatra <pradosh@sproute.net>
3f9c7369
DS
10 */
11
12#include <zebra.h>
13
14#include "prefix.h"
15#include "thread.h"
16#include "buffer.h"
17#include "stream.h"
18#include "command.h"
19#include "sockunion.h"
20#include "network.h"
21#include "memory.h"
22#include "filter.h"
23#include "routemap.h"
3f9c7369
DS
24#include "log.h"
25#include "plist.h"
26#include "linklist.h"
27#include "workqueue.h"
28#include "hash.h"
29#include "jhash.h"
30#include "queue.h"
31
32#include "bgpd/bgpd.h"
33#include "bgpd/bgp_table.h"
34#include "bgpd/bgp_debug.h"
14454c9f 35#include "bgpd/bgp_errors.h"
3f9c7369 36#include "bgpd/bgp_fsm.h"
b1dd7180 37#include "bgpd/bgp_addpath.h"
3f9c7369
DS
38#include "bgpd/bgp_advertise.h"
39#include "bgpd/bgp_packet.h"
40#include "bgpd/bgp_updgrp.h"
41#include "bgpd/bgp_route.h"
42#include "bgpd/bgp_filter.h"
2fc102e1 43#include "bgpd/bgp_io.h"
3f9c7369
DS
44
45/********************
46 * PRIVATE FUNCTIONS
47 ********************/
48
49/**
50 * assign a unique ID to update group and subgroup. Mostly for display/
51 * debugging purposes. It's a 64-bit space - used leisurely without a
52 * worry about its wrapping and about filling gaps. While at it, timestamp
53 * the creation.
54 */
d62a17ae 55static void update_group_checkin(struct update_group *updgrp)
3f9c7369 56{
d62a17ae 57 updgrp->id = ++bm->updgrp_idspace;
083ec940 58 updgrp->uptime = monotime(NULL);
3f9c7369
DS
59}
60
d62a17ae 61static void update_subgroup_checkin(struct update_subgroup *subgrp,
62 struct update_group *updgrp)
3f9c7369 63{
d62a17ae 64 subgrp->id = ++bm->subgrp_idspace;
083ec940 65 subgrp->uptime = monotime(NULL);
3f9c7369
DS
66}
67
ef56aee4
DA
68static void sync_init(struct update_subgroup *subgrp,
69 struct update_group *updgrp)
3f9c7369 70{
ef56aee4
DA
71 struct peer *peer = UPDGRP_PEER(updgrp);
72
d62a17ae 73 subgrp->sync =
74 XCALLOC(MTYPE_BGP_SYNCHRONISE, sizeof(struct bgp_synchronize));
a274fef8
DL
75 bgp_adv_fifo_init(&subgrp->sync->update);
76 bgp_adv_fifo_init(&subgrp->sync->withdraw);
77 bgp_adv_fifo_init(&subgrp->sync->withdraw_low);
996c9314 78 subgrp->hash =
4d28080c
DA
79 hash_create(bgp_advertise_attr_hash_key,
80 bgp_advertise_attr_hash_cmp, "BGP SubGroup Hash");
d62a17ae 81
82 /* We use a larger buffer for subgrp->work in the event that:
83 * - We RX a BGP_UPDATE where the attributes alone are just
ef56aee4 84 * under 4096 or 65535 (if Extended Message capability negotiated).
d62a17ae 85 * - The user configures an outbound route-map that does many as-path
86 * prepends or adds many communities. At most they can have
87 * CMD_ARGC_MAX
88 * args in a route-map so there is a finite limit on how large they
89 * can
90 * make the attributes.
91 *
92 * Having a buffer with BGP_MAX_PACKET_SIZE_OVERFLOW allows us to avoid
93 * bounds
94 * checking for every single attribute as we construct an UPDATE.
95 */
ef56aee4
DA
96 subgrp->work = stream_new(peer->max_packet_size
97 + BGP_MAX_PACKET_SIZE_OVERFLOW);
98 subgrp->scratch = stream_new(peer->max_packet_size);
3f9c7369
DS
99}
100
d62a17ae 101static void sync_delete(struct update_subgroup *subgrp)
3f9c7369 102{
0a22ddfb 103 XFREE(MTYPE_BGP_SYNCHRONISE, subgrp->sync);
e92cf867 104 if (subgrp->hash) {
4d28080c
DA
105 hash_clean(subgrp->hash,
106 (void (*)(void *))bgp_advertise_attr_free);
d62a17ae 107 hash_free(subgrp->hash);
e92cf867 108 }
d62a17ae 109 subgrp->hash = NULL;
110 if (subgrp->work)
111 stream_free(subgrp->work);
112 subgrp->work = NULL;
113 if (subgrp->scratch)
114 stream_free(subgrp->scratch);
115 subgrp->scratch = NULL;
3f9c7369
DS
116}
117
118/**
119 * conf_copy
120 *
121 * copy only those fields that are relevant to update group match
122 */
d62a17ae 123static void conf_copy(struct peer *dst, struct peer *src, afi_t afi,
124 safi_t safi)
3f9c7369 125{
d62a17ae 126 struct bgp_filter *srcfilter;
127 struct bgp_filter *dstfilter;
128
129 srcfilter = &src->filter[afi][safi];
130 dstfilter = &dst->filter[afi][safi];
131
132 dst->bgp = src->bgp;
133 dst->sort = src->sort;
134 dst->as = src->as;
135 dst->v_routeadv = src->v_routeadv;
136 dst->flags = src->flags;
137 dst->af_flags[afi][safi] = src->af_flags[afi][safi];
fde246e8 138 dst->pmax_out[afi][safi] = src->pmax_out[afi][safi];
ef56aee4 139 dst->max_packet_size = src->max_packet_size;
0a22ddfb 140 XFREE(MTYPE_BGP_PEER_HOST, dst->host);
d62a17ae 141
142 dst->host = XSTRDUP(MTYPE_BGP_PEER_HOST, src->host);
143 dst->cap = src->cap;
144 dst->af_cap[afi][safi] = src->af_cap[afi][safi];
145 dst->afc_nego[afi][safi] = src->afc_nego[afi][safi];
146 dst->orf_plist[afi][safi] = src->orf_plist[afi][safi];
dcc68b5e 147 dst->addpath_type[afi][safi] = src->addpath_type[afi][safi];
d62a17ae 148 dst->local_as = src->local_as;
149 dst->change_local_as = src->change_local_as;
150 dst->shared_network = src->shared_network;
d864dd9e 151 dst->local_role = src->local_role;
25851bf0 152 dst->as_path_loop_detection = src->as_path_loop_detection;
01da2d26
DA
153
154 if (src->soo[afi][safi]) {
155 ecommunity_free(&dst->soo[afi][safi]);
156 dst->soo[afi][safi] = ecommunity_dup(src->soo[afi][safi]);
157 }
158
d62a17ae 159 memcpy(&(dst->nexthop), &(src->nexthop), sizeof(struct bgp_nexthop));
160
161 dst->group = src->group;
162
163 if (src->default_rmap[afi][safi].name) {
164 dst->default_rmap[afi][safi].name =
165 XSTRDUP(MTYPE_ROUTE_MAP_NAME,
166 src->default_rmap[afi][safi].name);
167 dst->default_rmap[afi][safi].map =
168 src->default_rmap[afi][safi].map;
169 }
170
171 if (DISTRIBUTE_OUT_NAME(srcfilter)) {
172 DISTRIBUTE_OUT_NAME(dstfilter) = XSTRDUP(
173 MTYPE_BGP_FILTER_NAME, DISTRIBUTE_OUT_NAME(srcfilter));
174 DISTRIBUTE_OUT(dstfilter) = DISTRIBUTE_OUT(srcfilter);
175 }
176
177 if (PREFIX_LIST_OUT_NAME(srcfilter)) {
178 PREFIX_LIST_OUT_NAME(dstfilter) = XSTRDUP(
179 MTYPE_BGP_FILTER_NAME, PREFIX_LIST_OUT_NAME(srcfilter));
180 PREFIX_LIST_OUT(dstfilter) = PREFIX_LIST_OUT(srcfilter);
181 }
182
183 if (FILTER_LIST_OUT_NAME(srcfilter)) {
184 FILTER_LIST_OUT_NAME(dstfilter) = XSTRDUP(
185 MTYPE_BGP_FILTER_NAME, FILTER_LIST_OUT_NAME(srcfilter));
186 FILTER_LIST_OUT(dstfilter) = FILTER_LIST_OUT(srcfilter);
187 }
188
189 if (ROUTE_MAP_OUT_NAME(srcfilter)) {
190 ROUTE_MAP_OUT_NAME(dstfilter) = XSTRDUP(
191 MTYPE_BGP_FILTER_NAME, ROUTE_MAP_OUT_NAME(srcfilter));
192 ROUTE_MAP_OUT(dstfilter) = ROUTE_MAP_OUT(srcfilter);
193 }
194
195 if (UNSUPPRESS_MAP_NAME(srcfilter)) {
196 UNSUPPRESS_MAP_NAME(dstfilter) = XSTRDUP(
197 MTYPE_BGP_FILTER_NAME, UNSUPPRESS_MAP_NAME(srcfilter));
198 UNSUPPRESS_MAP(dstfilter) = UNSUPPRESS_MAP(srcfilter);
199 }
7f7940e6
MK
200
201 if (ADVERTISE_MAP_NAME(srcfilter)) {
202 ADVERTISE_MAP_NAME(dstfilter) = XSTRDUP(
203 MTYPE_BGP_FILTER_NAME, ADVERTISE_MAP_NAME(srcfilter));
204 ADVERTISE_MAP(dstfilter) = ADVERTISE_MAP(srcfilter);
205 ADVERTISE_CONDITION(dstfilter) = ADVERTISE_CONDITION(srcfilter);
206 }
207
208 if (CONDITION_MAP_NAME(srcfilter)) {
209 CONDITION_MAP_NAME(dstfilter) = XSTRDUP(
210 MTYPE_BGP_FILTER_NAME, CONDITION_MAP_NAME(srcfilter));
211 CONDITION_MAP(dstfilter) = CONDITION_MAP(srcfilter);
212 }
f373ce6c
QY
213
214 dstfilter->advmap.update_type = srcfilter->advmap.update_type;
3f9c7369
DS
215}
216
217/**
6e919709 218 * since we did a bunch of XSTRDUP's in conf_copy, time to free them up
3f9c7369 219 */
d62a17ae 220static void conf_release(struct peer *src, afi_t afi, safi_t safi)
3f9c7369 221{
d62a17ae 222 struct bgp_filter *srcfilter;
3f9c7369 223
d62a17ae 224 srcfilter = &src->filter[afi][safi];
3f9c7369 225
0a22ddfb 226 XFREE(MTYPE_ROUTE_MAP_NAME, src->default_rmap[afi][safi].name);
3f9c7369 227
0a22ddfb 228 XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->dlist[FILTER_OUT].name);
3f9c7369 229
0a22ddfb 230 XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->plist[FILTER_OUT].name);
3f9c7369 231
0a22ddfb 232 XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->aslist[FILTER_OUT].name);
3f9c7369 233
0a22ddfb 234 XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->map[RMAP_OUT].name);
3f9c7369 235
0a22ddfb 236 XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->usmap.name);
495f0b13 237
7f7940e6
MK
238 XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->advmap.aname);
239
240 XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->advmap.cname);
241
0a22ddfb 242 XFREE(MTYPE_BGP_PEER_HOST, src->host);
61adcf71
DA
243
244 ecommunity_free(&src->soo[afi][safi]);
3f9c7369
DS
245}
246
d62a17ae 247static void peer2_updgrp_copy(struct update_group *updgrp, struct peer_af *paf)
3f9c7369 248{
d62a17ae 249 struct peer *src;
250 struct peer *dst;
3f9c7369 251
d62a17ae 252 if (!updgrp || !paf)
253 return;
3f9c7369 254
d62a17ae 255 src = paf->peer;
256 dst = updgrp->conf;
257 if (!src || !dst)
258 return;
3f9c7369 259
d62a17ae 260 updgrp->afi = paf->afi;
261 updgrp->safi = paf->safi;
262 updgrp->afid = paf->afid;
263 updgrp->bgp = src->bgp;
3f9c7369 264
d62a17ae 265 conf_copy(dst, src, paf->afi, paf->safi);
3f9c7369
DS
266}
267
268/**
269 * auxiliary functions to maintain the hash table.
270 * - updgrp_hash_alloc - to create a new entry, passed to hash_get
271 * - updgrp_hash_key_make - makes the key for update group search
272 * - updgrp_hash_cmp - compare two update groups.
273 */
d62a17ae 274static void *updgrp_hash_alloc(void *p)
3f9c7369 275{
d62a17ae 276 struct update_group *updgrp;
277 const struct update_group *in;
278
279 in = (const struct update_group *)p;
280 updgrp = XCALLOC(MTYPE_BGP_UPDGRP, sizeof(struct update_group));
281 memcpy(updgrp, in, sizeof(struct update_group));
282 updgrp->conf = XCALLOC(MTYPE_BGP_PEER, sizeof(struct peer));
283 conf_copy(updgrp->conf, in->conf, in->afi, in->safi);
284 return updgrp;
3f9c7369
DS
285}
286
287/**
288 * The hash value for a peer is computed from the following variables:
289 * v = f(
290 * 1. IBGP (1) or EBGP (2)
291 * 2. FLAGS based on configuration:
292 * LOCAL_AS_NO_PREPEND
293 * LOCAL_AS_REPLACE_AS
294 * 3. AF_FLAGS based on configuration:
295 * Refer to definition in bgp_updgrp.h
296 * 4. (AF-independent) Capability flags:
297 * AS4_RCV capability
298 * 5. (AF-dependent) Capability flags:
299 * ORF_PREFIX_SM_RCV (peer can send prefix ORF)
300 * 6. MRAI
301 * 7. peer-group name
302 * 8. Outbound route-map name (neighbor route-map <> out)
303 * 9. Outbound distribute-list name (neighbor distribute-list <> out)
304 * 10. Outbound prefix-list name (neighbor prefix-list <> out)
305 * 11. Outbound as-list name (neighbor filter-list <> out)
306 * 12. Unsuppress map name (neighbor unsuppress-map <>)
307 * 13. default rmap name (neighbor default-originate route-map <>)
308 * 14. encoding both global and link-local nexthop?
309 * 15. If peer is configured to be a lonesoul, peer ip address
310 * 16. Local-as should match, if configured.
e0267260 311 * 17. maximum-prefix-out
d864dd9e 312 * 18. Local-role should also match, if configured.
3f9c7369
DS
313 * )
314 */
d8b87afe 315static unsigned int updgrp_hash_key_make(const void *p)
3f9c7369 316{
d62a17ae 317 const struct update_group *updgrp;
318 const struct peer *peer;
319 const struct bgp_filter *filter;
320 uint32_t flags;
321 uint32_t key;
322 afi_t afi;
323 safi_t safi;
3f9c7369
DS
324
325#define SEED1 999331
326#define SEED2 2147483647
327
d62a17ae 328 updgrp = p;
329 peer = updgrp->conf;
330 afi = updgrp->afi;
331 safi = updgrp->safi;
332 flags = peer->af_flags[afi][safi];
333 filter = &peer->filter[afi][safi];
334
335 key = 0;
336
337 key = jhash_1word(peer->sort, key); /* EBGP or IBGP */
338 key = jhash_1word((peer->flags & PEER_UPDGRP_FLAGS), key);
339 key = jhash_1word((flags & PEER_UPDGRP_AF_FLAGS), key);
dcc68b5e 340 key = jhash_1word((uint32_t)peer->addpath_type[afi][safi], key);
d62a17ae 341 key = jhash_1word((peer->cap & PEER_UPDGRP_CAP_FLAGS), key);
342 key = jhash_1word((peer->af_cap[afi][safi] & PEER_UPDGRP_AF_CAP_FLAGS),
343 key);
344 key = jhash_1word(peer->v_routeadv, key);
345 key = jhash_1word(peer->change_local_as, key);
cecd7358 346 key = jhash_1word(peer->max_packet_size, key);
e0267260 347 key = jhash_1word(peer->pmax_out[afi][safi], key);
d62a17ae 348
25851bf0
DA
349 if (peer->as_path_loop_detection)
350 key = jhash_2words(peer->as, peer->as_path_loop_detection, key);
351
d62a17ae 352 if (peer->group)
353 key = jhash_1word(jhash(peer->group->name,
354 strlen(peer->group->name), SEED1),
355 key);
356
357 if (filter->map[RMAP_OUT].name)
358 key = jhash_1word(jhash(filter->map[RMAP_OUT].name,
359 strlen(filter->map[RMAP_OUT].name),
360 SEED1),
361 key);
362
363 if (filter->dlist[FILTER_OUT].name)
364 key = jhash_1word(jhash(filter->dlist[FILTER_OUT].name,
365 strlen(filter->dlist[FILTER_OUT].name),
366 SEED1),
367 key);
368
369 if (filter->plist[FILTER_OUT].name)
370 key = jhash_1word(jhash(filter->plist[FILTER_OUT].name,
371 strlen(filter->plist[FILTER_OUT].name),
372 SEED1),
373 key);
374
375 if (filter->aslist[FILTER_OUT].name)
376 key = jhash_1word(jhash(filter->aslist[FILTER_OUT].name,
377 strlen(filter->aslist[FILTER_OUT].name),
378 SEED1),
379 key);
380
381 if (filter->usmap.name)
382 key = jhash_1word(jhash(filter->usmap.name,
383 strlen(filter->usmap.name), SEED1),
384 key);
385
7f7940e6
MK
386 if (filter->advmap.aname)
387 key = jhash_1word(jhash(filter->advmap.aname,
388 strlen(filter->advmap.aname), SEED1),
389 key);
390
f373ce6c
QY
391 if (filter->advmap.update_type)
392 key = jhash_1word(filter->advmap.update_type, key);
393
d62a17ae 394 if (peer->default_rmap[afi][safi].name)
395 key = jhash_1word(
396 jhash(peer->default_rmap[afi][safi].name,
397 strlen(peer->default_rmap[afi][safi].name),
398 SEED1),
399 key);
400
401 /* If peer is on a shared network and is exchanging IPv6 prefixes,
402 * it needs to include link-local address. That's different from
403 * non-shared-network peers (nexthop encoded with 32 bytes vs 16
404 * bytes). We create different update groups to take care of that.
405 */
406 key = jhash_1word(
407 (peer->shared_network && peer_afi_active_nego(peer, AFI_IP6)),
408 key);
d62a17ae 409 /*
410 * There are certain peers that must get their own update-group:
411 * - lonesoul peers
412 * - peers that negotiated ORF
a849a3fe 413 * - maximum-prefix-out is set
d62a17ae 414 */
415 if (CHECK_FLAG(peer->flags, PEER_FLAG_LONESOUL)
416 || CHECK_FLAG(peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV)
417 || CHECK_FLAG(peer->af_cap[afi][safi],
a849a3fe
DA
418 PEER_CAP_ORF_PREFIX_SM_OLD_RCV)
419 || CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_OUT))
d62a17ae 420 key = jhash_1word(jhash(peer->host, strlen(peer->host), SEED2),
421 key);
d864dd9e
EB
422 /*
423 * Multiple sessions with the same neighbor should get their own
424 * update-group if they have different roles.
425 */
426 key = jhash_1word(peer->local_role, key);
d62a17ae 427
97a52c82
DA
428 /* Neighbors configured with the AIGP attribute are put in a separate
429 * update group from other neighbors.
430 */
431 key = jhash_1word((peer->flags & PEER_FLAG_AIGP), key);
432
01da2d26
DA
433 if (peer->soo[afi][safi]) {
434 char *soo_str = ecommunity_str(peer->soo[afi][safi]);
435
436 key = jhash_1word(jhash(soo_str, strlen(soo_str), SEED1), key);
437 }
438
34d8aff1
DS
439 if (bgp_debug_neighbor_events(peer)) {
440 zlog_debug(
da5e1a58 441 "%pBP Update Group Hash: sort: %d UpdGrpFlags: %ju UpdGrpAFFlags: %ju",
0ebabd41 442 peer, peer->sort,
da5e1a58
DA
443 (intmax_t)CHECK_FLAG(peer->flags, PEER_UPDGRP_FLAGS),
444 (intmax_t)CHECK_FLAG(flags, PEER_UPDGRP_AF_FLAGS));
34d8aff1 445 zlog_debug(
25851bf0 446 "%pBP Update Group Hash: addpath: %u UpdGrpCapFlag: %u UpdGrpCapAFFlag: %u route_adv: %u change local as: %u, as_path_loop_detection: %d",
34d8aff1 447 peer, (uint32_t)peer->addpath_type[afi][safi],
da5e1a58
DA
448 CHECK_FLAG(peer->cap, PEER_UPDGRP_CAP_FLAGS),
449 CHECK_FLAG(peer->af_cap[afi][safi],
450 PEER_UPDGRP_AF_CAP_FLAGS),
25851bf0
DA
451 peer->v_routeadv, peer->change_local_as,
452 peer->as_path_loop_detection);
34d8aff1
DS
453 zlog_debug(
454 "%pBP Update Group Hash: max packet size: %u pmax_out: %u Peer Group: %s rmap out: %s",
455 peer, peer->max_packet_size, peer->pmax_out[afi][safi],
456 peer->group ? peer->group->name : "(NONE)",
457 ROUTE_MAP_OUT_NAME(filter) ? ROUTE_MAP_OUT_NAME(filter)
458 : "(NONE)");
459 zlog_debug(
460 "%pBP Update Group Hash: dlist out: %s plist out: %s aslist out: %s usmap out: %s advmap: %s",
461 peer,
462 DISTRIBUTE_OUT_NAME(filter)
463 ? DISTRIBUTE_OUT_NAME(filter)
464 : "(NONE)",
465 PREFIX_LIST_OUT_NAME(filter)
466 ? PREFIX_LIST_OUT_NAME(filter)
467 : "(NONE)",
468 FILTER_LIST_OUT_NAME(filter)
469 ? FILTER_LIST_OUT_NAME(filter)
470 : "(NONE)",
471 UNSUPPRESS_MAP_NAME(filter)
472 ? UNSUPPRESS_MAP_NAME(filter)
473 : "(NONE)",
474 ADVERTISE_MAP_NAME(filter) ? ADVERTISE_MAP_NAME(filter)
475 : "(NONE)");
476 zlog_debug(
477 "%pBP Update Group Hash: default rmap: %s shared network and afi active network: %d",
478 peer,
479 peer->default_rmap[afi][safi].name
480 ? peer->default_rmap[afi][safi].name
481 : "(NONE)",
482 peer->shared_network &&
483 peer_afi_active_nego(peer, AFI_IP6));
484 zlog_debug(
da5e1a58 485 "%pBP Update Group Hash: Lonesoul: %d ORF prefix: %u ORF old: %u max prefix out: %ju",
37e70073 486 peer, !!CHECK_FLAG(peer->flags, PEER_FLAG_LONESOUL),
34d8aff1
DS
487 CHECK_FLAG(peer->af_cap[afi][safi],
488 PEER_CAP_ORF_PREFIX_SM_RCV),
489 CHECK_FLAG(peer->af_cap[afi][safi],
490 PEER_CAP_ORF_PREFIX_SM_OLD_RCV),
da5e1a58
DA
491 (intmax_t)CHECK_FLAG(peer->af_flags[afi][safi],
492 PEER_FLAG_MAX_PREFIX_OUT));
34d8aff1
DS
493 zlog_debug("%pBP Update Group Hash key: %u", peer, key);
494 }
d62a17ae 495 return key;
3f9c7369
DS
496}
497
74df8d6d 498static bool updgrp_hash_cmp(const void *p1, const void *p2)
3f9c7369 499{
d62a17ae 500 const struct update_group *grp1;
501 const struct update_group *grp2;
502 const struct peer *pe1;
503 const struct peer *pe2;
504 uint32_t flags1;
505 uint32_t flags2;
506 const struct bgp_filter *fl1;
507 const struct bgp_filter *fl2;
508 afi_t afi;
509 safi_t safi;
510
511 if (!p1 || !p2)
74df8d6d 512 return false;
d62a17ae 513
514 grp1 = p1;
515 grp2 = p2;
516 pe1 = grp1->conf;
517 pe2 = grp2->conf;
518 afi = grp1->afi;
519 safi = grp1->safi;
520 flags1 = pe1->af_flags[afi][safi];
521 flags2 = pe2->af_flags[afi][safi];
522 fl1 = &pe1->filter[afi][safi];
523 fl2 = &pe2->filter[afi][safi];
524
525 /* put EBGP and IBGP peers in different update groups */
526 if (pe1->sort != pe2->sort)
74df8d6d 527 return false;
d62a17ae 528
529 /* check peer flags */
530 if ((pe1->flags & PEER_UPDGRP_FLAGS)
531 != (pe2->flags & PEER_UPDGRP_FLAGS))
74df8d6d 532 return false;
d62a17ae 533
534 /* If there is 'local-as' configured, it should match. */
535 if (pe1->change_local_as != pe2->change_local_as)
74df8d6d 536 return false;
d62a17ae 537
e0267260
LS
538 if (pe1->pmax_out[afi][safi] != pe2->pmax_out[afi][safi])
539 return false;
540
d62a17ae 541 /* flags like route reflector client */
542 if ((flags1 & PEER_UPDGRP_AF_FLAGS) != (flags2 & PEER_UPDGRP_AF_FLAGS))
74df8d6d 543 return false;
d62a17ae 544
dcc68b5e 545 if (pe1->addpath_type[afi][safi] != pe2->addpath_type[afi][safi])
b08047f8 546 return false;
dcc68b5e 547
d62a17ae 548 if ((pe1->cap & PEER_UPDGRP_CAP_FLAGS)
549 != (pe2->cap & PEER_UPDGRP_CAP_FLAGS))
74df8d6d 550 return false;
d62a17ae 551
552 if ((pe1->af_cap[afi][safi] & PEER_UPDGRP_AF_CAP_FLAGS)
553 != (pe2->af_cap[afi][safi] & PEER_UPDGRP_AF_CAP_FLAGS))
74df8d6d 554 return false;
d62a17ae 555
556 if (pe1->v_routeadv != pe2->v_routeadv)
74df8d6d 557 return false;
d62a17ae 558
559 if (pe1->group != pe2->group)
74df8d6d 560 return false;
d62a17ae 561
d864dd9e
EB
562 /* Roles can affect filtering */
563 if (pe1->local_role != pe2->local_role)
564 return false;
565
d62a17ae 566 /* route-map names should be the same */
567 if ((fl1->map[RMAP_OUT].name && !fl2->map[RMAP_OUT].name)
568 || (!fl1->map[RMAP_OUT].name && fl2->map[RMAP_OUT].name)
569 || (fl1->map[RMAP_OUT].name && fl2->map[RMAP_OUT].name
570 && strcmp(fl1->map[RMAP_OUT].name, fl2->map[RMAP_OUT].name)))
74df8d6d 571 return false;
d62a17ae 572
573 if ((fl1->dlist[FILTER_OUT].name && !fl2->dlist[FILTER_OUT].name)
574 || (!fl1->dlist[FILTER_OUT].name && fl2->dlist[FILTER_OUT].name)
575 || (fl1->dlist[FILTER_OUT].name && fl2->dlist[FILTER_OUT].name
576 && strcmp(fl1->dlist[FILTER_OUT].name,
577 fl2->dlist[FILTER_OUT].name)))
74df8d6d 578 return false;
d62a17ae 579
580 if ((fl1->plist[FILTER_OUT].name && !fl2->plist[FILTER_OUT].name)
581 || (!fl1->plist[FILTER_OUT].name && fl2->plist[FILTER_OUT].name)
582 || (fl1->plist[FILTER_OUT].name && fl2->plist[FILTER_OUT].name
583 && strcmp(fl1->plist[FILTER_OUT].name,
584 fl2->plist[FILTER_OUT].name)))
74df8d6d 585 return false;
d62a17ae 586
587 if ((fl1->aslist[FILTER_OUT].name && !fl2->aslist[FILTER_OUT].name)
588 || (!fl1->aslist[FILTER_OUT].name && fl2->aslist[FILTER_OUT].name)
589 || (fl1->aslist[FILTER_OUT].name && fl2->aslist[FILTER_OUT].name
590 && strcmp(fl1->aslist[FILTER_OUT].name,
591 fl2->aslist[FILTER_OUT].name)))
74df8d6d 592 return false;
d62a17ae 593
594 if ((fl1->usmap.name && !fl2->usmap.name)
595 || (!fl1->usmap.name && fl2->usmap.name)
596 || (fl1->usmap.name && fl2->usmap.name
597 && strcmp(fl1->usmap.name, fl2->usmap.name)))
74df8d6d 598 return false;
d62a17ae 599
7f7940e6
MK
600 if ((fl1->advmap.aname && !fl2->advmap.aname)
601 || (!fl1->advmap.aname && fl2->advmap.aname)
602 || (fl1->advmap.aname && fl2->advmap.aname
603 && strcmp(fl1->advmap.aname, fl2->advmap.aname)))
604 return false;
605
f373ce6c
QY
606 if (fl1->advmap.update_type != fl2->advmap.update_type)
607 return false;
608
d62a17ae 609 if ((pe1->default_rmap[afi][safi].name
610 && !pe2->default_rmap[afi][safi].name)
611 || (!pe1->default_rmap[afi][safi].name
612 && pe2->default_rmap[afi][safi].name)
613 || (pe1->default_rmap[afi][safi].name
614 && pe2->default_rmap[afi][safi].name
615 && strcmp(pe1->default_rmap[afi][safi].name,
616 pe2->default_rmap[afi][safi].name)))
74df8d6d 617 return false;
d62a17ae 618
619 if ((afi == AFI_IP6) && (pe1->shared_network != pe2->shared_network))
74df8d6d 620 return false;
d62a17ae 621
622 if ((CHECK_FLAG(pe1->flags, PEER_FLAG_LONESOUL)
623 || CHECK_FLAG(pe1->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV)
624 || CHECK_FLAG(pe1->af_cap[afi][safi],
625 PEER_CAP_ORF_PREFIX_SM_OLD_RCV))
626 && !sockunion_same(&pe1->su, &pe2->su))
74df8d6d 627 return false;
d62a17ae 628
74df8d6d 629 return true;
3f9c7369
DS
630}
631
d62a17ae 632static void peer_lonesoul_or_not(struct peer *peer, int set)
3f9c7369 633{
d62a17ae 634 /* no change in status? */
635 if (set == (CHECK_FLAG(peer->flags, PEER_FLAG_LONESOUL) > 0))
636 return;
3f9c7369 637
d62a17ae 638 if (set)
639 SET_FLAG(peer->flags, PEER_FLAG_LONESOUL);
640 else
641 UNSET_FLAG(peer->flags, PEER_FLAG_LONESOUL);
3f9c7369 642
d62a17ae 643 update_group_adjust_peer_afs(peer);
3f9c7369
DS
644}
645
646/*
647 * subgroup_total_packets_enqueued
648 *
649 * Returns the total number of packets enqueued to a subgroup.
650 */
651static unsigned int
d62a17ae 652subgroup_total_packets_enqueued(struct update_subgroup *subgrp)
3f9c7369 653{
d62a17ae 654 struct bpacket *pkt;
3f9c7369 655
d62a17ae 656 pkt = bpacket_queue_last(SUBGRP_PKTQ(subgrp));
3f9c7369 657
d62a17ae 658 return pkt->ver - 1;
3f9c7369
DS
659}
660
d62a17ae 661static int update_group_show_walkcb(struct update_group *updgrp, void *arg)
3f9c7369 662{
d62a17ae 663 struct updwalk_context *ctx = arg;
664 struct vty *vty;
665 struct update_subgroup *subgrp;
666 struct peer_af *paf;
667 struct bgp_filter *filter;
0997ee26 668 struct peer *peer = UPDGRP_PEER(updgrp);
d62a17ae 669 int match = 0;
fa5a9276
AR
670 json_object *json_updgrp = NULL;
671 json_object *json_subgrps = NULL;
672 json_object *json_subgrp = NULL;
673 json_object *json_time = NULL;
674 json_object *json_subgrp_time = NULL;
675 json_object *json_subgrp_event = NULL;
676 json_object *json_peers = NULL;
677 json_object *json_pkt_info = NULL;
678 time_t epoch_tbuf, tbuf;
d62a17ae 679
680 if (!ctx)
681 return CMD_SUCCESS;
682
683 if (ctx->subgrp_id) {
a2addae8 684 UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) {
d62a17ae 685 if (ctx->subgrp_id && (ctx->subgrp_id != subgrp->id))
686 continue;
687 else {
688 match = 1;
689 break;
690 }
691 }
692 } else {
693 match = 1;
694 }
695
696 if (!match) {
697 /* Since this routine is invoked from a walk, we cannot signal
698 * any */
699 /* error here, can only return. */
700 return CMD_SUCCESS;
701 }
702
703 vty = ctx->vty;
704
fa5a9276
AR
705 if (ctx->uj) {
706 json_updgrp = json_object_new_object();
707 /* Display json o/p */
708 tbuf = monotime(NULL);
709 tbuf -= updgrp->uptime;
710 epoch_tbuf = time(NULL) - tbuf;
711 json_time = json_object_new_object();
712 json_object_int_add(json_time, "epoch", epoch_tbuf);
713 json_object_string_add(json_time, "epochString",
714 ctime(&epoch_tbuf));
715 json_object_object_add(json_updgrp, "groupCreateTime",
716 json_time);
717 json_object_string_add(json_updgrp, "afi",
718 afi2str(updgrp->afi));
719 json_object_string_add(json_updgrp, "safi",
720 safi2str(updgrp->safi));
721 } else {
722 vty_out(vty, "Update-group %" PRIu64 ":\n", updgrp->id);
723 vty_out(vty, " Created: %s", timestamp_string(updgrp->uptime));
724 }
725
d62a17ae 726 filter = &updgrp->conf->filter[updgrp->afi][updgrp->safi];
fa5a9276
AR
727 if (filter->map[RMAP_OUT].name) {
728 if (ctx->uj)
729 json_object_string_add(json_updgrp, "outRouteMap",
730 filter->map[RMAP_OUT].name);
731 else
732 vty_out(vty, " Outgoing route map: %s\n",
733 filter->map[RMAP_OUT].name);
734 }
d62a17ae 735
fa5a9276
AR
736 if (ctx->uj)
737 json_object_int_add(json_updgrp, "minRouteAdvInt",
738 updgrp->conf->v_routeadv);
739 else
740 vty_out(vty, " MRAI value (seconds): %d\n",
741 updgrp->conf->v_routeadv);
742
743 if (updgrp->conf->change_local_as) {
744 if (ctx->uj) {
745 json_object_int_add(json_updgrp, "localAs",
746 updgrp->conf->change_local_as);
747 json_object_boolean_add(
748 json_updgrp, "noPrepend",
749 CHECK_FLAG(updgrp->conf->flags,
750 PEER_FLAG_LOCAL_AS_NO_PREPEND));
751 json_object_boolean_add(
752 json_updgrp, "replaceLocalAs",
753 CHECK_FLAG(updgrp->conf->flags,
754 PEER_FLAG_LOCAL_AS_REPLACE_AS));
755 } else {
756 vty_out(vty, " Local AS %u%s%s\n",
757 updgrp->conf->change_local_as,
758 CHECK_FLAG(updgrp->conf->flags,
759 PEER_FLAG_LOCAL_AS_NO_PREPEND)
760 ? " no-prepend"
761 : "",
762 CHECK_FLAG(updgrp->conf->flags,
763 PEER_FLAG_LOCAL_AS_REPLACE_AS)
764 ? " replace-as"
765 : "");
766 }
767 }
5691f760
DS
768 if (ctx->uj)
769 json_subgrps = json_object_new_array();
a2addae8 770 UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) {
d62a17ae 771 if (ctx->subgrp_id && (ctx->subgrp_id != subgrp->id))
772 continue;
fa5a9276
AR
773 if (ctx->uj) {
774 json_subgrp = json_object_new_object();
775 json_object_int_add(json_subgrp, "subGroupId",
776 subgrp->id);
777 tbuf = monotime(NULL);
778 tbuf -= subgrp->uptime;
779 epoch_tbuf = time(NULL) - tbuf;
780 json_subgrp_time = json_object_new_object();
781 json_object_int_add(json_subgrp_time, "epoch",
782 epoch_tbuf);
783 json_object_string_add(json_subgrp_time, "epochString",
784 ctime(&epoch_tbuf));
785 json_object_object_add(json_subgrp, "groupCreateTime",
786 json_subgrp_time);
787 } else {
788 vty_out(vty, "\n");
789 vty_out(vty, " Update-subgroup %" PRIu64 ":\n",
790 subgrp->id);
791 vty_out(vty, " Created: %s",
792 timestamp_string(subgrp->uptime));
793 }
d62a17ae 794
795 if (subgrp->split_from.update_group_id
796 || subgrp->split_from.subgroup_id) {
fa5a9276
AR
797 if (ctx->uj) {
798 json_object_int_add(
799 json_subgrp, "splitGroupId",
800 subgrp->split_from.update_group_id);
801 json_object_int_add(
802 json_subgrp, "splitSubGroupId",
803 subgrp->split_from.subgroup_id);
804 } else {
805 vty_out(vty,
806 " Split from group id: %" PRIu64
807 "\n",
808 subgrp->split_from.update_group_id);
809 vty_out(vty,
810 " Split from subgroup id: %" PRIu64
811 "\n",
812 subgrp->split_from.subgroup_id);
813 }
d62a17ae 814 }
815
fa5a9276
AR
816 if (ctx->uj) {
817 json_subgrp_event = json_object_new_object();
818 json_object_int_add(json_subgrp_event, "joinEvents",
819 subgrp->join_events);
820 json_object_int_add(json_subgrp_event, "pruneEvents",
821 subgrp->prune_events);
822 json_object_int_add(json_subgrp_event, "mergeEvents",
823 subgrp->merge_events);
824 json_object_int_add(json_subgrp_event, "splitEvents",
825 subgrp->split_events);
826 json_object_int_add(json_subgrp_event, "switchEvents",
827 subgrp->updgrp_switch_events);
828 json_object_int_add(json_subgrp_event,
829 "peerRefreshEvents",
830 subgrp->peer_refreshes_combined);
831 json_object_int_add(json_subgrp_event,
832 "mergeCheckEvents",
833 subgrp->merge_checks_triggered);
834 json_object_object_add(json_subgrp, "statistics",
835 json_subgrp_event);
836 json_object_int_add(json_subgrp, "coalesceTime",
837 (UPDGRP_INST(subgrp->update_group))
838 ->coalesce_time);
839 json_object_int_add(json_subgrp, "version",
840 subgrp->version);
841 json_pkt_info = json_object_new_object();
842 json_object_int_add(
843 json_pkt_info, "qeueueLen",
844 bpacket_queue_length(SUBGRP_PKTQ(subgrp)));
845 json_object_int_add(
846 json_pkt_info, "queuedTotal",
847 subgroup_total_packets_enqueued(subgrp));
848 json_object_int_add(
849 json_pkt_info, "queueHwmLen",
850 bpacket_queue_hwm_length(SUBGRP_PKTQ(subgrp)));
851 json_object_int_add(
852 json_pkt_info, "totalEnqueued",
853 subgroup_total_packets_enqueued(subgrp));
854 json_object_object_add(json_subgrp, "packetQueueInfo",
855 json_pkt_info);
856 json_object_int_add(json_subgrp, "adjListCount",
857 subgrp->adj_count);
858 json_object_boolean_add(
859 json_subgrp, "needsRefresh",
860 CHECK_FLAG(subgrp->flags,
861 SUBGRP_FLAG_NEEDS_REFRESH));
862 } else {
863 vty_out(vty, " Join events: %u\n",
864 subgrp->join_events);
865 vty_out(vty, " Prune events: %u\n",
866 subgrp->prune_events);
867 vty_out(vty, " Merge events: %u\n",
868 subgrp->merge_events);
869 vty_out(vty, " Split events: %u\n",
870 subgrp->split_events);
871 vty_out(vty, " Update group switch events: %u\n",
872 subgrp->updgrp_switch_events);
873 vty_out(vty, " Peer refreshes combined: %u\n",
874 subgrp->peer_refreshes_combined);
875 vty_out(vty, " Merge checks triggered: %u\n",
876 subgrp->merge_checks_triggered);
877 vty_out(vty, " Coalesce Time: %u%s\n",
878 (UPDGRP_INST(subgrp->update_group))
879 ->coalesce_time,
880 subgrp->t_coalesce ? "(Running)" : "");
881 vty_out(vty, " Version: %" PRIu64 "\n",
882 subgrp->version);
883 vty_out(vty, " Packet queue length: %d\n",
884 bpacket_queue_length(SUBGRP_PKTQ(subgrp)));
885 vty_out(vty, " Total packets enqueued: %u\n",
886 subgroup_total_packets_enqueued(subgrp));
887 vty_out(vty, " Packet queue high watermark: %d\n",
888 bpacket_queue_hwm_length(SUBGRP_PKTQ(subgrp)));
889 vty_out(vty, " Adj-out list count: %u\n",
890 subgrp->adj_count);
891 vty_out(vty, " Advertise list: %s\n",
892 advertise_list_is_empty(subgrp) ? "empty"
893 : "not empty");
894 vty_out(vty, " Flags: %s\n",
895 CHECK_FLAG(subgrp->flags,
896 SUBGRP_FLAG_NEEDS_REFRESH)
897 ? "R"
898 : "");
899 if (peer)
900 vty_out(vty, " Max packet size: %d\n",
901 peer->max_packet_size);
902 }
d62a17ae 903 if (subgrp->peer_count > 0) {
fa5a9276
AR
904 if (ctx->uj) {
905 json_peers = json_object_new_array();
906 SUBGRP_FOREACH_PEER (subgrp, paf) {
907 json_object *peer =
908 json_object_new_string(
909 paf->peer->host);
910 json_object_array_add(json_peers, peer);
911 }
912 json_object_object_add(json_subgrp, "peers",
913 json_peers);
914 } else {
915 vty_out(vty, " Peers:\n");
916 SUBGRP_FOREACH_PEER (subgrp, paf)
917 vty_out(vty, " - %s\n",
918 paf->peer->host);
919 }
d62a17ae 920 }
fa5a9276
AR
921
922 if (ctx->uj)
923 json_object_array_add(json_subgrps, json_subgrp);
8fe8a7f6 924 }
fa5a9276
AR
925
926 if (ctx->uj) {
927 json_object_object_add(json_updgrp, "subGroup", json_subgrps);
928 json_object_object_addf(ctx->json_updategrps, json_updgrp,
929 "%" PRIu64, updgrp->id);
930 }
931
d62a17ae 932 return UPDWALK_CONTINUE;
3f9c7369
DS
933}
934
935/*
936 * Helper function to show the packet queue for each subgroup of update group.
937 * Will be constrained to a particular subgroup id if id !=0
938 */
d62a17ae 939static int updgrp_show_packet_queue_walkcb(struct update_group *updgrp,
940 void *arg)
3f9c7369 941{
d62a17ae 942 struct updwalk_context *ctx = arg;
943 struct update_subgroup *subgrp;
944 struct vty *vty;
945
946 vty = ctx->vty;
a2addae8 947 UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) {
d62a17ae 948 if (ctx->subgrp_id && (ctx->subgrp_id != subgrp->id))
949 continue;
950 vty_out(vty, "update group %" PRIu64 ", subgroup %" PRIu64 "\n",
951 updgrp->id, subgrp->id);
952 bpacket_queue_show_vty(SUBGRP_PKTQ(subgrp), vty);
953 }
954 return UPDWALK_CONTINUE;
3f9c7369
DS
955}
956
957/*
958 * Show the packet queue for each subgroup of update group. Will be
959 * constrained to a particular subgroup id if id !=0
960 */
d62a17ae 961void update_group_show_packet_queue(struct bgp *bgp, afi_t afi, safi_t safi,
962 struct vty *vty, uint64_t id)
3f9c7369 963{
d62a17ae 964 struct updwalk_context ctx;
965
966 memset(&ctx, 0, sizeof(ctx));
967 ctx.vty = vty;
968 ctx.subgrp_id = id;
969 ctx.flags = 0;
970 update_group_af_walk(bgp, afi, safi, updgrp_show_packet_queue_walkcb,
971 &ctx);
3f9c7369
DS
972}
973
d62a17ae 974static struct update_group *update_group_find(struct peer_af *paf)
3f9c7369 975{
d62a17ae 976 struct update_group *updgrp;
977 struct update_group tmp;
978 struct peer tmp_conf;
3f9c7369 979
d62a17ae 980 if (!peer_established(PAF_PEER(paf)))
981 return NULL;
3f9c7369 982
d62a17ae 983 memset(&tmp, 0, sizeof(tmp));
984 memset(&tmp_conf, 0, sizeof(tmp_conf));
985 tmp.conf = &tmp_conf;
986 peer2_updgrp_copy(&tmp, paf);
3f9c7369 987
d62a17ae 988 updgrp = hash_lookup(paf->peer->bgp->update_groups[paf->afid], &tmp);
989 conf_release(&tmp_conf, paf->afi, paf->safi);
990 return updgrp;
3f9c7369
DS
991}
992
d62a17ae 993static struct update_group *update_group_create(struct peer_af *paf)
3f9c7369 994{
d62a17ae 995 struct update_group *updgrp;
996 struct update_group tmp;
997 struct peer tmp_conf;
3f9c7369 998
d62a17ae 999 memset(&tmp, 0, sizeof(tmp));
1000 memset(&tmp_conf, 0, sizeof(tmp_conf));
1001 tmp.conf = &tmp_conf;
1002 peer2_updgrp_copy(&tmp, paf);
3f9c7369 1003
d62a17ae 1004 updgrp = hash_get(paf->peer->bgp->update_groups[paf->afid], &tmp,
1005 updgrp_hash_alloc);
d62a17ae 1006 update_group_checkin(updgrp);
3f9c7369 1007
d62a17ae 1008 if (BGP_DEBUG(update_groups, UPDATE_GROUPS))
1009 zlog_debug("create update group %" PRIu64, updgrp->id);
3f9c7369 1010
d62a17ae 1011 UPDGRP_GLOBAL_STAT(updgrp, updgrps_created) += 1;
3f9c7369 1012
d62a17ae 1013 conf_release(&tmp_conf, paf->afi, paf->safi);
1014 return updgrp;
3f9c7369
DS
1015}
1016
d62a17ae 1017static void update_group_delete(struct update_group *updgrp)
3f9c7369 1018{
d62a17ae 1019 if (BGP_DEBUG(update_groups, UPDATE_GROUPS))
1020 zlog_debug("delete update group %" PRIu64, updgrp->id);
3f9c7369 1021
d62a17ae 1022 UPDGRP_GLOBAL_STAT(updgrp, updgrps_deleted) += 1;
3f9c7369 1023
d62a17ae 1024 hash_release(updgrp->bgp->update_groups[updgrp->afid], updgrp);
1025 conf_release(updgrp->conf, updgrp->afi, updgrp->safi);
3d68677e 1026
0a22ddfb 1027 XFREE(MTYPE_BGP_PEER_HOST, updgrp->conf->host);
6e919709 1028
0a22ddfb 1029 XFREE(MTYPE_BGP_PEER_IFNAME, updgrp->conf->ifname);
6e919709 1030
d62a17ae 1031 XFREE(MTYPE_BGP_PEER, updgrp->conf);
1032 XFREE(MTYPE_BGP_UPDGRP, updgrp);
3f9c7369
DS
1033}
1034
d62a17ae 1035static void update_group_add_subgroup(struct update_group *updgrp,
1036 struct update_subgroup *subgrp)
3f9c7369 1037{
d62a17ae 1038 if (!updgrp || !subgrp)
1039 return;
3f9c7369 1040
d62a17ae 1041 LIST_INSERT_HEAD(&(updgrp->subgrps), subgrp, updgrp_train);
1042 subgrp->update_group = updgrp;
3f9c7369
DS
1043}
1044
d62a17ae 1045static void update_group_remove_subgroup(struct update_group *updgrp,
1046 struct update_subgroup *subgrp)
3f9c7369 1047{
d62a17ae 1048 if (!updgrp || !subgrp)
1049 return;
3f9c7369 1050
d62a17ae 1051 LIST_REMOVE(subgrp, updgrp_train);
1052 subgrp->update_group = NULL;
1053 if (LIST_EMPTY(&(updgrp->subgrps)))
1054 update_group_delete(updgrp);
3f9c7369
DS
1055}
1056
1057static struct update_subgroup *
d62a17ae 1058update_subgroup_create(struct update_group *updgrp)
3f9c7369 1059{
d62a17ae 1060 struct update_subgroup *subgrp;
3f9c7369 1061
d62a17ae 1062 subgrp = XCALLOC(MTYPE_BGP_UPD_SUBGRP, sizeof(struct update_subgroup));
1063 update_subgroup_checkin(subgrp, updgrp);
1064 subgrp->v_coalesce = (UPDGRP_INST(updgrp))->coalesce_time;
ef56aee4 1065 sync_init(subgrp, updgrp);
d62a17ae 1066 bpacket_queue_init(SUBGRP_PKTQ(subgrp));
1067 bpacket_queue_add(SUBGRP_PKTQ(subgrp), NULL, NULL);
1068 TAILQ_INIT(&(subgrp->adjq));
1069 if (BGP_DEBUG(update_groups, UPDATE_GROUPS))
1070 zlog_debug("create subgroup u%" PRIu64 ":s%" PRIu64, updgrp->id,
1071 subgrp->id);
3f9c7369 1072
d62a17ae 1073 update_group_add_subgroup(updgrp, subgrp);
3f9c7369 1074
d62a17ae 1075 UPDGRP_INCR_STAT(updgrp, subgrps_created);
3f9c7369 1076
d62a17ae 1077 return subgrp;
3f9c7369
DS
1078}
1079
d62a17ae 1080static void update_subgroup_delete(struct update_subgroup *subgrp)
3f9c7369 1081{
d62a17ae 1082 if (!subgrp)
1083 return;
3f9c7369 1084
d62a17ae 1085 if (subgrp->update_group)
1086 UPDGRP_INCR_STAT(subgrp->update_group, subgrps_deleted);
3f9c7369 1087
28ef0ee1 1088 THREAD_OFF(subgrp->t_merge_check);
50478845 1089 THREAD_OFF(subgrp->t_coalesce);
3f9c7369 1090
d62a17ae 1091 bpacket_queue_cleanup(SUBGRP_PKTQ(subgrp));
1092 subgroup_clear_table(subgrp);
3f9c7369 1093
d62a17ae 1094 sync_delete(subgrp);
3f9c7369 1095
4f9a63ad 1096 if (BGP_DEBUG(update_groups, UPDATE_GROUPS) && subgrp->update_group)
d62a17ae 1097 zlog_debug("delete subgroup u%" PRIu64 ":s%" PRIu64,
1098 subgrp->update_group->id, subgrp->id);
3f9c7369 1099
d62a17ae 1100 update_group_remove_subgroup(subgrp->update_group, subgrp);
3f9c7369 1101
d62a17ae 1102 XFREE(MTYPE_BGP_UPD_SUBGRP, subgrp);
3f9c7369
DS
1103}
1104
d62a17ae 1105void update_subgroup_inherit_info(struct update_subgroup *to,
1106 struct update_subgroup *from)
3f9c7369 1107{
d62a17ae 1108 if (!to || !from)
1109 return;
3f9c7369 1110
d62a17ae 1111 to->sflags = from->sflags;
3f9c7369
DS
1112}
1113
1114/*
1115 * update_subgroup_check_delete
1116 *
1117 * Delete a subgroup if it is ready to be deleted.
1118 *
2951a7a4 1119 * Returns true if the subgroup was deleted.
3f9c7369 1120 */
3dc339cd 1121static bool update_subgroup_check_delete(struct update_subgroup *subgrp)
3f9c7369 1122{
d62a17ae 1123 if (!subgrp)
3dc339cd 1124 return false;
3f9c7369 1125
d62a17ae 1126 if (!LIST_EMPTY(&(subgrp->peers)))
3dc339cd 1127 return false;
3f9c7369 1128
d62a17ae 1129 update_subgroup_delete(subgrp);
3f9c7369 1130
3dc339cd 1131 return true;
3f9c7369
DS
1132}
1133
1134/*
1135 * update_subgroup_add_peer
1136 *
1137 * @param send_enqueued_packets If true all currently enqueued packets will
1138 * also be sent to the peer.
1139 */
d62a17ae 1140static void update_subgroup_add_peer(struct update_subgroup *subgrp,
1141 struct peer_af *paf,
1142 int send_enqueued_pkts)
3f9c7369 1143{
d62a17ae 1144 struct bpacket *pkt;
3f9c7369 1145
d62a17ae 1146 if (!subgrp || !paf)
1147 return;
3f9c7369 1148
d62a17ae 1149 LIST_INSERT_HEAD(&(subgrp->peers), paf, subgrp_train);
1150 paf->subgroup = subgrp;
1151 subgrp->peer_count++;
3f9c7369 1152
d62a17ae 1153 if (bgp_debug_peer_updout_enabled(paf->peer->host)) {
1154 UPDGRP_PEER_DBG_EN(subgrp->update_group);
1155 }
3f9c7369 1156
d62a17ae 1157 SUBGRP_INCR_STAT(subgrp, join_events);
3f9c7369 1158
d62a17ae 1159 if (send_enqueued_pkts) {
1160 pkt = bpacket_queue_first(SUBGRP_PKTQ(subgrp));
1161 } else {
3f9c7369 1162
d62a17ae 1163 /*
1164 * Hang the peer off of the last, placeholder, packet in the
1165 * queue. This means it won't see any of the packets that are
1166 * currently the queue.
1167 */
1168 pkt = bpacket_queue_last(SUBGRP_PKTQ(subgrp));
1169 assert(pkt->buffer == NULL);
1170 }
3f9c7369 1171
d62a17ae 1172 bpacket_add_peer(pkt, paf);
3f9c7369 1173
7bfdba54
S
1174 if (BGP_DEBUG(update_groups, UPDATE_GROUPS))
1175 zlog_debug("peer %s added to subgroup s%" PRIu64,
1176 paf->peer->host, subgrp->id);
3f9c7369
DS
1177}
1178
1179/*
1180 * update_subgroup_remove_peer_internal
1181 *
1182 * Internal function that removes a peer from a subgroup, but does not
1183 * delete the subgroup. A call to this function must almost always be
1184 * followed by a call to update_subgroup_check_delete().
1185 *
1186 * @see update_subgroup_remove_peer
1187 */
d62a17ae 1188static void update_subgroup_remove_peer_internal(struct update_subgroup *subgrp,
1189 struct peer_af *paf)
3f9c7369 1190{
d3e51db0 1191 assert(subgrp && paf && subgrp->update_group);
3f9c7369 1192
d62a17ae 1193 if (bgp_debug_peer_updout_enabled(paf->peer->host)) {
1194 UPDGRP_PEER_DBG_DIS(subgrp->update_group);
1195 }
3f9c7369 1196
d62a17ae 1197 bpacket_queue_remove_peer(paf);
1198 LIST_REMOVE(paf, subgrp_train);
1199 paf->subgroup = NULL;
1200 subgrp->peer_count--;
3f9c7369 1201
7bfdba54
S
1202 if (BGP_DEBUG(update_groups, UPDATE_GROUPS))
1203 zlog_debug("peer %s deleted from subgroup s%"
4882d296 1204 PRIu64 " peer cnt %d",
7bfdba54 1205 paf->peer->host, subgrp->id, subgrp->peer_count);
d62a17ae 1206 SUBGRP_INCR_STAT(subgrp, prune_events);
3f9c7369
DS
1207}
1208
1209/*
1210 * update_subgroup_remove_peer
1211 */
d62a17ae 1212void update_subgroup_remove_peer(struct update_subgroup *subgrp,
1213 struct peer_af *paf)
3f9c7369 1214{
d62a17ae 1215 if (!subgrp || !paf)
1216 return;
3f9c7369 1217
d62a17ae 1218 update_subgroup_remove_peer_internal(subgrp, paf);
3f9c7369 1219
d62a17ae 1220 if (update_subgroup_check_delete(subgrp))
1221 return;
3f9c7369 1222
d62a17ae 1223 /*
1224 * The deletion of the peer may have caused some packets to be
1225 * deleted from the subgroup packet queue. Check if the subgroup can
1226 * be merged now.
1227 */
1228 update_subgroup_check_merge(subgrp, "removed peer from subgroup");
3f9c7369
DS
1229}
1230
d62a17ae 1231static struct update_subgroup *update_subgroup_find(struct update_group *updgrp,
1232 struct peer_af *paf)
3f9c7369 1233{
d62a17ae 1234 struct update_subgroup *subgrp = NULL;
1235 uint64_t version;
1236
1237 if (paf->subgroup) {
1238 assert(0);
1239 return NULL;
1240 } else
1241 version = 0;
1242
1243 if (!peer_established(PAF_PEER(paf)))
1244 return NULL;
1245
a2addae8 1246 UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) {
d62a17ae 1247 if (subgrp->version != version
1248 || CHECK_FLAG(subgrp->sflags,
1249 SUBGRP_STATUS_DEFAULT_ORIGINATE))
1250 continue;
1251
1252 /*
1253 * The version number is not meaningful on a subgroup that needs
1254 * a refresh.
1255 */
1256 if (update_subgroup_needs_refresh(subgrp))
1257 continue;
1258
1259 break;
1260 }
1261
1262 return subgrp;
3f9c7369
DS
1263}
1264
1265/*
1266 * update_subgroup_ready_for_merge
1267 *
2951a7a4 1268 * Returns true if this subgroup is in a state that allows it to be
3f9c7369
DS
1269 * merged into another subgroup.
1270 */
3dc339cd 1271static bool update_subgroup_ready_for_merge(struct update_subgroup *subgrp)
3f9c7369
DS
1272{
1273
d62a17ae 1274 /*
1275 * Not ready if there are any encoded packets waiting to be written
1276 * out to peers.
1277 */
1278 if (!bpacket_queue_is_empty(SUBGRP_PKTQ(subgrp)))
3dc339cd 1279 return false;
d62a17ae 1280
1281 /*
1282 * Not ready if there enqueued updates waiting to be encoded.
1283 */
1284 if (!advertise_list_is_empty(subgrp))
3dc339cd 1285 return false;
d62a17ae 1286
1287 /*
1288 * Don't attempt to merge a subgroup that needs a refresh. For one,
1289 * we can't determine if the adj_out of such a group matches that of
1290 * another group.
1291 */
1292 if (update_subgroup_needs_refresh(subgrp))
3dc339cd 1293 return false;
d62a17ae 1294
3dc339cd 1295 return true;
3f9c7369
DS
1296}
1297
1298/*
1299 * update_subgrp_can_merge_into
1300 *
2951a7a4 1301 * Returns true if the first subgroup can merge into the second
3f9c7369
DS
1302 * subgroup.
1303 */
d62a17ae 1304static int update_subgroup_can_merge_into(struct update_subgroup *subgrp,
1305 struct update_subgroup *target)
3f9c7369
DS
1306{
1307
d62a17ae 1308 if (subgrp == target)
1309 return 0;
3f9c7369 1310
d62a17ae 1311 /*
1312 * Both must have processed the BRIB to the same point in order to
1313 * be merged.
1314 */
1315 if (subgrp->version != target->version)
1316 return 0;
3f9c7369 1317
d62a17ae 1318 if (CHECK_FLAG(subgrp->sflags, SUBGRP_STATUS_DEFAULT_ORIGINATE)
1319 != CHECK_FLAG(target->sflags, SUBGRP_STATUS_DEFAULT_ORIGINATE))
1320 return 0;
f910ef58 1321
d62a17ae 1322 if (subgrp->adj_count != target->adj_count)
1323 return 0;
3f9c7369 1324
d62a17ae 1325 return update_subgroup_ready_for_merge(target);
3f9c7369
DS
1326}
1327
1328/*
1329 * update_subgroup_merge
1330 *
1331 * Merge the first subgroup into the second one.
1332 */
d62a17ae 1333static void update_subgroup_merge(struct update_subgroup *subgrp,
1334 struct update_subgroup *target,
1335 const char *reason)
3f9c7369 1336{
d62a17ae 1337 struct peer_af *paf;
1338 int result;
1339 int peer_count;
3f9c7369 1340
d62a17ae 1341 assert(subgrp->adj_count == target->adj_count);
3f9c7369 1342
d62a17ae 1343 peer_count = subgrp->peer_count;
3f9c7369 1344
d62a17ae 1345 while (1) {
1346 paf = LIST_FIRST(&subgrp->peers);
1347 if (!paf)
1348 break;
3f9c7369 1349
d62a17ae 1350 update_subgroup_remove_peer_internal(subgrp, paf);
3f9c7369 1351
d62a17ae 1352 /*
1353 * Add the peer to the target subgroup, while making sure that
1354 * any currently enqueued packets won't be sent to it. Enqueued
1355 * packets could, for example, result in an unnecessary withdraw
1356 * followed by an advertise.
1357 */
1358 update_subgroup_add_peer(target, paf, 0);
1359 }
3f9c7369 1360
d62a17ae 1361 SUBGRP_INCR_STAT(target, merge_events);
3f9c7369 1362
d62a17ae 1363 if (BGP_DEBUG(update_groups, UPDATE_GROUPS))
6cde4b45 1364 zlog_debug("u%" PRIu64 ":s%" PRIu64" (%d peers) merged into u%" PRIu64 ":s%" PRIu64", trigger: %s",
d62a17ae 1365 subgrp->update_group->id, subgrp->id, peer_count,
1366 target->update_group->id, target->id,
1367 reason ? reason : "unknown");
3f9c7369 1368
d62a17ae 1369 result = update_subgroup_check_delete(subgrp);
1370 assert(result);
3f9c7369
DS
1371}
1372
1373/*
1374 * update_subgroup_check_merge
1375 *
1376 * Merge this subgroup into another subgroup if possible.
1377 *
2951a7a4 1378 * Returns true if the subgroup has been merged. The subgroup pointer
3f9c7369
DS
1379 * should not be accessed in this case.
1380 */
3dc339cd
DA
1381bool update_subgroup_check_merge(struct update_subgroup *subgrp,
1382 const char *reason)
3f9c7369 1383{
d62a17ae 1384 struct update_subgroup *target;
3f9c7369 1385
d62a17ae 1386 if (!update_subgroup_ready_for_merge(subgrp))
3dc339cd 1387 return false;
3f9c7369 1388
d62a17ae 1389 /*
1390 * Look for a subgroup to merge into.
1391 */
a2addae8 1392 UPDGRP_FOREACH_SUBGRP (subgrp->update_group, target) {
d62a17ae 1393 if (update_subgroup_can_merge_into(subgrp, target))
1394 break;
1395 }
3f9c7369 1396
d62a17ae 1397 if (!target)
3dc339cd 1398 return false;
3f9c7369 1399
d62a17ae 1400 update_subgroup_merge(subgrp, target, reason);
3dc339cd 1401 return true;
3f9c7369
DS
1402}
1403
d62a17ae 1404/*
9d303b37
DL
1405* update_subgroup_merge_check_thread_cb
1406*/
cc9f21da 1407static void update_subgroup_merge_check_thread_cb(struct thread *thread)
3f9c7369 1408{
d62a17ae 1409 struct update_subgroup *subgrp;
3f9c7369 1410
d62a17ae 1411 subgrp = THREAD_ARG(thread);
3f9c7369 1412
d62a17ae 1413 subgrp->t_merge_check = NULL;
3f9c7369 1414
d62a17ae 1415 update_subgroup_check_merge(subgrp, "triggered merge check");
3f9c7369
DS
1416}
1417
1418/*
1419 * update_subgroup_trigger_merge_check
1420 *
1421 * Triggers a call to update_subgroup_check_merge() on a clean context.
1422 *
1423 * @param force If true, the merge check will be triggered even if the
1424 * subgroup doesn't currently look ready for a merge.
1425 *
2951a7a4 1426 * Returns true if a merge check will be performed shortly.
3f9c7369 1427 */
3dc339cd
DA
1428bool update_subgroup_trigger_merge_check(struct update_subgroup *subgrp,
1429 int force)
3f9c7369 1430{
d62a17ae 1431 if (subgrp->t_merge_check)
3dc339cd 1432 return true;
3f9c7369 1433
d62a17ae 1434 if (!force && !update_subgroup_ready_for_merge(subgrp))
3dc339cd 1435 return false;
3f9c7369 1436
d62a17ae 1437 subgrp->t_merge_check = NULL;
1438 thread_add_timer_msec(bm->master, update_subgroup_merge_check_thread_cb,
1439 subgrp, 0, &subgrp->t_merge_check);
3f9c7369 1440
d62a17ae 1441 SUBGRP_INCR_STAT(subgrp, merge_checks_triggered);
3f9c7369 1442
3dc339cd 1443 return true;
3f9c7369
DS
1444}
1445
1446/*
1447 * update_subgroup_copy_adj_out
1448 *
1449 * Helper function that clones the adj out (state about advertised
1450 * routes) from one subgroup to another. It assumes that the adj out
1451 * of the target subgroup is empty.
1452 */
d62a17ae 1453static void update_subgroup_copy_adj_out(struct update_subgroup *source,
1454 struct update_subgroup *dest)
3f9c7369 1455{
d62a17ae 1456 struct bgp_adj_out *aout, *aout_copy;
1457
a2addae8 1458 SUBGRP_FOREACH_ADJ (source, aout) {
d62a17ae 1459 /*
1460 * Copy the adj out.
1461 */
9bcb3eef
DS
1462 aout_copy = bgp_adj_out_alloc(dest, aout->dest,
1463 aout->addpath_tx_id);
d62a17ae 1464 aout_copy->attr =
7c87afac 1465 aout->attr ? bgp_attr_intern(aout->attr) : NULL;
d62a17ae 1466 }
0ab7b206
AD
1467
1468 dest->scount = source->scount;
3f9c7369
DS
1469}
1470
1471/*
1472 * update_subgroup_copy_packets
1473 *
1474 * Copy packets after and including the given packet to the subgroup
1475 * 'dest'.
1476 *
1477 * Returns the number of packets copied.
1478 */
d62a17ae 1479static int update_subgroup_copy_packets(struct update_subgroup *dest,
1480 struct bpacket *pkt)
3f9c7369 1481{
d62a17ae 1482 int count;
1483
1484 count = 0;
1485 while (pkt && pkt->buffer) {
1486 bpacket_queue_add(SUBGRP_PKTQ(dest), stream_dup(pkt->buffer),
1487 &pkt->arr);
1488 count++;
1489 pkt = bpacket_next(pkt);
1490 }
3f9c7369 1491
d62a17ae 1492 return count;
3f9c7369
DS
1493}
1494
3dc339cd
DA
1495static bool updgrp_prefix_list_update(struct update_group *updgrp,
1496 const char *name)
3f9c7369 1497{
d62a17ae 1498 struct peer *peer;
1499 struct bgp_filter *filter;
1500
1501 peer = UPDGRP_PEER(updgrp);
1502 filter = &peer->filter[UPDGRP_AFI(updgrp)][UPDGRP_SAFI(updgrp)];
1503
1504 if (PREFIX_LIST_OUT_NAME(filter)
1505 && (strcmp(name, PREFIX_LIST_OUT_NAME(filter)) == 0)) {
1506 PREFIX_LIST_OUT(filter) = prefix_list_lookup(
1507 UPDGRP_AFI(updgrp), PREFIX_LIST_OUT_NAME(filter));
3dc339cd 1508 return true;
d62a17ae 1509 }
3dc339cd 1510 return false;
3f9c7369
DS
1511}
1512
3dc339cd
DA
1513static bool updgrp_filter_list_update(struct update_group *updgrp,
1514 const char *name)
3f9c7369 1515{
d62a17ae 1516 struct peer *peer;
1517 struct bgp_filter *filter;
1518
1519 peer = UPDGRP_PEER(updgrp);
1520 filter = &peer->filter[UPDGRP_AFI(updgrp)][UPDGRP_SAFI(updgrp)];
1521
1522 if (FILTER_LIST_OUT_NAME(filter)
1523 && (strcmp(name, FILTER_LIST_OUT_NAME(filter)) == 0)) {
1524 FILTER_LIST_OUT(filter) =
1525 as_list_lookup(FILTER_LIST_OUT_NAME(filter));
3dc339cd 1526 return true;
d62a17ae 1527 }
3dc339cd 1528 return false;
3f9c7369
DS
1529}
1530
3dc339cd
DA
1531static bool updgrp_distribute_list_update(struct update_group *updgrp,
1532 const char *name)
3f9c7369 1533{
d62a17ae 1534 struct peer *peer;
1535 struct bgp_filter *filter;
1536
1537 peer = UPDGRP_PEER(updgrp);
1538 filter = &peer->filter[UPDGRP_AFI(updgrp)][UPDGRP_SAFI(updgrp)];
1539
1540 if (DISTRIBUTE_OUT_NAME(filter)
1541 && (strcmp(name, DISTRIBUTE_OUT_NAME(filter)) == 0)) {
1542 DISTRIBUTE_OUT(filter) = access_list_lookup(
1543 UPDGRP_AFI(updgrp), DISTRIBUTE_OUT_NAME(filter));
3dc339cd 1544 return true;
d62a17ae 1545 }
3dc339cd 1546 return false;
3f9c7369
DS
1547}
1548
d62a17ae 1549static int updgrp_route_map_update(struct update_group *updgrp,
1550 const char *name, int *def_rmap_changed)
3f9c7369 1551{
d62a17ae 1552 struct peer *peer;
1553 struct bgp_filter *filter;
1554 int changed = 0;
1555 afi_t afi;
1556 safi_t safi;
1557
1558 peer = UPDGRP_PEER(updgrp);
1559 afi = UPDGRP_AFI(updgrp);
1560 safi = UPDGRP_SAFI(updgrp);
1561 filter = &peer->filter[afi][safi];
1562
1563 if (ROUTE_MAP_OUT_NAME(filter)
1564 && (strcmp(name, ROUTE_MAP_OUT_NAME(filter)) == 0)) {
1565 ROUTE_MAP_OUT(filter) = route_map_lookup_by_name(name);
1566
1567 changed = 1;
1568 }
1569
1570 if (UNSUPPRESS_MAP_NAME(filter)
1571 && (strcmp(name, UNSUPPRESS_MAP_NAME(filter)) == 0)) {
1572 UNSUPPRESS_MAP(filter) = route_map_lookup_by_name(name);
1573 changed = 1;
1574 }
1575
1576 /* process default-originate route-map */
1577 if (peer->default_rmap[afi][safi].name
1578 && (strcmp(name, peer->default_rmap[afi][safi].name) == 0)) {
1579 peer->default_rmap[afi][safi].map =
1580 route_map_lookup_by_name(name);
1581 if (def_rmap_changed)
1582 *def_rmap_changed = 1;
1583 }
1584 return changed;
3f9c7369
DS
1585}
1586
1587/*
1588 * hash iteration callback function to process a policy change for an
1589 * update group. Check if the changed policy matches the updgrp's
1590 * outbound route-map or unsuppress-map or default-originate map or
1591 * filter-list or prefix-list or distribute-list.
1592 * Trigger update generation accordingly.
1593 */
d62a17ae 1594static int updgrp_policy_update_walkcb(struct update_group *updgrp, void *arg)
3f9c7369 1595{
d62a17ae 1596 struct updwalk_context *ctx = arg;
1597 struct update_subgroup *subgrp;
1598 int changed = 0;
1599 int def_changed = 0;
1600
1601 if (!updgrp || !ctx || !ctx->policy_name)
1602 return UPDWALK_CONTINUE;
1603
1604 switch (ctx->policy_type) {
1605 case BGP_POLICY_ROUTE_MAP:
1606 changed = updgrp_route_map_update(updgrp, ctx->policy_name,
1607 &def_changed);
1608 break;
1609 case BGP_POLICY_FILTER_LIST:
1610 changed = updgrp_filter_list_update(updgrp, ctx->policy_name);
1611 break;
1612 case BGP_POLICY_PREFIX_LIST:
1613 changed = updgrp_prefix_list_update(updgrp, ctx->policy_name);
1614 break;
1615 case BGP_POLICY_DISTRIBUTE_LIST:
1616 changed =
1617 updgrp_distribute_list_update(updgrp, ctx->policy_name);
1618 break;
1619 default:
1620 break;
1621 }
1622
1623 /* If not doing route update, return after updating "config" */
1624 if (!ctx->policy_route_update)
1625 return UPDWALK_CONTINUE;
1626
1627 /* If nothing has changed, return after updating "config" */
1628 if (!changed && !def_changed)
1629 return UPDWALK_CONTINUE;
1630
1631 /*
1632 * If something has changed, at the beginning of a route-map
1633 * modification
1634 * event, mark each subgroup's needs-refresh bit. For one, it signals to
1635 * whoever that the subgroup needs a refresh. Second, it prevents
1636 * premature
1637 * merge of this subgroup with another before a complete (outbound)
1638 * refresh.
1639 */
1640 if (ctx->policy_event_start_flag) {
a2addae8 1641 UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) {
d62a17ae 1642 update_subgroup_set_needs_refresh(subgrp, 1);
1643 }
1644 return UPDWALK_CONTINUE;
1645 }
1646
a2addae8 1647 UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) {
2adac256
DA
1648 /* Avoid supressing duplicate routes later
1649 * when processing in subgroup_announce_table().
1650 */
1651 SET_FLAG(subgrp->sflags, SUBGRP_STATUS_FORCE_UPDATES);
1652
d62a17ae 1653 if (changed) {
1654 if (bgp_debug_update(NULL, NULL, updgrp, 0))
1655 zlog_debug(
6cde4b45 1656 "u%" PRIu64 ":s%" PRIu64" announcing routes upon policy %s (type %d) change",
d62a17ae 1657 updgrp->id, subgrp->id,
1658 ctx->policy_name, ctx->policy_type);
1659 subgroup_announce_route(subgrp);
1660 }
1661 if (def_changed) {
1662 if (bgp_debug_update(NULL, NULL, updgrp, 0))
1663 zlog_debug(
6cde4b45 1664 "u%" PRIu64 ":s%" PRIu64" announcing default upon default routemap %s change",
d62a17ae 1665 updgrp->id, subgrp->id,
1666 ctx->policy_name);
a9ae9fb5
AR
1667 if (route_map_lookup_by_name(ctx->policy_name)) {
1668 /*
1669 * When there is change in routemap, this flow
1670 * is triggered. the routemap is still present
1671 * in lib, hence its a update flow. The flag
1672 * needs to be unset.
1673 */
1674 UNSET_FLAG(subgrp->sflags,
1675 SUBGRP_STATUS_DEFAULT_ORIGINATE);
1676 subgroup_default_originate(subgrp, 0);
1677 } else {
1678 /*
1679 * This is a explicit withdraw, since the
1680 * routemap is not present in routemap lib. need
1681 * to pass 1 for withdraw arg.
1682 */
1683 subgroup_default_originate(subgrp, 1);
1684 }
d62a17ae 1685 }
1686 update_subgroup_set_needs_refresh(subgrp, 0);
1687 }
1688 return UPDWALK_CONTINUE;
3f9c7369
DS
1689}
1690
e3b78da8 1691static int update_group_walkcb(struct hash_bucket *bucket, void *arg)
3f9c7369 1692{
e3b78da8 1693 struct update_group *updgrp = bucket->data;
d62a17ae 1694 struct updwalk_context *wctx = arg;
1695 int ret = (*wctx->cb)(updgrp, wctx->context);
1696 return ret;
3f9c7369
DS
1697}
1698
d62a17ae 1699static int update_group_periodic_merge_walkcb(struct update_group *updgrp,
1700 void *arg)
3f9c7369 1701{
d62a17ae 1702 struct update_subgroup *subgrp;
1703 struct update_subgroup *tmp_subgrp;
1704 const char *reason = arg;
3f9c7369 1705
a2addae8
RW
1706 UPDGRP_FOREACH_SUBGRP_SAFE (updgrp, subgrp, tmp_subgrp)
1707 update_subgroup_check_merge(subgrp, reason);
d62a17ae 1708 return UPDWALK_CONTINUE;
3f9c7369
DS
1709}
1710
1711/********************
1712 * PUBLIC FUNCTIONS
1713 ********************/
1714
1715/*
1716 * trigger function when a policy (route-map/filter-list/prefix-list/
1717 * distribute-list etc.) content changes. Go through all the
1718 * update groups and process the change.
1719 *
1720 * bgp: the bgp instance
1721 * ptype: the type of policy that got modified, see bgpd.h
1722 * pname: name of the policy
1723 * route_update: flag to control if an automatic update generation should
1724 * occur
1725 * start_event: flag that indicates if it's the beginning of the change.
1726 * Esp. when the user is changing the content interactively
1727 * over multiple statements. Useful to set dirty flag on
1728 * update groups.
1729 */
d54f55f2 1730void update_group_policy_update(struct bgp *bgp, enum bgp_policy_type ptype,
f1aa4929 1731 const char *pname, bool route_update,
d62a17ae 1732 int start_event)
3f9c7369 1733{
d62a17ae 1734 struct updwalk_context ctx;
3f9c7369 1735
d62a17ae 1736 memset(&ctx, 0, sizeof(ctx));
1737 ctx.policy_type = ptype;
1738 ctx.policy_name = pname;
1739 ctx.policy_route_update = route_update;
1740 ctx.policy_event_start_flag = start_event;
1741 ctx.flags = 0;
3f9c7369 1742
d62a17ae 1743 update_group_walk(bgp, updgrp_policy_update_walkcb, &ctx);
3f9c7369
DS
1744}
1745
1746/*
1747 * update_subgroup_split_peer
1748 *
1749 * Ensure that the given peer is in a subgroup of its own in the
1750 * specified update group.
1751 */
d62a17ae 1752void update_subgroup_split_peer(struct peer_af *paf,
1753 struct update_group *updgrp)
3f9c7369 1754{
d62a17ae 1755 struct update_subgroup *old_subgrp, *subgrp;
1756 uint64_t old_id;
1757
1758
1759 old_subgrp = paf->subgroup;
1760
1761 if (!updgrp)
1762 updgrp = old_subgrp->update_group;
1763
1764 /*
1765 * If the peer is alone in its subgroup, reuse the existing
1766 * subgroup.
1767 */
1768 if (old_subgrp->peer_count == 1) {
1769 if (updgrp == old_subgrp->update_group)
1770 return;
1771
1772 subgrp = old_subgrp;
1773 old_id = old_subgrp->update_group->id;
1774
1775 if (bgp_debug_peer_updout_enabled(paf->peer->host)) {
1776 UPDGRP_PEER_DBG_DIS(old_subgrp->update_group);
1777 }
1778
1779 update_group_remove_subgroup(old_subgrp->update_group,
1780 old_subgrp);
1781 update_group_add_subgroup(updgrp, subgrp);
1782
1783 if (bgp_debug_peer_updout_enabled(paf->peer->host)) {
1784 UPDGRP_PEER_DBG_EN(updgrp);
1785 }
1786 if (BGP_DEBUG(update_groups, UPDATE_GROUPS))
6cde4b45 1787 zlog_debug("u%" PRIu64 ":s%" PRIu64" peer %s moved to u%" PRIu64 ":s%" PRIu64,
d62a17ae 1788 old_id, subgrp->id, paf->peer->host,
1789 updgrp->id, subgrp->id);
1790
1791 /*
1792 * The state of the subgroup (adj_out, advs, packet queue etc)
1793 * is consistent internally, but may not be identical to other
1794 * subgroups in the new update group even if the version number
1795 * matches up. Make sure a full refresh is done before the
1796 * subgroup is merged with another.
1797 */
1798 update_subgroup_set_needs_refresh(subgrp, 1);
1799
1800 SUBGRP_INCR_STAT(subgrp, updgrp_switch_events);
1801 return;
1802 }
3f9c7369 1803
d62a17ae 1804 /*
1805 * Create a new subgroup under the specified update group, and copy
1806 * over relevant state to it.
1807 */
1808 subgrp = update_subgroup_create(updgrp);
1809 update_subgroup_inherit_info(subgrp, old_subgrp);
1810
1811 subgrp->split_from.update_group_id = old_subgrp->update_group->id;
1812 subgrp->split_from.subgroup_id = old_subgrp->id;
1813
1814 /*
1815 * Copy out relevant state from the old subgroup.
1816 */
1817 update_subgroup_copy_adj_out(paf->subgroup, subgrp);
1818 update_subgroup_copy_packets(subgrp, paf->next_pkt_to_send);
1819
1820 if (BGP_DEBUG(update_groups, UPDATE_GROUPS))
6cde4b45 1821 zlog_debug("u%" PRIu64 ":s%" PRIu64" peer %s split and moved into u%" PRIu64":s%" PRIu64,
d62a17ae 1822 paf->subgroup->update_group->id, paf->subgroup->id,
1823 paf->peer->host, updgrp->id, subgrp->id);
1824
1825 SUBGRP_INCR_STAT(paf->subgroup, split_events);
1826
1827 /*
1828 * Since queued advs were left behind, this new subgroup needs a
1829 * refresh.
1830 */
1831 update_subgroup_set_needs_refresh(subgrp, 1);
1832
1833 /*
1834 * Remove peer from old subgroup, and add it to the new one.
1835 */
1836 update_subgroup_remove_peer(paf->subgroup, paf);
1837
1838 update_subgroup_add_peer(subgrp, paf, 1);
3f9c7369
DS
1839}
1840
d62a17ae 1841void update_bgp_group_init(struct bgp *bgp)
3f9c7369 1842{
d62a17ae 1843 int afid;
3f9c7369 1844
a2addae8 1845 AF_FOREACH (afid)
3f65c5b1 1846 bgp->update_groups[afid] =
996c9314 1847 hash_create(updgrp_hash_key_make, updgrp_hash_cmp,
3f65c5b1 1848 "BGP Update Group Hash");
3f9c7369
DS
1849}
1850
d62a17ae 1851void update_bgp_group_free(struct bgp *bgp)
3d68677e 1852{
d62a17ae 1853 int afid;
1854
a2addae8 1855 AF_FOREACH (afid) {
d62a17ae 1856 if (bgp->update_groups[afid]) {
1857 hash_free(bgp->update_groups[afid]);
1858 bgp->update_groups[afid] = NULL;
1859 }
1860 }
3d68677e
DS
1861}
1862
d62a17ae 1863void update_group_show(struct bgp *bgp, afi_t afi, safi_t safi, struct vty *vty,
fa5a9276 1864 uint64_t subgrp_id, bool uj)
3f9c7369 1865{
d62a17ae 1866 struct updwalk_context ctx;
fa5a9276
AR
1867 json_object *json_vrf_obj = NULL;
1868
d62a17ae 1869 memset(&ctx, 0, sizeof(ctx));
1870 ctx.vty = vty;
1871 ctx.subgrp_id = subgrp_id;
fa5a9276
AR
1872 ctx.uj = uj;
1873
1874 if (uj) {
1875 ctx.json_updategrps = json_object_new_object();
1876 json_vrf_obj = json_object_new_object();
1877 }
8fe8a7f6 1878
d62a17ae 1879 update_group_af_walk(bgp, afi, safi, update_group_show_walkcb, &ctx);
fa5a9276
AR
1880
1881 if (uj) {
1882 const char *vname;
1883
1884 if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
1885 vname = VRF_DEFAULT_NAME;
1886 else
1887 vname = bgp->name;
1888 json_object_object_add(json_vrf_obj, vname,
1889 ctx.json_updategrps);
1890 vty_json(vty, json_vrf_obj);
1891 }
3f9c7369
DS
1892}
1893
1894/*
1895 * update_group_show_stats
1896 *
1897 * Show global statistics about update groups.
1898 */
d62a17ae 1899void update_group_show_stats(struct bgp *bgp, struct vty *vty)
3f9c7369 1900{
d62a17ae 1901 vty_out(vty, "Update groups created: %u\n",
1902 bgp->update_group_stats.updgrps_created);
1903 vty_out(vty, "Update groups deleted: %u\n",
1904 bgp->update_group_stats.updgrps_deleted);
1905 vty_out(vty, "Update subgroups created: %u\n",
1906 bgp->update_group_stats.subgrps_created);
1907 vty_out(vty, "Update subgroups deleted: %u\n",
1908 bgp->update_group_stats.subgrps_deleted);
1909 vty_out(vty, "Join events: %u\n", bgp->update_group_stats.join_events);
1910 vty_out(vty, "Prune events: %u\n",
1911 bgp->update_group_stats.prune_events);
1912 vty_out(vty, "Merge events: %u\n",
1913 bgp->update_group_stats.merge_events);
1914 vty_out(vty, "Split events: %u\n",
1915 bgp->update_group_stats.split_events);
1916 vty_out(vty, "Update group switch events: %u\n",
1917 bgp->update_group_stats.updgrp_switch_events);
1918 vty_out(vty, "Peer route refreshes combined: %u\n",
1919 bgp->update_group_stats.peer_refreshes_combined);
1920 vty_out(vty, "Merge checks triggered: %u\n",
1921 bgp->update_group_stats.merge_checks_triggered);
3f9c7369
DS
1922}
1923
1924/*
1925 * update_group_adjust_peer
1926 */
d62a17ae 1927void update_group_adjust_peer(struct peer_af *paf)
3f9c7369 1928{
d62a17ae 1929 struct update_group *updgrp;
1930 struct update_subgroup *subgrp, *old_subgrp;
1931 struct peer *peer;
1932
1933 if (!paf)
1934 return;
1935
1936 peer = PAF_PEER(paf);
1937 if (!peer_established(peer)) {
1938 return;
1939 }
1940
1941 if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)) {
1942 return;
3f9c7369 1943 }
3f9c7369 1944
d62a17ae 1945 if (!peer->afc_nego[paf->afi][paf->safi]) {
1946 return;
1947 }
3f9c7369 1948
d62a17ae 1949 updgrp = update_group_find(paf);
1950 if (!updgrp) {
1951 updgrp = update_group_create(paf);
1952 if (!updgrp) {
e50f7cfd 1953 flog_err(EC_BGP_UPDGRP_CREATE,
1c50c1c0
QY
1954 "couldn't create update group for peer %s",
1955 paf->peer->host);
d62a17ae 1956 return;
1957 }
1958 }
3f9c7369 1959
d62a17ae 1960 old_subgrp = paf->subgroup;
3f9c7369 1961
d62a17ae 1962 if (old_subgrp) {
3f9c7369 1963
d62a17ae 1964 /*
1965 * If the update group of the peer is unchanged, the peer can
1966 * stay
1967 * in its existing subgroup and we're done.
1968 */
1969 if (old_subgrp->update_group == updgrp)
1970 return;
1971
1972 /*
1973 * The peer is switching between update groups. Put it in its
1974 * own subgroup under the new update group.
1975 */
1976 update_subgroup_split_peer(paf, updgrp);
1977 return;
1978 }
1979
1980 subgrp = update_subgroup_find(updgrp, paf);
1981 if (!subgrp) {
1982 subgrp = update_subgroup_create(updgrp);
1983 if (!subgrp)
1984 return;
1985 }
3f9c7369 1986
d62a17ae 1987 update_subgroup_add_peer(subgrp, paf, 1);
1988 if (BGP_DEBUG(update_groups, UPDATE_GROUPS))
1989 zlog_debug("u%" PRIu64 ":s%" PRIu64 " add peer %s", updgrp->id,
1990 subgrp->id, paf->peer->host);
1991
1992 return;
3f9c7369
DS
1993}
1994
d62a17ae 1995int update_group_adjust_soloness(struct peer *peer, int set)
3f9c7369 1996{
d62a17ae 1997 struct peer_group *group;
1998 struct listnode *node, *nnode;
1999
2000 if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
2001 peer_lonesoul_or_not(peer, set);
feb17238 2002 if (peer_established(peer))
d62a17ae 2003 bgp_announce_route_all(peer);
2004 } else {
2005 group = peer->group;
2006 for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
2007 peer_lonesoul_or_not(peer, set);
feb17238 2008 if (peer_established(peer))
d62a17ae 2009 bgp_announce_route_all(peer);
2010 }
2011 }
2012 return 0;
3f9c7369
DS
2013}
2014
2015/*
2016 * update_subgroup_rib
2017 */
d62a17ae 2018struct bgp_table *update_subgroup_rib(struct update_subgroup *subgrp)
3f9c7369 2019{
d62a17ae 2020 struct bgp *bgp;
3f9c7369 2021
d62a17ae 2022 bgp = SUBGRP_INST(subgrp);
2023 if (!bgp)
2024 return NULL;
3f9c7369 2025
d62a17ae 2026 return bgp->rib[SUBGRP_AFI(subgrp)][SUBGRP_SAFI(subgrp)];
3f9c7369
DS
2027}
2028
d62a17ae 2029void update_group_af_walk(struct bgp *bgp, afi_t afi, safi_t safi,
2030 updgrp_walkcb cb, void *ctx)
3f9c7369 2031{
d62a17ae 2032 struct updwalk_context wctx;
2033 int afid;
3f9c7369 2034
d62a17ae 2035 if (!bgp)
2036 return;
2037 afid = afindex(afi, safi);
2038 if (afid >= BGP_AF_MAX)
2039 return;
3f9c7369 2040
d62a17ae 2041 memset(&wctx, 0, sizeof(wctx));
2042 wctx.cb = cb;
2043 wctx.context = ctx;
0de4848d 2044
d62a17ae 2045 if (bgp->update_groups[afid])
2046 hash_walk(bgp->update_groups[afid], update_group_walkcb, &wctx);
3f9c7369
DS
2047}
2048
d62a17ae 2049void update_group_walk(struct bgp *bgp, updgrp_walkcb cb, void *ctx)
3f9c7369 2050{
d62a17ae 2051 afi_t afi;
2052 safi_t safi;
3f9c7369 2053
a2addae8 2054 FOREACH_AFI_SAFI (afi, safi) {
d62a17ae 2055 update_group_af_walk(bgp, afi, safi, cb, ctx);
2056 }
3f9c7369
DS
2057}
2058
d62a17ae 2059void update_group_periodic_merge(struct bgp *bgp)
3f9c7369 2060{
d62a17ae 2061 char reason[] = "periodic merge check";
3f9c7369 2062
d62a17ae 2063 update_group_walk(bgp, update_group_periodic_merge_walkcb,
2064 (void *)reason);
3f9c7369
DS
2065}
2066
0de4848d
DS
2067static int
2068update_group_default_originate_route_map_walkcb(struct update_group *updgrp,
d62a17ae 2069 void *arg)
0de4848d 2070{
d62a17ae 2071 struct update_subgroup *subgrp;
2072 struct peer *peer;
2073 afi_t afi;
2074 safi_t safi;
2075
a2addae8 2076 UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) {
d62a17ae 2077 peer = SUBGRP_PEER(subgrp);
2078 afi = SUBGRP_AFI(subgrp);
2079 safi = SUBGRP_SAFI(subgrp);
2080
2081 if (peer->default_rmap[afi][safi].name) {
a9ae9fb5
AR
2082 /*
2083 * When there is change in routemap this flow will
2084 * be triggered. We need to unset the Flag to ensure
2085 * the update flow gets triggered.
2086 */
2087 UNSET_FLAG(subgrp->sflags,
2088 SUBGRP_STATUS_DEFAULT_ORIGINATE);
d62a17ae 2089 subgroup_default_originate(subgrp, 0);
2090 }
2091 }
2092
2093 return UPDWALK_CONTINUE;
0de4848d
DS
2094}
2095
cc9f21da 2096void update_group_refresh_default_originate_route_map(struct thread *thread)
0de4848d 2097{
d62a17ae 2098 struct bgp *bgp;
2099 char reason[] = "refresh default-originate route-map";
0de4848d 2100
d62a17ae 2101 bgp = THREAD_ARG(thread);
2102 update_group_walk(bgp, update_group_default_originate_route_map_walkcb,
2103 reason);
c3aaa89a 2104 THREAD_OFF(bgp->t_rmap_def_originate_eval);
d62a17ae 2105 bgp_unlock(bgp);
0de4848d
DS
2106}
2107
3f9c7369
DS
2108/*
2109 * peer_af_announce_route
2110 *
2111 * Refreshes routes out to a peer_af immediately.
2112 *
2951a7a4 2113 * If the combine parameter is true, then this function will try to
3f9c7369
DS
2114 * gather other peers in the subgroup for which a route announcement
2115 * is pending and efficently announce routes to all of them.
2116 *
2117 * For now, the 'combine' option has an effect only if all peers in
2118 * the subgroup have a route announcement pending.
2119 */
d62a17ae 2120void peer_af_announce_route(struct peer_af *paf, int combine)
3f9c7369 2121{
d62a17ae 2122 struct update_subgroup *subgrp;
2123 struct peer_af *cur_paf;
2124 int all_pending;
2125
2126 subgrp = paf->subgroup;
2127 all_pending = 0;
2128
2129 if (combine) {
2130 /*
2131 * If there are other peers in the old subgroup that also need
2132 * routes to be announced, pull them into the peer's new
2133 * subgroup.
2134 * Combine route announcement with other peers if possible.
2135 *
2136 * For now, we combine only if all peers in the subgroup have an
2137 * announcement pending.
2138 */
2139 all_pending = 1;
2140
a2addae8 2141 SUBGRP_FOREACH_PEER (subgrp, cur_paf) {
d62a17ae 2142 if (cur_paf == paf)
2143 continue;
2144
2145 if (cur_paf->t_announce_route)
2146 continue;
2147
2148 all_pending = 0;
2149 break;
2150 }
2151 }
2152 /*
2153 * Announce to the peer alone if we were not asked to combine peers,
2154 * or if some peers don't have a route annoucement pending.
2155 */
2156 if (!combine || !all_pending) {
2157 update_subgroup_split_peer(paf, NULL);
7bfdba54 2158 subgrp = paf->subgroup;
d62a17ae 2159
7bfdba54 2160 assert(subgrp && subgrp->update_group);
d62a17ae 2161 if (bgp_debug_update(paf->peer, NULL, subgrp->update_group, 0))
6cde4b45 2162 zlog_debug("u%" PRIu64 ":s%" PRIu64" %s announcing routes",
d62a17ae 2163 subgrp->update_group->id, subgrp->id,
2164 paf->peer->host);
2165
2166 subgroup_announce_route(paf->subgroup);
2167 return;
3f9c7369 2168 }
3f9c7369 2169
d62a17ae 2170 /*
2171 * We will announce routes the entire subgroup.
2172 *
2173 * First stop refresh timers on all the other peers.
2174 */
a2addae8 2175 SUBGRP_FOREACH_PEER (subgrp, cur_paf) {
d62a17ae 2176 if (cur_paf == paf)
2177 continue;
3f9c7369 2178
d62a17ae 2179 bgp_stop_announce_route_timer(cur_paf);
2180 }
3f9c7369 2181
d62a17ae 2182 if (bgp_debug_update(paf->peer, NULL, subgrp->update_group, 0))
6cde4b45 2183 zlog_debug("u%" PRIu64 ":s%" PRIu64" announcing routes to %s, combined into %d peers",
d62a17ae 2184 subgrp->update_group->id, subgrp->id,
2185 paf->peer->host, subgrp->peer_count);
3f9c7369 2186
d62a17ae 2187 subgroup_announce_route(subgrp);
3f9c7369 2188
d62a17ae 2189 SUBGRP_INCR_STAT_BY(subgrp, peer_refreshes_combined,
2190 subgrp->peer_count - 1);
3f9c7369
DS
2191}
2192
2fc102e1
QY
2193void subgroup_trigger_write(struct update_subgroup *subgrp)
2194{
2195 struct peer_af *paf;
2196
becedef6
QY
2197 /*
2198 * For each peer in the subgroup, schedule a job to pull packets from
2199 * the subgroup output queue into their own output queue. This action
2200 * will trigger a write job on the I/O thread.
2201 */
996c9314 2202 SUBGRP_FOREACH_PEER (subgrp, paf)
feb17238 2203 if (peer_established(paf->peer))
996c9314
LB
2204 thread_add_timer_msec(
2205 bm->master, bgp_generate_updgrp_packets,
2206 paf->peer, 0,
2207 &paf->peer->t_generate_updgrp_packets);
2fc102e1
QY
2208}
2209
d62a17ae 2210int update_group_clear_update_dbg(struct update_group *updgrp, void *arg)
3f9c7369 2211{
d62a17ae 2212 UPDGRP_PEER_DBG_OFF(updgrp);
2213 return UPDWALK_CONTINUE;
3f9c7369 2214}
adbac85e 2215
06370dac 2216/* Return true if we should addpath encode NLRI to this peer */
be92fc9f 2217bool bgp_addpath_encode_tx(struct peer *peer, afi_t afi, safi_t safi)
adbac85e 2218{
d62a17ae 2219 return (CHECK_FLAG(peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_TX_ADV)
2220 && CHECK_FLAG(peer->af_cap[afi][safi],
2221 PEER_CAP_ADDPATH_AF_RX_RCV));
adbac85e 2222}
b1dd7180 2223
8ccee4b8
DA
2224bool bgp_addpath_capable(struct bgp_path_info *bpi, struct peer *peer,
2225 afi_t afi, safi_t safi)
2226{
2227 return (bgp_addpath_tx_path(peer->addpath_type[afi][safi], bpi) ||
2228 (safi == SAFI_LABELED_UNICAST &&
2229 bgp_addpath_tx_path(peer->addpath_type[afi][SAFI_UNICAST],
2230 bpi)));
2231}
2232
b1dd7180
DA
2233bool bgp_check_selected(struct bgp_path_info *bpi, struct peer *peer,
2234 bool addpath_capable, afi_t afi, safi_t safi)
2235{
2236 return (CHECK_FLAG(bpi->flags, BGP_PATH_SELECTED) ||
8ccee4b8 2237 (addpath_capable && bgp_addpath_capable(bpi, peer, afi, safi)));
b1dd7180 2238}