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