]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/bgp_updgrp.h
debian: add pkg-config to build-depends
[mirror_frr.git] / bgpd / bgp_updgrp.h
1 /**
2 * bgp_updgrp.c: BGP update group structures
3 *
4 * @copyright Copyright (C) 2014 Cumulus Networks, Inc.
5 *
6 * @author Avneesh Sachdev <avneesh@sproute.net>
7 * @author Rajesh Varadarajan <rajesh@sproute.net>
8 * @author Pradosh Mohapatra <pradosh@sproute.net>
9 *
10 * This file is part of GNU Zebra.
11 *
12 * GNU Zebra is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2, or (at your option) any
15 * later version.
16 *
17 * GNU Zebra is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with GNU Zebra; see the file COPYING. If not, write to the Free
24 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
25 * 02111-1307, USA.
26 */
27
28 #ifndef _QUAGGA_BGP_UPDGRP_H
29 #define _QUAGGA_BGP_UPDGRP_H
30
31 #include "bgp_advertise.h"
32
33 #define BGP_DEFAULT_SUBGROUP_COALESCE_TIME 200
34
35 #define PEER_UPDGRP_FLAGS \
36 (PEER_FLAG_LOCAL_AS_NO_PREPEND | PEER_FLAG_LOCAL_AS_REPLACE_AS)
37
38 #define PEER_UPDGRP_AF_FLAGS \
39 (PEER_FLAG_SEND_COMMUNITY | PEER_FLAG_SEND_EXT_COMMUNITY \
40 | PEER_FLAG_DEFAULT_ORIGINATE | PEER_FLAG_REFLECTOR_CLIENT \
41 | PEER_FLAG_RSERVER_CLIENT | PEER_FLAG_NEXTHOP_SELF \
42 | PEER_FLAG_NEXTHOP_UNCHANGED | PEER_FLAG_FORCE_NEXTHOP_SELF \
43 | PEER_FLAG_AS_PATH_UNCHANGED | PEER_FLAG_MED_UNCHANGED \
44 | PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED | PEER_FLAG_REMOVE_PRIVATE_AS \
45 | PEER_FLAG_REMOVE_PRIVATE_AS_ALL \
46 | PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE \
47 | PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE \
48 | PEER_FLAG_ADDPATH_TX_ALL_PATHS \
49 | PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS | PEER_FLAG_AS_OVERRIDE)
50
51 #define PEER_UPDGRP_CAP_FLAGS (PEER_CAP_AS4_RCV)
52
53 #define PEER_UPDGRP_AF_CAP_FLAGS \
54 (PEER_CAP_ORF_PREFIX_SM_RCV | PEER_CAP_ORF_PREFIX_SM_OLD_RCV \
55 | PEER_CAP_ADDPATH_AF_TX_ADV | PEER_CAP_ADDPATH_AF_RX_RCV \
56 | PEER_CAP_ENHE_AF_NEGO)
57
58 typedef enum { BGP_ATTR_VEC_NH = 0, BGP_ATTR_VEC_MAX } bpacket_attr_vec_type;
59
60 typedef struct {
61 u_int32_t flags;
62 unsigned long offset;
63 } bpacket_attr_vec;
64
65 #define BPKT_ATTRVEC_FLAGS_UPDATED (1 << 0)
66 #define BPKT_ATTRVEC_FLAGS_RMAP_NH_PEER_ADDRESS (1 << 1)
67 #define BPKT_ATTRVEC_FLAGS_REFLECTED (1 << 2)
68 #define BPKT_ATTRVEC_FLAGS_RMAP_NH_UNCHANGED (1 << 3)
69 #define BPKT_ATTRVEC_FLAGS_RMAP_IPV4_NH_CHANGED (1 << 4)
70 #define BPKT_ATTRVEC_FLAGS_RMAP_IPV6_GNH_CHANGED (1 << 5)
71 #define BPKT_ATTRVEC_FLAGS_RMAP_IPV6_LNH_CHANGED (1 << 6)
72
73 typedef struct bpacket_attr_vec_arr {
74 bpacket_attr_vec entries[BGP_ATTR_VEC_MAX];
75 } bpacket_attr_vec_arr;
76
77 struct bpacket {
78 /* for being part of an update subgroup's message list */
79 TAILQ_ENTRY(bpacket) pkt_train;
80
81 /* list of peers (well, peer_afs) that the packet needs to be sent to */
82 LIST_HEAD(pkt_peer_list, peer_af) peers;
83
84 struct stream *buffer;
85 bpacket_attr_vec_arr arr;
86
87 unsigned int ver;
88 };
89
90 struct bpacket_queue {
91 TAILQ_HEAD(pkt_queue, bpacket) pkts;
92
93 #if 0
94 /* A dummy packet that is used to thread all peers that have
95 completed their work */
96 struct bpacket sentinel;
97 #endif
98
99 unsigned int conf_max_count;
100 unsigned int curr_count;
101 unsigned int hwm_count;
102 unsigned int max_count_reached_count;
103 };
104
105 struct update_group {
106 /* back pointer to the BGP instance */
107 struct bgp *bgp;
108
109 /* list of subgroups that belong to the update group */
110 LIST_HEAD(subgrp_list, update_subgroup) subgrps;
111
112 /* lazy way to store configuration common to all peers
113 hash function will compute from this data */
114 struct peer *conf;
115
116 afi_t afi;
117 safi_t safi;
118 int afid;
119
120 uint64_t id;
121 time_t uptime;
122
123 u_int32_t join_events;
124 u_int32_t prune_events;
125 u_int32_t merge_events;
126 u_int32_t updgrp_switch_events;
127 u_int32_t peer_refreshes_combined;
128 u_int32_t adj_count;
129 u_int32_t split_events;
130 u_int32_t merge_checks_triggered;
131
132 u_int32_t subgrps_created;
133 u_int32_t subgrps_deleted;
134
135 u_int32_t num_dbg_en_peers;
136 };
137
138 /*
139 * Shorthand for a global statistics counter.
140 */
141 #define UPDGRP_GLOBAL_STAT(updgrp, stat) \
142 ((updgrp)->bgp->update_group_stats.stat)
143
144 /*
145 * Add the given value to a counter on an update group and the bgp
146 * instance.
147 */
148 #define UPDGRP_INCR_STAT_BY(updgrp, stat, value) \
149 do { \
150 (updgrp)->stat += (value); \
151 UPDGRP_GLOBAL_STAT(updgrp, stat) += (value); \
152 } while (0)
153
154 /*
155 * Increment a counter on a update group and its parent structures.
156 */
157 #define UPDGRP_INCR_STAT(subgrp, stat) UPDGRP_INCR_STAT_BY(subgrp, stat, 1)
158
159 struct update_subgroup {
160 /* back pointer to the parent update group */
161 struct update_group *update_group;
162
163 /* list of peers that belong to the subgroup */
164 LIST_HEAD(peer_list, peer_af) peers;
165 int peer_count;
166
167 /* for being part of an update group's subgroup list */
168 LIST_ENTRY(update_subgroup) updgrp_train;
169
170 struct bpacket_queue pkt_queue;
171
172 /*
173 * List of adj-out structures for this subgroup.
174 * It essentially represents the snapshot of every prefix that
175 * has been advertised to the members of the subgroup
176 */
177 TAILQ_HEAD(adjout_queue, bgp_adj_out) adjq;
178
179 /* packet buffer for update generation */
180 struct stream *work;
181
182 /* We use a separate stream to encode MP_REACH_NLRI for efficient
183 * NLRI packing. peer->work stores all the other attributes. The
184 * actual packet is then constructed by concatenating the two.
185 */
186 struct stream *scratch;
187
188 /* synchronization list and time */
189 struct bgp_synchronize *sync;
190
191 /* send prefix count */
192 unsigned long scount;
193
194 /* announcement attribute hash */
195 struct hash *hash;
196
197 struct thread *t_coalesce;
198 u_int32_t v_coalesce;
199
200 struct thread *t_merge_check;
201
202 /* table version that the subgroup has caught up to. */
203 uint64_t version;
204
205 /* version maintained to record adj changes */
206 uint64_t adj_version;
207
208 time_t uptime;
209
210 /*
211 * Identifying information about the subgroup that this subgroup was
212 * split
213 * from, if any.
214 */
215 struct {
216 uint64_t update_group_id;
217 uint64_t subgroup_id;
218 } split_from;
219
220 u_int32_t join_events;
221 u_int32_t prune_events;
222
223 /*
224 * This is bumped up when another subgroup merges into this one.
225 */
226 u_int32_t merge_events;
227 u_int32_t updgrp_switch_events;
228 u_int32_t peer_refreshes_combined;
229 u_int32_t adj_count;
230 u_int32_t split_events;
231 u_int32_t merge_checks_triggered;
232
233 uint64_t id;
234
235 u_int16_t sflags;
236
237 /* Subgroup flags, see below */
238 u_int16_t flags;
239 };
240
241 /*
242 * We need to do an outbound refresh to get this subgroup into a
243 * consistent state.
244 */
245 #define SUBGRP_FLAG_NEEDS_REFRESH (1 << 0)
246
247 #define SUBGRP_STATUS_DEFAULT_ORIGINATE (1 << 0)
248
249 /*
250 * Add the given value to the specified counter on a subgroup and its
251 * parent structures.
252 */
253 #define SUBGRP_INCR_STAT_BY(subgrp, stat, value) \
254 do { \
255 (subgrp)->stat += (value); \
256 if ((subgrp)->update_group) \
257 UPDGRP_INCR_STAT_BY((subgrp)->update_group, stat, \
258 value); \
259 } while (0)
260
261 /*
262 * Increment a counter on a subgroup and its parent structures.
263 */
264 #define SUBGRP_INCR_STAT(subgrp, stat) SUBGRP_INCR_STAT_BY(subgrp, stat, 1)
265
266 /*
267 * Decrement a counter on a subgroup and its parent structures.
268 */
269 #define SUBGRP_DECR_STAT(subgrp, stat) SUBGRP_INCR_STAT_BY(subgrp, stat, -1)
270
271
272 typedef int (*updgrp_walkcb)(struct update_group *updgrp, void *ctx);
273
274 /* really a private structure */
275 struct updwalk_context {
276 struct vty *vty;
277 struct bgp_node *rn;
278 struct bgp_info *ri;
279 uint64_t updgrp_id;
280 uint64_t subgrp_id;
281 bgp_policy_type_e policy_type;
282 const char *policy_name;
283 int policy_event_start_flag;
284 int policy_route_update;
285 updgrp_walkcb cb;
286 void *context;
287 u_int8_t flags;
288
289 #define UPDWALK_FLAGS_ADVQUEUE (1 << 0)
290 #define UPDWALK_FLAGS_ADVERTISED (1 << 1)
291 };
292
293 #define UPDWALK_CONTINUE HASHWALK_CONTINUE
294 #define UPDWALK_ABORT HASHWALK_ABORT
295
296 #define PAF_PEER(p) ((p)->peer)
297 #define PAF_SUBGRP(p) ((p)->subgroup)
298 #define PAF_UPDGRP(p) ((p)->subgroup->update_group)
299 #define PAF_PKTQ(f) SUBGRP_PKTQ((f)->subgroup)
300
301 #define UPDGRP_PEER(u) ((u)->conf)
302 #define UPDGRP_AFI(u) ((u)->afi)
303 #define UPDGRP_SAFI(u) ((u)->safi)
304 #define UPDGRP_INST(u) ((u)->bgp)
305 #define UPDGRP_AFFLAGS(u) ((u)->conf->af_flags[UPDGRP_AFI(u)][UPDGRP_SAFI(u)])
306 #define UPDGRP_DBG_ON(u) ((u)->num_dbg_en_peers)
307 #define UPDGRP_PEER_DBG_EN(u) (((u)->num_dbg_en_peers)++)
308 #define UPDGRP_PEER_DBG_DIS(u) (((u)->num_dbg_en_peers)--)
309 #define UPDGRP_PEER_DBG_OFF(u) (u)->num_dbg_en_peers = 0
310
311 #define SUBGRP_AFI(s) UPDGRP_AFI((s)->update_group)
312 #define SUBGRP_SAFI(s) UPDGRP_SAFI((s)->update_group)
313 #define SUBGRP_PEER(s) UPDGRP_PEER((s)->update_group)
314 #define SUBGRP_PCOUNT(s) ((s)->peer_count)
315 #define SUBGRP_PFIRST(s) LIST_FIRST(&((s)->peers))
316 #define SUBGRP_PKTQ(s) &((s)->pkt_queue)
317 #define SUBGRP_INST(s) UPDGRP_INST((s)->update_group)
318 #define SUBGRP_AFFLAGS(s) UPDGRP_AFFLAGS((s)->update_group)
319 #define SUBGRP_UPDGRP(s) ((s)->update_group)
320
321 /*
322 * Walk all subgroups in an update group.
323 */
324 #define UPDGRP_FOREACH_SUBGRP(updgrp, subgrp) \
325 LIST_FOREACH(subgrp, &((updgrp)->subgrps), updgrp_train)
326
327 #define UPDGRP_FOREACH_SUBGRP_SAFE(updgrp, subgrp, tmp_subgrp) \
328 LIST_FOREACH_SAFE(subgrp, &((updgrp)->subgrps), updgrp_train, \
329 tmp_subgrp)
330
331 #define SUBGRP_FOREACH_PEER(subgrp, paf) \
332 LIST_FOREACH(paf, &(subgrp->peers), subgrp_train)
333
334 #define SUBGRP_FOREACH_PEER_SAFE(subgrp, paf, temp_paf) \
335 LIST_FOREACH_SAFE(paf, &(subgrp->peers), subgrp_train, temp_paf)
336
337 #define SUBGRP_FOREACH_ADJ(subgrp, adj) \
338 TAILQ_FOREACH(adj, &(subgrp->adjq), subgrp_adj_train)
339
340 #define SUBGRP_FOREACH_ADJ_SAFE(subgrp, adj, adj_temp) \
341 TAILQ_FOREACH_SAFE(adj, &(subgrp->adjq), subgrp_adj_train, adj_temp)
342
343 /* Prototypes. */
344 /* bgp_updgrp.c */
345 extern void update_bgp_group_init(struct bgp *);
346 extern void udpate_bgp_group_free(struct bgp *);
347
348 extern void update_group_show(struct bgp *bgp, afi_t afi, safi_t safi,
349 struct vty *vty, uint64_t subgrp_id);
350 extern void update_group_show_stats(struct bgp *bgp, struct vty *vty);
351 extern void update_group_adjust_peer(struct peer_af *paf);
352 extern int update_group_adjust_soloness(struct peer *peer, int set);
353
354 extern void update_subgroup_remove_peer(struct update_subgroup *,
355 struct peer_af *);
356 extern struct bgp_table *update_subgroup_rib(struct update_subgroup *);
357 extern void update_subgroup_split_peer(struct peer_af *, struct update_group *);
358 extern int update_subgroup_check_merge(struct update_subgroup *, const char *);
359 extern int update_subgroup_trigger_merge_check(struct update_subgroup *,
360 int force);
361 extern void update_group_policy_update(struct bgp *bgp, bgp_policy_type_e ptype,
362 const char *pname, int route_update,
363 int start_event);
364 extern void update_group_af_walk(struct bgp *bgp, afi_t afi, safi_t safi,
365 updgrp_walkcb cb, void *ctx);
366 extern void update_group_walk(struct bgp *bgp, updgrp_walkcb cb, void *ctx);
367 extern void update_group_periodic_merge(struct bgp *bgp);
368 extern int
369 update_group_refresh_default_originate_route_map(struct thread *thread);
370 extern void update_group_start_advtimer(struct bgp *bgp);
371
372 extern void update_subgroup_inherit_info(struct update_subgroup *to,
373 struct update_subgroup *from);
374
375 /* bgp_updgrp_packet.c */
376 extern struct bpacket *bpacket_alloc(void);
377 extern void bpacket_free(struct bpacket *pkt);
378 extern void bpacket_queue_init(struct bpacket_queue *q);
379 extern void bpacket_queue_cleanup(struct bpacket_queue *q);
380 extern void bpacket_queue_sanity_check(struct bpacket_queue *q);
381 extern struct bpacket *bpacket_queue_add(struct bpacket_queue *q,
382 struct stream *s,
383 struct bpacket_attr_vec_arr *vecarr);
384 struct bpacket *bpacket_queue_remove(struct bpacket_queue *q);
385 extern struct bpacket *bpacket_queue_first(struct bpacket_queue *q);
386 struct bpacket *bpacket_queue_last(struct bpacket_queue *q);
387 unsigned int bpacket_queue_length(struct bpacket_queue *q);
388 unsigned int bpacket_queue_hwm_length(struct bpacket_queue *q);
389 int bpacket_queue_is_full(struct bgp *bgp, struct bpacket_queue *q);
390 extern void bpacket_queue_advance_peer(struct peer_af *paf);
391 extern void bpacket_queue_remove_peer(struct peer_af *paf);
392 extern void bpacket_add_peer(struct bpacket *pkt, struct peer_af *paf);
393 unsigned int bpacket_queue_virtual_length(struct peer_af *paf);
394 extern void bpacket_queue_show_vty(struct bpacket_queue *q, struct vty *vty);
395 int subgroup_packets_to_build(struct update_subgroup *subgrp);
396 extern struct bpacket *subgroup_update_packet(struct update_subgroup *s);
397 extern struct bpacket *subgroup_withdraw_packet(struct update_subgroup *s);
398 extern struct stream *bpacket_reformat_for_peer(struct bpacket *pkt,
399 struct peer_af *paf);
400 extern void bpacket_attr_vec_arr_reset(struct bpacket_attr_vec_arr *vecarr);
401 extern void bpacket_attr_vec_arr_set_vec(struct bpacket_attr_vec_arr *vecarr,
402 bpacket_attr_vec_type type,
403 struct stream *s, struct attr *attr);
404 extern void subgroup_default_update_packet(struct update_subgroup *subgrp,
405 struct attr *attr,
406 struct peer *from);
407 extern void subgroup_default_withdraw_packet(struct update_subgroup *subgrp);
408
409 /* bgp_updgrp_adv.c */
410 extern struct bgp_advertise *
411 bgp_advertise_clean_subgroup(struct update_subgroup *subgrp,
412 struct bgp_adj_out *adj);
413 extern void update_group_show_adj_queue(struct bgp *bgp, afi_t afi, safi_t safi,
414 struct vty *vty, uint64_t id);
415 extern void update_group_show_advertised(struct bgp *bgp, afi_t afi,
416 safi_t safi, struct vty *vty,
417 uint64_t id);
418 extern void update_group_show_packet_queue(struct bgp *bgp, afi_t afi,
419 safi_t safi, struct vty *vty,
420 uint64_t id);
421 extern void subgroup_announce_route(struct update_subgroup *subgrp);
422 extern void subgroup_announce_all(struct update_subgroup *subgrp);
423
424 extern void subgroup_default_originate(struct update_subgroup *subgrp,
425 int withdraw);
426 extern void group_announce_route(struct bgp *bgp, afi_t afi, safi_t safi,
427 struct bgp_node *rn, struct bgp_info *ri);
428 extern void subgroup_clear_table(struct update_subgroup *subgrp);
429 extern void update_group_announce(struct bgp *bgp);
430 extern void update_group_announce_rrclients(struct bgp *bgp);
431 extern void peer_af_announce_route(struct peer_af *paf, int combine);
432 extern struct bgp_adj_out *bgp_adj_out_alloc(struct update_subgroup *subgrp,
433 struct bgp_node *rn,
434 u_int32_t addpath_tx_id);
435 extern void bgp_adj_out_remove_subgroup(struct bgp_node *rn,
436 struct bgp_adj_out *adj,
437 struct update_subgroup *subgrp);
438 extern void bgp_adj_out_set_subgroup(struct bgp_node *rn,
439 struct update_subgroup *subgrp,
440 struct attr *attr, struct bgp_info *binfo);
441 extern void bgp_adj_out_unset_subgroup(struct bgp_node *rn,
442 struct update_subgroup *subgrp,
443 char withdraw, u_int32_t addpath_tx_id);
444 void subgroup_announce_table(struct update_subgroup *subgrp,
445 struct bgp_table *table);
446 extern void subgroup_trigger_write(struct update_subgroup *subgrp);
447
448 extern int update_group_clear_update_dbg(struct update_group *updgrp,
449 void *arg);
450
451 extern void update_bgp_group_free(struct bgp *bgp);
452 extern int bgp_addpath_encode_tx(struct peer *peer, afi_t afi, safi_t safi);
453 extern int bgp_addpath_tx_path(struct peer *peer, afi_t afi, safi_t safi,
454 struct bgp_info *ri);
455
456 /*
457 * Inline functions
458 */
459
460 /*
461 * bpacket_queue_is_empty
462 */
463 static inline int bpacket_queue_is_empty(struct bpacket_queue *queue)
464 {
465
466 /*
467 * The packet queue is empty if it only contains a sentinel.
468 */
469 if (queue->curr_count != 1)
470 return 0;
471
472 assert(bpacket_queue_first(queue)->buffer == NULL);
473 return 1;
474 }
475
476 /*
477 * bpacket_next
478 *
479 * Returns the packet after the given packet in a bpacket queue.
480 */
481 static inline struct bpacket *bpacket_next(struct bpacket *pkt)
482 {
483 return TAILQ_NEXT(pkt, pkt_train);
484 }
485
486 /*
487 * update_group_adjust_peer_afs
488 *
489 * Adjust all peer_af structures for the given peer.
490 */
491 static inline void update_group_adjust_peer_afs(struct peer *peer)
492 {
493 struct peer_af *paf;
494 int afidx;
495
496 for (afidx = BGP_AF_START; afidx < BGP_AF_MAX; afidx++) {
497 paf = peer->peer_af_array[afidx];
498 if (paf != NULL)
499 update_group_adjust_peer(paf);
500 }
501 }
502
503 /*
504 * update_group_remove_peer_afs
505 *
506 * Remove all peer_af structures for the given peer from their subgroups.
507 */
508 static inline void update_group_remove_peer_afs(struct peer *peer)
509 {
510 struct peer_af *paf;
511 int afidx;
512
513 for (afidx = BGP_AF_START; afidx < BGP_AF_MAX; afidx++) {
514 paf = peer->peer_af_array[afidx];
515 if (paf != NULL)
516 update_subgroup_remove_peer(PAF_SUBGRP(paf), paf);
517 }
518 }
519
520 /*
521 * update_subgroup_needs_refresh
522 */
523 static inline int
524 update_subgroup_needs_refresh(const struct update_subgroup *subgrp)
525 {
526 if (CHECK_FLAG(subgrp->flags, SUBGRP_FLAG_NEEDS_REFRESH))
527 return 1;
528 else
529 return 0;
530 }
531
532 /*
533 * update_subgroup_set_needs_refresh
534 */
535 static inline void
536 update_subgroup_set_needs_refresh(struct update_subgroup *subgrp, int value)
537 {
538 if (value)
539 SET_FLAG(subgrp->flags, SUBGRP_FLAG_NEEDS_REFRESH);
540 else
541 UNSET_FLAG(subgrp->flags, SUBGRP_FLAG_NEEDS_REFRESH);
542 }
543
544 static inline struct update_subgroup *peer_subgroup(struct peer *peer,
545 afi_t afi, safi_t safi)
546 {
547 struct peer_af *paf;
548
549 paf = peer_af_find(peer, afi, safi);
550 if (paf)
551 return PAF_SUBGRP(paf);
552 return NULL;
553 }
554
555 /*
556 * update_group_adjust_peer_afs
557 *
558 * Adjust all peer_af structures for the given peer.
559 */
560 static inline void bgp_announce_peer(struct peer *peer)
561 {
562 struct peer_af *paf;
563 int afidx;
564
565 for (afidx = BGP_AF_START; afidx < BGP_AF_MAX; afidx++) {
566 paf = peer->peer_af_array[afidx];
567 if (paf != NULL)
568 subgroup_announce_all(PAF_SUBGRP(paf));
569 }
570 }
571
572 /**
573 * advertise_list_is_empty
574 */
575 static inline int advertise_list_is_empty(struct update_subgroup *subgrp)
576 {
577 if (!BGP_ADV_FIFO_EMPTY(&subgrp->sync->update)
578 || !BGP_ADV_FIFO_EMPTY(&subgrp->sync->withdraw)
579 || !BGP_ADV_FIFO_EMPTY(&subgrp->sync->withdraw_low)) {
580 return 0;
581 }
582
583 return 1;
584 }
585
586 #endif /* _QUAGGA_BGP_UPDGRP_H */