]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_updgrp_adv.c
Ensure that during event-driven route-map processing, the peer status is
[mirror_frr.git] / bgpd / bgp_updgrp_adv.c
CommitLineData
3f9c7369
DS
1/**
2 * bgp_updgrp_adv.c: BGP update group advertisement and adjacency
3 * maintenance
4 *
5 *
6 * @copyright Copyright (C) 2014 Cumulus Networks, Inc.
7 *
8 * @author Avneesh Sachdev <avneesh@sproute.net>
9 * @author Rajesh Varadarajan <rajesh@sproute.net>
10 * @author Pradosh Mohapatra <pradosh@sproute.net>
11 *
12 * This file is part of GNU Zebra.
13 *
14 * GNU Zebra is free software; you can redistribute it and/or modify it
15 * under the terms of the GNU General Public License as published by the
16 * Free Software Foundation; either version 2, or (at your option) any
17 * later version.
18 *
19 * GNU Zebra is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with GNU Zebra; see the file COPYING. If not, write to the Free
26 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 */
29
30#include <zebra.h>
31
32#include "command.h"
33#include "memory.h"
34#include "prefix.h"
35#include "hash.h"
36#include "thread.h"
37#include "queue.h"
38#include "routemap.h"
39
40#include "bgpd/bgpd.h"
41#include "bgpd/bgp_table.h"
42#include "bgpd/bgp_debug.h"
43#include "bgpd/bgp_route.h"
44#include "bgpd/bgp_advertise.h"
45#include "bgpd/bgp_attr.h"
46#include "bgpd/bgp_aspath.h"
47#include "bgpd/bgp_packet.h"
48#include "bgpd/bgp_fsm.h"
49#include "bgpd/bgp_mplsvpn.h"
50#include "bgpd/bgp_updgrp.h"
51#include "bgpd/bgp_advertise.h"
52
53
54/********************
55 * PRIVATE FUNCTIONS
56 ********************/
57
58static inline struct bgp_adj_out *
59adj_lookup (struct bgp_node *rn, struct update_subgroup *subgrp)
60{
61 struct bgp_adj_out *adj;
62
63 if (!rn || !subgrp)
64 return NULL;
65 for (adj = rn->adj_out; adj; adj = adj->next)
66 if (adj->subgroup == subgrp)
67 break;
68 return adj;
69}
70
71static void
72adj_free (struct bgp_adj_out *adj)
73{
74 TAILQ_REMOVE (&(adj->subgroup->adjq), adj, subgrp_adj_train);
75 SUBGRP_DECR_STAT (adj->subgroup, adj_count);
76 XFREE (MTYPE_BGP_ADJ_OUT, adj);
77}
78
79static int
80group_announce_route_walkcb (struct update_group *updgrp, void *arg)
81{
82 struct updwalk_context *ctx = arg;
83 struct update_subgroup *subgrp;
84
85 UPDGRP_FOREACH_SUBGRP (updgrp, subgrp)
86 {
87
88 /*
89 * Skip the subgroups that have coalesce timer running. We will
90 * walk the entire prefix table for those subgroups when the
91 * coalesce timer fires.
92 */
93 if (!subgrp->t_coalesce)
94 subgroup_process_announce_selected (subgrp, ctx->ri, ctx->rn);
95 }
96
97 return UPDWALK_CONTINUE;
98}
99
100static void
101subgrp_show_adjq_vty (struct update_subgroup *subgrp, struct vty *vty,
102 u_int8_t flags)
103{
104 struct bgp_table *table;
105 struct bgp_adj_out *adj;
106 unsigned long output_count;
107 struct bgp_node *rn;
108 int header1 = 1;
109 struct bgp *bgp;
110 int header2 = 1;
111
112 bgp = SUBGRP_INST (subgrp);
113 if (!bgp)
114 return;
115
116 table = bgp->rib[SUBGRP_AFI (subgrp)][SUBGRP_SAFI (subgrp)];
117
118 output_count = 0;
119
120 for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
121 for (adj = rn->adj_out; adj; adj = adj->next)
122 if (adj->subgroup == subgrp)
123 {
124 if (header1)
125 {
126 vty_out (vty,
127 "BGP table version is %llu, local router ID is %s%s",
128 table->version, inet_ntoa (bgp->router_id),
129 VTY_NEWLINE);
130 vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
131 vty_out (vty, BGP_SHOW_OCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
132 header1 = 0;
133 }
134 if (header2)
135 {
136 vty_out (vty, BGP_SHOW_HEADER, VTY_NEWLINE);
137 header2 = 0;
138 }
139 if ((flags & UPDWALK_FLAGS_ADVQUEUE) && adj->adv && adj->adv->baa)
140 {
141 route_vty_out_tmp (vty, &rn->p, adj->adv->baa->attr,
b05a1c8b 142 SUBGRP_SAFI (subgrp));
3f9c7369
DS
143 output_count++;
144 }
145 if ((flags & UPDWALK_FLAGS_ADVERTISED) && adj->attr)
146 {
b05a1c8b 147 route_vty_out_tmp (vty, &rn->p, adj->attr, SUBGRP_SAFI (subgrp));
3f9c7369
DS
148 output_count++;
149 }
150 }
151 if (output_count != 0)
152 vty_out (vty, "%sTotal number of prefixes %ld%s",
153 VTY_NEWLINE, output_count, VTY_NEWLINE);
154}
155
156static int
157updgrp_show_adj_walkcb (struct update_group *updgrp, void *arg)
158{
159 struct updwalk_context *ctx = arg;
160 struct update_subgroup *subgrp;
161 struct vty *vty;
162
163 vty = ctx->vty;
164 UPDGRP_FOREACH_SUBGRP (updgrp, subgrp)
165 {
166 if (ctx->subgrp_id && (ctx->subgrp_id != subgrp->id))
167 continue;
168 vty_out (vty, "update group %llu, subgroup %llu%s", updgrp->id,
169 subgrp->id, VTY_NEWLINE);
170 subgrp_show_adjq_vty (subgrp, vty, ctx->flags);
171 }
172 return UPDWALK_CONTINUE;
173}
174
175static void
176updgrp_show_adj (struct bgp *bgp, afi_t afi, safi_t safi,
177 struct vty *vty, u_int64_t id, u_int8_t flags)
178{
179 struct updwalk_context ctx;
180 memset (&ctx, 0, sizeof (ctx));
181 ctx.vty = vty;
182 ctx.subgrp_id = id;
183 ctx.flags = flags;
184
185 update_group_af_walk (bgp, afi, safi, updgrp_show_adj_walkcb, &ctx);
186}
187
188static int
189subgroup_coalesce_timer (struct thread *thread)
190{
191 struct update_subgroup *subgrp;
192
193 subgrp = THREAD_ARG (thread);
194 if (bgp_debug_update(NULL, NULL, subgrp->update_group, 0))
195 zlog_debug ("u%llu:s%llu announcing routes upon coalesce timer expiry",
196 (SUBGRP_UPDGRP (subgrp))->id, subgrp->id);
197 subgrp->t_coalesce = NULL;
198 subgrp->v_coalesce = 0;
199 subgroup_announce_route (subgrp);
200
201
202 /* While the announce_route() may kick off the route advertisement timer for
203 * the members of the subgroup, we'd like to send the initial updates much
204 * faster (i.e., without enforcing MRAI). Also, if there were no routes to
205 * announce, this is the method currently employed to trigger the EOR.
206 */
207 if (!bgp_update_delay_active(SUBGRP_INST(subgrp)))
208 {
209 struct peer_af *paf;
210 struct peer *peer;
211
212 SUBGRP_FOREACH_PEER (subgrp, paf)
213 {
214 peer = PAF_PEER(paf);
215 BGP_TIMER_OFF(peer->t_routeadv);
216 BGP_TIMER_ON (peer->t_routeadv, bgp_routeadv_timer, 0);
217 }
218 }
219
220 return 0;
221}
222
223static int
224update_group_announce_walkcb (struct update_group *updgrp, void *arg)
225{
226 struct update_subgroup *subgrp;
227
228 UPDGRP_FOREACH_SUBGRP (updgrp, subgrp)
229 {
230 subgroup_announce_all (subgrp);
231 }
232
233 return UPDWALK_CONTINUE;
234}
235
236static int
237update_group_announce_rrc_walkcb (struct update_group *updgrp, void *arg)
238{
239 struct update_subgroup *subgrp;
240 afi_t afi;
241 safi_t safi;
242 struct peer *peer;
243
244 afi = UPDGRP_AFI (updgrp);
245 safi = UPDGRP_SAFI (updgrp);
246 peer = UPDGRP_PEER (updgrp);
247
248 /* Only announce if this is a group of route-reflector-clients */
249 if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT))
250 {
251 UPDGRP_FOREACH_SUBGRP (updgrp, subgrp)
252 {
253 subgroup_announce_all (subgrp);
254 }
255 }
256
257 return UPDWALK_CONTINUE;
258}
259
260/********************
261 * PUBLIC FUNCTIONS
262 ********************/
263
264/**
265 * Allocate an adj-out object. Do proper initialization of its fields,
266 * primarily its association with the subgroup and the prefix.
267 */
268struct bgp_adj_out *
269bgp_adj_out_alloc (struct update_subgroup *subgrp, struct bgp_node *rn)
270{
271 struct bgp_adj_out *adj;
272
273 adj = XCALLOC (MTYPE_BGP_ADJ_OUT, sizeof (struct bgp_adj_out));
274 adj->subgroup = subgrp;
275 if (rn)
276 {
277 BGP_ADJ_OUT_ADD (rn, adj);
278 bgp_lock_node (rn);
279 adj->rn = rn;
280 }
281 TAILQ_INSERT_TAIL (&(subgrp->adjq), adj, subgrp_adj_train);
282 SUBGRP_INCR_STAT (subgrp, adj_count);
283 return adj;
284}
285
286
287struct bgp_advertise *
288bgp_advertise_clean_subgroup (struct update_subgroup *subgrp,
289 struct bgp_adj_out *adj)
290{
291 struct bgp_advertise *adv;
292 struct bgp_advertise_attr *baa;
293 struct bgp_advertise *next;
294 struct bgp_advertise_fifo *fhead;
295
296 adv = adj->adv;
297 baa = adv->baa;
298 next = NULL;
299
300 if (baa)
301 {
302 fhead = &subgrp->sync->update;
303
304 /* Unlink myself from advertise attribute FIFO. */
305 bgp_advertise_delete (baa, adv);
306
307 /* Fetch next advertise candidate. */
308 next = baa->adv;
309
310 /* Unintern BGP advertise attribute. */
311 bgp_advertise_unintern (subgrp->hash, baa);
312 }
313 else
314 fhead = &subgrp->sync->withdraw;
315
316
317 /* Unlink myself from advertisement FIFO. */
318 BGP_ADV_FIFO_DEL (fhead, adv);
319
320 /* Free memory. */
321 bgp_advertise_free (adj->adv);
322 adj->adv = NULL;
323
324 return next;
325}
326
327void
328bgp_adj_out_set_subgroup (struct bgp_node *rn,
329 struct update_subgroup *subgrp,
330 struct attr *attr, struct bgp_info *binfo)
331{
332 struct bgp_adj_out *adj = NULL;
333 struct bgp_advertise *adv;
334
335 if (DISABLE_BGP_ANNOUNCE)
336 return;
337
338 /* Look for adjacency information. */
339 adj = adj_lookup (rn, subgrp);
340
341 if (!adj)
342 {
343 adj = bgp_adj_out_alloc (subgrp, rn);
344 if (!adj)
345 return;
346 }
347
348 if (adj->adv)
349 bgp_advertise_clean_subgroup (subgrp, adj);
350 adj->adv = bgp_advertise_new ();
351
352 adv = adj->adv;
353 adv->rn = rn;
354 assert (adv->binfo == NULL);
355 adv->binfo = bgp_info_lock (binfo); /* bgp_info adj_out reference */
356
357 if (attr)
358 adv->baa = bgp_advertise_intern (subgrp->hash, attr);
359 else
360 adv->baa = baa_new ();
361 adv->adj = adj;
362
363 /* Add new advertisement to advertisement attribute list. */
364 bgp_advertise_add (adv->baa, adv);
365
366 /*
367 * If the update adv list is empty, trigger the member peers'
368 * mrai timers so the socket writes can happen.
369 */
370 if (BGP_ADV_FIFO_EMPTY (&subgrp->sync->update))
371 {
372 struct peer_af *paf;
373
374 SUBGRP_FOREACH_PEER (subgrp, paf)
375 {
376 bgp_adjust_routeadv (PAF_PEER (paf));
377 }
378 }
379
380 BGP_ADV_FIFO_ADD (&subgrp->sync->update, &adv->fifo);
381
382 subgrp->version = max (subgrp->version, rn->version);
383}
384
385void
386bgp_adj_out_unset_subgroup (struct bgp_node *rn,
387 struct update_subgroup *subgrp)
388{
389 struct bgp_adj_out *adj;
390 struct bgp_advertise *adv;
391
392 if (DISABLE_BGP_ANNOUNCE)
393 return;
394
395 /* Lookup existing adjacency, if it is not there return immediately. */
396 adj = adj_lookup (rn, subgrp);
397
398 if (!adj)
399 goto done;
400
401 /* Clearn up previous advertisement. */
402 if (adj->adv)
403 bgp_advertise_clean_subgroup (subgrp, adj);
404
405 if (adj->attr)
406 {
407 /* We need advertisement structure. */
408 adj->adv = bgp_advertise_new ();
409 adv = adj->adv;
410 adv->rn = rn;
411 adv->adj = adj;
412
413 /* Schedule packet write, if FIFO is getting its first entry. */
414 if (BGP_ADV_FIFO_EMPTY (&subgrp->sync->withdraw))
415 subgroup_trigger_write(subgrp);
416
417 /* Add to synchronization entry for withdraw announcement. */
418 BGP_ADV_FIFO_ADD (&subgrp->sync->withdraw, &adv->fifo);
419 }
420 else
421 {
422 /* Remove myself from adjacency. */
423 BGP_ADJ_OUT_DEL (rn, adj);
424
425 /* Free allocated information. */
426 adj_free (adj);
427
428 bgp_unlock_node (rn);
429 }
430
431 /*
432 * Fall through.
433 */
434
435done:
436 subgrp->version = max (subgrp->version, rn->version);
437}
438
439void
440bgp_adj_out_remove_subgroup (struct bgp_node *rn, struct bgp_adj_out *adj,
441 struct update_subgroup *subgrp)
442{
443 if (adj->attr)
444 bgp_attr_unintern (&adj->attr);
445
446 if (adj->adv)
447 bgp_advertise_clean_subgroup (subgrp, adj);
448
449 BGP_ADJ_OUT_DEL (rn, adj);
450 adj_free (adj);
451}
452
453/*
454 * Go through all the routes and clean up the adj/adv structures corresponding
455 * to the subgroup.
456 */
457void
458subgroup_clear_table (struct update_subgroup *subgrp)
459{
460 struct bgp_adj_out *aout, *taout;
461
462 SUBGRP_FOREACH_ADJ_SAFE (subgrp, aout, taout)
463 {
464 bgp_unlock_node (aout->rn);
465 bgp_adj_out_remove_subgroup (aout->rn, aout, subgrp);
466 }
467}
468
469/*
470 * subgroup_announce_table
471 */
472void
473subgroup_announce_table (struct update_subgroup *subgrp,
474 struct bgp_table *table, int rsclient)
475{
476 struct bgp_node *rn;
477 struct bgp_info *ri;
478 struct attr attr;
479 struct attr_extra extra;
480 struct peer *peer;
481 struct peer *onlypeer;
482 afi_t afi;
483 safi_t safi;
484
485 peer = SUBGRP_PEER (subgrp);
486 afi = SUBGRP_AFI (subgrp);
487 safi = SUBGRP_SAFI (subgrp);
488
489 onlypeer = ((SUBGRP_PCOUNT (subgrp) == 1) ?
490 (SUBGRP_PFIRST (subgrp))->peer : NULL);
491 if (rsclient)
492 assert(onlypeer);
493
494 if (!table)
495 table = (rsclient) ? onlypeer->rib[afi][safi] : peer->bgp->rib[afi][safi];
496
497 if (safi != SAFI_MPLS_VPN
498 && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE))
499 subgroup_default_originate (subgrp, 0);
500
501 /* It's initialized in bgp_announce_[check|check_rsclient]() */
502 attr.extra = &extra;
503
504 for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
505 for (ri = rn->info; ri; ri = ri->next)
506
507 if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED))
508 {
509 if (!rsclient
510 && subgroup_announce_check (ri, subgrp, &rn->p, &attr))
511 bgp_adj_out_set_subgroup (rn, subgrp, &attr, ri);
512 else
513 bgp_adj_out_unset_subgroup (rn, subgrp);
514 }
515
516 /*
517 * We walked through the whole table -- make sure our version number
518 * is consistent with the one on the table. This should allow
519 * subgroups to merge sooner if a peer comes up when the route node
520 * with the largest version is no longer in the table. This also
521 * covers the pathological case where all routes in the table have
522 * now been deleted.
523 */
524 subgrp->version = max (subgrp->version, table->version);
525
526 /*
527 * Start a task to merge the subgroup if necessary.
528 */
529 update_subgroup_trigger_merge_check (subgrp, 0);
530}
531
532/*
533 * subgroup_announce_route
534 *
535 * Refresh all routes out to a subgroup.
536 */
537void
538subgroup_announce_route (struct update_subgroup *subgrp)
539{
540 struct bgp_node *rn;
541 struct bgp_table *table;
542 struct peer *onlypeer;
543 struct peer *peer;
544
545 if (update_subgroup_needs_refresh (subgrp))
546 {
547 update_subgroup_set_needs_refresh (subgrp, 0);
548 }
549
550 /*
551 * First update is deferred until ORF or ROUTE-REFRESH is received
552 */
553 onlypeer = ((SUBGRP_PCOUNT (subgrp) == 1) ?
554 (SUBGRP_PFIRST (subgrp))->peer : NULL);
555 if (onlypeer &&
556 CHECK_FLAG (onlypeer->
557 af_sflags[SUBGRP_AFI (subgrp)][SUBGRP_SAFI (subgrp)],
558 PEER_STATUS_ORF_WAIT_REFRESH))
559 return;
560
561 if (SUBGRP_SAFI (subgrp) != SAFI_MPLS_VPN)
562 subgroup_announce_table (subgrp, NULL, 0);
563 else
564 for (rn = bgp_table_top (update_subgroup_rib (subgrp)); rn;
565 rn = bgp_route_next (rn))
566 if ((table = (rn->info)) != NULL)
567 subgroup_announce_table (subgrp, table, 0);
568
569 peer = SUBGRP_PEER(subgrp);
570 if (CHECK_FLAG(peer->af_flags[SUBGRP_AFI(subgrp)][SUBGRP_SAFI(subgrp)],
571 PEER_FLAG_RSERVER_CLIENT))
572 subgroup_announce_table (subgrp, NULL, 1);
573}
574
575void
576subgroup_default_originate (struct update_subgroup *subgrp, int withdraw)
577{
578 struct bgp *bgp;
579 struct attr attr;
580 struct aspath *aspath;
581 struct prefix p;
582 struct peer *from;
583 struct bgp_node *rn;
584 struct bgp_info *ri;
585 struct peer *peer;
586 int ret = RMAP_DENYMATCH;
587 afi_t afi;
588 safi_t safi;
589
590 if (!subgrp)
591 return;
592
593 peer = SUBGRP_PEER (subgrp);
594 afi = SUBGRP_AFI (subgrp);
595 safi = SUBGRP_SAFI (subgrp);
596
597 if (!(afi == AFI_IP || afi == AFI_IP6))
598 return;
599
600 bgp = peer->bgp;
601 from = bgp->peer_self;
602
603 bgp_attr_default_set (&attr, BGP_ORIGIN_IGP);
604 aspath = attr.aspath;
605 attr.local_pref = bgp->default_local_pref;
606 memcpy (&attr.nexthop, &peer->nexthop.v4, IPV4_MAX_BYTELEN);
607
608 if (afi == AFI_IP)
609 str2prefix ("0.0.0.0/0", &p);
610#ifdef HAVE_IPV6
611 else if (afi == AFI_IP6)
612 {
613 struct attr_extra *ae = attr.extra;
614
615 str2prefix ("::/0", &p);
616
617 /* IPv6 global nexthop must be included. */
618 memcpy (&ae->mp_nexthop_global, &peer->nexthop.v6_global,
619 IPV6_MAX_BYTELEN);
620 ae->mp_nexthop_len = 16;
621
622 /* If the peer is on shared nextwork and we have link-local
623 nexthop set it. */
624 if (peer->shared_network
625 && !IN6_IS_ADDR_UNSPECIFIED (&peer->nexthop.v6_local))
626 {
627 memcpy (&ae->mp_nexthop_local, &peer->nexthop.v6_local,
628 IPV6_MAX_BYTELEN);
629 ae->mp_nexthop_len = 32;
630 }
631 }
632#endif /* HAVE_IPV6 */
633
634 if (peer->default_rmap[afi][safi].name)
635 {
636 SET_FLAG (bgp->peer_self->rmap_type, PEER_RMAP_TYPE_DEFAULT);
637 for (rn = bgp_table_top (bgp->rib[afi][safi]); rn;
638 rn = bgp_route_next (rn))
639 {
640 for (ri = rn->info; ri; ri = ri->next)
641 {
642 struct attr dummy_attr;
643 struct attr_extra dummy_extra;
644 struct bgp_info info;
645
646 /* Provide dummy so the route-map can't modify the attributes */
647 dummy_attr.extra = &dummy_extra;
648 bgp_attr_dup (&dummy_attr, ri->attr);
649 info.peer = ri->peer;
650 info.attr = &dummy_attr;
651
652 ret =
653 route_map_apply (peer->default_rmap[afi][safi].map, &rn->p,
654 RMAP_BGP, &info);
655
656 /* The route map might have set attributes. If we don't flush them
657 * here, they will be leaked. */
658 bgp_attr_flush (&dummy_attr);
659 if (ret != RMAP_DENYMATCH)
660 break;
661 }
662 if (ret != RMAP_DENYMATCH)
663 break;
664 }
665 bgp->peer_self->rmap_type = 0;
666
667 if (ret == RMAP_DENYMATCH)
668 withdraw = 1;
669 }
670
671 if (withdraw)
672 {
673 if (CHECK_FLAG (subgrp->sflags, SUBGRP_STATUS_DEFAULT_ORIGINATE))
674 subgroup_default_withdraw_packet (subgrp);
675 UNSET_FLAG (subgrp->sflags, SUBGRP_STATUS_DEFAULT_ORIGINATE);
676 }
677 else
678 {
679 if (!CHECK_FLAG (subgrp->sflags, SUBGRP_STATUS_DEFAULT_ORIGINATE))
680 {
681 SET_FLAG (subgrp->sflags, SUBGRP_STATUS_DEFAULT_ORIGINATE);
682 subgroup_default_update_packet (subgrp, &attr, from);
683 }
684 }
685
686 bgp_attr_extra_free (&attr);
687 aspath_unintern (&aspath);
688}
689
690/*
691 * Announce the BGP table to a subgroup.
692 *
693 * At startup, we try to optimize route announcement by coalescing the
694 * peer-up events. This is done only the first time - from then on,
695 * subgrp->v_coalesce will be set to zero and the normal logic
696 * prevails.
697 */
698void
699subgroup_announce_all (struct update_subgroup *subgrp)
700{
701 if (!subgrp)
702 return;
703
704 /*
705 * If coalesce timer value is not set, announce routes immediately.
706 */
707 if (!subgrp->v_coalesce)
708 {
709 if (bgp_debug_update(NULL, NULL, subgrp->update_group, 0))
710 zlog_debug ("u%llu:s%llu announcing all routes",
711 subgrp->update_group->id, subgrp->id);
712 subgroup_announce_route (subgrp);
713 return;
714 }
715
716 /*
717 * We should wait for the coalesce timer. Arm the timer if not done.
718 */
719 if (!subgrp->t_coalesce)
720 {
721 THREAD_TIMER_MSEC_ON (master, subgrp->t_coalesce, subgroup_coalesce_timer,
722 subgrp, subgrp->v_coalesce);
723 }
724}
725
726/*
727 * Go through all update subgroups and set up the adv queue for the
728 * input route.
729 */
730void
731group_announce_route (struct bgp *bgp, afi_t afi, safi_t safi,
732 struct bgp_node *rn, struct bgp_info *ri)
733{
734 struct updwalk_context ctx;
735 ctx.ri = ri;
736 ctx.rn = rn;
737 update_group_af_walk (bgp, afi, safi, group_announce_route_walkcb, &ctx);
738}
739
740void
741update_group_show_adj_queue (struct bgp *bgp, afi_t afi, safi_t safi,
742 struct vty *vty, u_int64_t id)
743{
744 updgrp_show_adj (bgp, afi, safi, vty, id, UPDWALK_FLAGS_ADVQUEUE);
745}
746
747void
748update_group_show_advertised (struct bgp *bgp, afi_t afi, safi_t safi,
749 struct vty *vty, u_int64_t id)
750{
751 updgrp_show_adj (bgp, afi, safi, vty, id, UPDWALK_FLAGS_ADVERTISED);
752}
753
754void
755update_group_announce (struct bgp *bgp)
756{
757 update_group_walk (bgp, update_group_announce_walkcb, NULL);
758}
759
760void
761update_group_announce_rrclients (struct bgp *bgp)
762{
763 update_group_walk (bgp, update_group_announce_rrc_walkcb, NULL);
764}